| use rustc_index::IndexSlice; | |
| use rustc_middle::mir::visit::{PlaceContext, VisitPlacesWith, Visitor}; | |
| use rustc_middle::mir::{Body, Local, Place}; | |
| use rustc_middle::ty::{self, RegionVid, TyCtxt}; | |
| use rustc_span::{Span, Symbol}; | |
| use tracing::debug; | |
| use crate::region_infer::RegionInferenceContext; | |
| impl<'tcx> RegionInferenceContext<'tcx> { | |
| /// Find the name and span of the variable corresponding to the given region. | |
| /// The returned var will also be ensured to actually be used in `body`. | |
| pub(crate) fn get_var_name_and_span_for_region( | |
| &self, | |
| tcx: TyCtxt<'tcx>, | |
| body: &Body<'tcx>, | |
| local_names: &IndexSlice<Local, Option<Symbol>>, | |
| upvars: &[&ty::CapturedPlace<'tcx>], | |
| fr: RegionVid, | |
| ) -> Option<(Option<Symbol>, Span)> { | |
| debug!("get_var_name_and_span_for_region(fr={fr:?})"); | |
| assert!(self.universal_regions().is_universal_region(fr)); | |
| debug!("get_var_name_and_span_for_region: attempting upvar"); | |
| self.get_upvar_index_for_region(tcx, fr) | |
| .map(|index| { | |
| // FIXME(project-rfc-2229#8): Use place span for diagnostics | |
| // We know our upvars are used thanks to `fn compute_min_captures()` in `upvar.rs`. | |
| let (name, span) = self.get_upvar_name_and_span_for_region(tcx, upvars, index); | |
| (Some(name), span) | |
| }) | |
| .or_else(|| { | |
| debug!("get_var_name_and_span_for_region: attempting argument"); | |
| self.get_user_arg_index_for_region(tcx, fr).and_then(|index| { | |
| let local = self.user_arg_index_to_local(body, index); | |
| if body_uses_local(body, local) { | |
| Some(self.get_argument_name_and_span_for_region(body, local_names, index)) | |
| } else { | |
| debug!("get_var_name_and_span_for_region: skipping unused local {local:?}"); | |
| None | |
| } | |
| }) | |
| }) | |
| } | |
| /// Search the upvars (if any) to find one that references fr. Return its index. | |
| pub(crate) fn get_upvar_index_for_region( | |
| &self, | |
| tcx: TyCtxt<'tcx>, | |
| fr: RegionVid, | |
| ) -> Option<usize> { | |
| let upvar_index = | |
| self.universal_regions().defining_ty.upvar_tys().iter().position(|upvar_ty| { | |
| debug!("get_upvar_index_for_region: upvar_ty={upvar_ty:?}"); | |
| tcx.any_free_region_meets(&upvar_ty, |r| { | |
| let r = r.as_var(); | |
| debug!("get_upvar_index_for_region: r={r:?} fr={fr:?}"); | |
| r == fr | |
| }) | |
| })?; | |
| let upvar_ty = self.universal_regions().defining_ty.upvar_tys().get(upvar_index); | |
| debug!( | |
| "get_upvar_index_for_region: found {fr:?} in upvar {upvar_index} which has type {upvar_ty:?}", | |
| ); | |
| Some(upvar_index) | |
| } | |
| /// Given the index of an upvar, finds its name and the span from where it was | |
| /// declared. | |
| pub(crate) fn get_upvar_name_and_span_for_region( | |
| &self, | |
| tcx: TyCtxt<'tcx>, | |
| upvars: &[&ty::CapturedPlace<'tcx>], | |
| upvar_index: usize, | |
| ) -> (Symbol, Span) { | |
| let upvar_hir_id = upvars[upvar_index].get_root_variable(); | |
| debug!("get_upvar_name_and_span_for_region: upvar_hir_id={upvar_hir_id:?}"); | |
| let upvar_name = tcx.hir_name(upvar_hir_id); | |
| let upvar_span = tcx.hir_span(upvar_hir_id); | |
| debug!( | |
| "get_upvar_name_and_span_for_region: upvar_name={upvar_name:?} upvar_span={upvar_span:?}", | |
| ); | |
| (upvar_name, upvar_span) | |
| } | |
| /// Search the argument types for one that references fr (which should be a free region). | |
| /// Returns Some(_) with the index of the input if one is found. | |
| /// | |
| /// N.B., in the case of a closure, the index is indexing into the signature as seen by the | |
| /// user - in particular, index 0 is not the implicit self parameter. | |
| pub(crate) fn get_user_arg_index_for_region( | |
| &self, | |
| tcx: TyCtxt<'tcx>, | |
| fr: RegionVid, | |
| ) -> Option<usize> { | |
| let implicit_inputs = self.universal_regions().defining_ty.implicit_inputs(); | |
| let user_arg_index = | |
| self.universal_regions().unnormalized_input_tys.iter().skip(implicit_inputs).position( | |
| |arg_ty| { | |
| debug!("get_user_arg_index_for_region: arg_ty = {arg_ty:?}"); | |
| tcx.any_free_region_meets(arg_ty, |r| r.as_var() == fr) | |
| }, | |
| )?; | |
| debug!( | |
| "get_user_arg_index_for_region: found {fr:?} in argument {user_arg_index} which has type {:?}", | |
| self.universal_regions().unnormalized_input_tys[user_arg_index], | |
| ); | |
| Some(user_arg_index) | |
| } | |
| /// Given the index of an argument as seen from the user (i.e. excluding | |
| /// implicit inputs), returns the corresponding MIR local. | |
| fn user_arg_index_to_local(&self, body: &Body<'tcx>, user_arg_index: usize) -> Local { | |
| let implicit_inputs = self.universal_regions().defining_ty.implicit_inputs(); | |
| body.args_iter().nth(implicit_inputs + user_arg_index).unwrap() | |
| } | |
| /// Given the index of an argument, finds its name (if any) and the span from where it was | |
| /// declared. | |
| pub(crate) fn get_argument_name_and_span_for_region( | |
| &self, | |
| body: &Body<'tcx>, | |
| local_names: &IndexSlice<Local, Option<Symbol>>, | |
| user_arg_index: usize, | |
| ) -> (Option<Symbol>, Span) { | |
| let argument_local = self.user_arg_index_to_local(body, user_arg_index); | |
| debug!("get_argument_name_and_span_for_region: argument_local={argument_local:?}"); | |
| let argument_name = local_names[argument_local]; | |
| let argument_span = body.local_decls[argument_local].source_info.span; | |
| debug!( | |
| "get_argument_name_and_span_for_region: argument_name={argument_name:?} argument_span={argument_span:?}", | |
| ); | |
| (argument_name, argument_span) | |
| } | |
| } | |
| fn body_uses_local<'tcx>(body: &Body<'tcx>, target: Local) -> bool { | |
| let mut used = false; | |
| VisitPlacesWith(|place: Place<'_>, context: PlaceContext| { | |
| if !matches!(context, PlaceContext::NonUse(_)) && place.local == target { | |
| used = true; | |
| } | |
| }) | |
| .visit_body(body); | |
| used | |
| } |