diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index 1f0b8adeaf16c..f370c02161b11 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -17,7 +17,7 @@ pub(crate) mod graph; /// constraints of the form `R1: R2`. Each constraint is identified by /// a unique `OutlivesConstraintIndex` and you can index into the set /// (`constraint_set[i]`) to access the constraint details. -#[derive(Clone, Default)] +#[derive(Clone, Debug, Default)] pub(crate) struct OutlivesConstraintSet<'tcx> { outlives: IndexVec>, } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 98103af779d8b..622b57c7b7f2b 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -25,7 +25,9 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::ChunkedBitSet; use rustc_index::vec::IndexVec; -use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt}; +use rustc_infer::infer::{ + DefiningAnchor, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, +}; use rustc_middle::mir::{ traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, VarDebugInfoContents, @@ -43,6 +45,7 @@ use smallvec::SmallVec; use std::cell::OnceCell; use std::cell::RefCell; use std::collections::BTreeMap; +use std::ops::Deref; use std::rc::Rc; use rustc_mir_dataflow::impls::{ @@ -94,6 +97,7 @@ use nll::{PoloniusOutput, ToRegionVid}; use place_ext::PlaceExt; use places_conflict::{places_conflict, PlaceConflictBias}; use region_infer::RegionInferenceContext; +use renumber::RegionCtxt; // FIXME(eddyb) perhaps move this somewhere more centrally. #[derive(Debug)] @@ -167,10 +171,10 @@ fn do_mir_borrowck<'tcx>( return_body_with_facts: bool, ) -> (BorrowCheckResult<'tcx>, Option>>) { let def = input_body.source.with_opt_param().as_local().unwrap(); - debug!(?def); let tcx = infcx.tcx; + let infcx = BorrowckInferCtxt::new(infcx); let param_env = tcx.param_env(def.did); let mut local_names = IndexVec::from_elem(None, &input_body.local_decls); @@ -218,7 +222,7 @@ fn do_mir_borrowck<'tcx>( let mut body_owned = input_body.clone(); let mut promoted = input_promoted.clone(); let free_regions = - nll::replace_regions_in_mir(infcx, param_env, &mut body_owned, &mut promoted); + nll::replace_regions_in_mir(&infcx, param_env, &mut body_owned, &mut promoted); let body = &body_owned; // no further changes let location_table_owned = LocationTable::new(body); @@ -256,7 +260,7 @@ fn do_mir_borrowck<'tcx>( opt_closure_req, nll_errors, } = nll::compute_regions( - infcx, + &infcx, free_regions, body, &promoted, @@ -271,12 +275,12 @@ fn do_mir_borrowck<'tcx>( // Dump MIR results into a file, if that is enabled. This let us // write unit-tests, as well as helping with debugging. - nll::dump_mir_results(infcx, &body, ®ioncx, &opt_closure_req); + nll::dump_mir_results(&infcx, &body, ®ioncx, &opt_closure_req); // We also have a `#[rustc_regions]` annotation that causes us to dump // information. nll::dump_annotation( - infcx, + &infcx, &body, ®ioncx, &opt_closure_req, @@ -320,7 +324,7 @@ fn do_mir_borrowck<'tcx>( if let Err((move_data, move_errors)) = move_data_results { let mut promoted_mbcx = MirBorrowckCtxt { - infcx, + infcx: &infcx, param_env, body: promoted_body, move_data: &move_data, @@ -349,7 +353,7 @@ fn do_mir_borrowck<'tcx>( } let mut mbcx = MirBorrowckCtxt { - infcx, + infcx: &infcx, param_env, body, move_data: &mdpe.move_data, @@ -481,8 +485,84 @@ pub struct BodyWithBorrowckFacts<'tcx> { pub location_table: LocationTable, } +pub struct BorrowckInferCtxt<'cx, 'tcx> { + pub(crate) infcx: &'cx InferCtxt<'tcx>, + pub(crate) reg_var_to_origin: RefCell>, +} + +impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { + pub(crate) fn new(infcx: &'cx InferCtxt<'tcx>) -> Self { + BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) } + } + + pub(crate) fn next_region_var( + &self, + origin: RegionVariableOrigin, + get_ctxt_fn: F, + ) -> ty::Region<'tcx> + where + F: Fn() -> RegionCtxt, + { + let next_region = self.infcx.next_region_var(origin); + let vid = next_region + .as_var() + .unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region)); + + if cfg!(debug_assertions) { + debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin); + let ctxt = get_ctxt_fn(); + let mut var_to_origin = self.reg_var_to_origin.borrow_mut(); + let prev = var_to_origin.insert(vid, ctxt); + + // This only makes sense if not called in a canonicalization context. If this + // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin` + // or modify how we track nll region vars for that map. + assert!(matches!(prev, None)); + } + + next_region + } + + #[instrument(skip(self, get_ctxt_fn), level = "debug")] + pub(crate) fn next_nll_region_var( + &self, + origin: NllRegionVariableOrigin, + get_ctxt_fn: F, + ) -> ty::Region<'tcx> + where + F: Fn() -> RegionCtxt, + { + let next_region = self.infcx.next_nll_region_var(origin.clone()); + let vid = next_region + .as_var() + .unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region)); + + if cfg!(debug_assertions) { + debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin); + let ctxt = get_ctxt_fn(); + let mut var_to_origin = self.reg_var_to_origin.borrow_mut(); + let prev = var_to_origin.insert(vid, ctxt); + + // This only makes sense if not called in a canonicalization context. If this + // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin` + // or modify how we track nll region vars for that map. + assert!(matches!(prev, None)); + } + + next_region + } +} + +impl<'cx, 'tcx> Deref for BorrowckInferCtxt<'cx, 'tcx> { + type Target = InferCtxt<'tcx>; + + fn deref(&self) -> &'cx Self::Target { + self.infcx + } +} + struct MirBorrowckCtxt<'cx, 'tcx> { - infcx: &'cx InferCtxt<'tcx>, + infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, param_env: ParamEnv<'tcx>, body: &'cx Body<'tcx>, move_data: &'cx MoveData<'tcx>, diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index c71413e8e7c04..e5dbb83dd0728 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -5,7 +5,6 @@ use rustc_data_structures::vec_map::VecMap; use rustc_hir::def_id::LocalDefId; use rustc_index::vec::IndexVec; -use rustc_infer::infer::InferCtxt; use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere}; use rustc_middle::mir::{ BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, @@ -37,7 +36,7 @@ use crate::{ renumber, type_check::{self, MirTypeckRegionConstraints, MirTypeckResults}, universal_regions::UniversalRegions, - Upvar, + BorrowckInferCtxt, Upvar, }; pub type PoloniusOutput = Output; @@ -58,7 +57,7 @@ pub(crate) struct NllOutput<'tcx> { /// `compute_regions`. #[instrument(skip(infcx, param_env, body, promoted), level = "debug")] pub(crate) fn replace_regions_in_mir<'tcx>( - infcx: &InferCtxt<'tcx>, + infcx: &BorrowckInferCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexVec>, @@ -157,7 +156,7 @@ fn populate_polonius_move_facts( /// /// This may result in errors being reported. pub(crate) fn compute_regions<'cx, 'tcx>( - infcx: &InferCtxt<'tcx>, + infcx: &BorrowckInferCtxt<'_, 'tcx>, universal_regions: UniversalRegions<'tcx>, body: &Body<'tcx>, promoted: &IndexVec>, @@ -259,6 +258,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>( ); let mut regioncx = RegionInferenceContext::new( + infcx, var_origins, universal_regions, placeholder_indices, @@ -322,7 +322,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>( } pub(super) fn dump_mir_results<'tcx>( - infcx: &InferCtxt<'tcx>, + infcx: &BorrowckInferCtxt<'_, 'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, @@ -372,7 +372,7 @@ pub(super) fn dump_mir_results<'tcx>( #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] pub(super) fn dump_annotation<'tcx>( - infcx: &InferCtxt<'tcx>, + infcx: &BorrowckInferCtxt<'_, 'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 83fdb6066c6b4..8c374c2164c7b 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -34,6 +34,7 @@ use crate::{ }, type_check::{free_region_relations::UniversalRegionRelations, Locations}, universal_regions::UniversalRegions, + BorrowckInferCtxt, }; mod dump_mir; @@ -243,6 +244,70 @@ pub enum ExtraConstraintInfo { PlaceholderFromPredicate(Span), } +#[instrument(skip(infcx, sccs), level = "debug")] +fn sccs_info<'cx, 'tcx>( + infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, + sccs: Rc>, +) { + use crate::renumber::RegionCtxt; + + let var_to_origin = infcx.reg_var_to_origin.borrow(); + + let mut var_to_origin_sorted = var_to_origin.clone().into_iter().collect::>(); + var_to_origin_sorted.sort_by(|a, b| a.0.cmp(&b.0)); + let mut debug_str = "region variables to origins:\n".to_string(); + for (reg_var, origin) in var_to_origin_sorted.into_iter() { + debug_str.push_str(&format!("{:?}: {:?}\n", reg_var, origin)); + } + debug!(debug_str); + + let num_components = sccs.scc_data().ranges().len(); + let mut components = vec![FxHashSet::default(); num_components]; + + for (reg_var_idx, scc_idx) in sccs.scc_indices().iter().enumerate() { + let reg_var = ty::RegionVid::from_usize(reg_var_idx); + let origin = var_to_origin.get(®_var).unwrap_or_else(|| &RegionCtxt::Unknown); + components[scc_idx.as_usize()].insert((reg_var, *origin)); + } + + let mut components_str = "strongly connected components:".to_string(); + for (scc_idx, reg_vars_origins) in components.iter().enumerate() { + let regions_info = reg_vars_origins.clone().into_iter().collect::>(); + components_str.push_str(&format!( + "{:?}: {:?})", + ConstraintSccIndex::from_usize(scc_idx), + regions_info, + )) + } + debug!(components_str); + + // calculate the best representative for each component + let components_representatives = components + .into_iter() + .enumerate() + .map(|(scc_idx, region_ctxts)| { + let repr = region_ctxts + .into_iter() + .map(|reg_var_origin| reg_var_origin.1) + .max_by(|x, y| x.preference_value().cmp(&y.preference_value())) + .unwrap(); + + (ConstraintSccIndex::from_usize(scc_idx), repr) + }) + .collect::>(); + + let mut scc_node_to_edges = FxHashMap::default(); + for (scc_idx, repr) in components_representatives.iter() { + let edges_range = sccs.scc_data().ranges()[*scc_idx].clone(); + let edges = &sccs.scc_data().all_successors()[edges_range]; + let edge_representatives = + edges.iter().map(|scc_idx| components_representatives[scc_idx]).collect::>(); + scc_node_to_edges.insert((scc_idx, repr), edge_representatives); + } + + debug!("SCC edges {:#?}", scc_node_to_edges); +} + impl<'tcx> RegionInferenceContext<'tcx> { /// Creates a new region inference context with a total of /// `num_region_variables` valid inference variables; the first N @@ -251,7 +316,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// The `outlives_constraints` and `type_tests` are an initial set /// of constraints produced by the MIR type check. - pub(crate) fn new( + pub(crate) fn new<'cx>( + _infcx: &BorrowckInferCtxt<'cx, 'tcx>, var_infos: VarInfos, universal_regions: Rc>, placeholder_indices: Rc, @@ -263,6 +329,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { liveness_constraints: LivenessValues, elements: &Rc, ) -> Self { + debug!("universal_regions: {:#?}", universal_regions); + debug!("outlives constraints: {:#?}", outlives_constraints); + debug!("placeholder_indices: {:#?}", placeholder_indices); + debug!("type tests: {:#?}", type_tests); + // Create a RegionDefinition for each inference variable. let definitions: IndexVec<_, _> = var_infos .iter() @@ -274,6 +345,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { let fr_static = universal_regions.fr_static; let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph, fr_static)); + if cfg!(debug_assertions) { + sccs_info(_infcx, constraint_sccs.clone()); + } + let mut scc_values = RegionValues::new(elements, universal_regions.len(), &placeholder_indices); diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 6a3748fded554..c361357ca2134 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -181,7 +181,7 @@ impl LivenessValues { /// Maps from `ty::PlaceholderRegion` values that are used in the rest of /// rustc to the internal `PlaceholderIndex` values that are used in /// NLL. -#[derive(Default)] +#[derive(Debug, Default)] pub(crate) struct PlaceholderIndices { indices: FxIndexSet, } diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 084754830bdbf..960dedc74efbb 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -1,18 +1,20 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +use crate::BorrowckInferCtxt; use rustc_index::vec::IndexVec; -use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; +use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::visit::{MutVisitor, TyContext}; use rustc_middle::mir::Constant; use rustc_middle::mir::{Body, Location, Promoted}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_span::{Span, Symbol}; /// Replaces all free regions appearing in the MIR with fresh /// inference variables, returning the number of variables created. #[instrument(skip(infcx, body, promoted), level = "debug")] pub fn renumber_mir<'tcx>( - infcx: &InferCtxt<'tcx>, + infcx: &BorrowckInferCtxt<'_, 'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexVec>, ) { @@ -29,27 +31,68 @@ pub fn renumber_mir<'tcx>( /// Replaces all regions appearing in `value` with fresh inference /// variables. -#[instrument(skip(infcx), level = "debug")] -pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> T +#[instrument(skip(infcx, get_ctxt_fn), level = "debug")] +pub(crate) fn renumber_regions<'tcx, T, F>( + infcx: &BorrowckInferCtxt<'_, 'tcx>, + value: T, + get_ctxt_fn: F, +) -> T where T: TypeFoldable<'tcx>, + F: Fn() -> RegionCtxt, { infcx.tcx.fold_regions(value, |_region, _depth| { let origin = NllRegionVariableOrigin::Existential { from_forall: false }; - infcx.next_nll_region_var(origin) + infcx.next_nll_region_var(origin, || get_ctxt_fn()) }) } +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub(crate) enum BoundRegionInfo { + Name(Symbol), + Span(Span), +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub(crate) enum RegionCtxt { + Location(Location), + TyContext(TyContext), + Free(Symbol), + Bound(BoundRegionInfo), + LateBound(BoundRegionInfo), + Existential(Option), + Placeholder(BoundRegionInfo), + Unknown, +} + +impl RegionCtxt { + /// Used to determine the representative of a component in the strongly connected + /// constraint graph + pub(crate) fn preference_value(self) -> usize { + let _anon = Symbol::intern("anon"); + + match self { + RegionCtxt::Unknown => 1, + RegionCtxt::Existential(None) => 2, + RegionCtxt::Existential(Some(_anon)) | RegionCtxt::Free(_anon) => 2, + RegionCtxt::Location(_) => 3, + RegionCtxt::TyContext(_) => 4, + _ => 5, + } + } +} + struct NllVisitor<'a, 'tcx> { - infcx: &'a InferCtxt<'tcx>, + infcx: &'a BorrowckInferCtxt<'a, 'tcx>, } impl<'a, 'tcx> NllVisitor<'a, 'tcx> { - fn renumber_regions(&mut self, value: T) -> T + fn renumber_regions(&mut self, value: T, region_ctxt_fn: F) -> T where T: TypeFoldable<'tcx>, + F: Fn() -> RegionCtxt, { - renumber_regions(self.infcx, value) + renumber_regions(self.infcx, value, region_ctxt_fn) } } @@ -60,14 +103,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { #[instrument(skip(self), level = "debug")] fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) { - *ty = self.renumber_regions(*ty); + *ty = self.renumber_regions(*ty, || RegionCtxt::TyContext(ty_context)); debug!(?ty); } #[instrument(skip(self), level = "debug")] fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) { - *substs = self.renumber_regions(*substs); + *substs = self.renumber_regions(*substs, || RegionCtxt::Location(location)); debug!(?substs); } @@ -75,7 +118,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { #[instrument(skip(self), level = "debug")] fn visit_region(&mut self, region: &mut ty::Region<'tcx>, location: Location) { let old_region = *region; - *region = self.renumber_regions(old_region); + *region = self.renumber_regions(old_region, || RegionCtxt::Location(location)); debug!(?region); } @@ -83,7 +126,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { #[instrument(skip(self), level = "debug")] fn visit_constant(&mut self, constant: &mut Constant<'tcx>, _location: Location) { let literal = constant.literal; - constant.literal = self.renumber_regions(literal); + constant.literal = self.renumber_regions(literal, || RegionCtxt::Location(_location)); debug!("constant: {:#?}", constant); } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 5e1334559f5f3..f14f8f1906be7 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -64,7 +64,7 @@ use crate::{ region_infer::TypeTest, type_check::free_region_relations::{CreateResult, UniversalRegionRelations}, universal_regions::{DefiningTy, UniversalRegions}, - Upvar, + BorrowckInferCtxt, Upvar, }; macro_rules! span_mirbug { @@ -123,7 +123,7 @@ mod relate_tys; /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis /// - `elements` -- MIR region map pub(crate) fn type_check<'mir, 'tcx>( - infcx: &InferCtxt<'tcx>, + infcx: &BorrowckInferCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, promoted: &IndexVec>, @@ -866,7 +866,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { /// way, it accrues region constraints -- these can later be used by /// NLL region checking. struct TypeChecker<'a, 'tcx> { - infcx: &'a InferCtxt<'tcx>, + infcx: &'a BorrowckInferCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, last_span: Span, body: &'a Body<'tcx>, @@ -1019,7 +1019,7 @@ impl Locations { impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn new( - infcx: &'a InferCtxt<'tcx>, + infcx: &'a BorrowckInferCtxt<'a, 'tcx>, body: &'a Body<'tcx>, param_env: ty::ParamEnv<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, @@ -1356,11 +1356,34 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } }; let (sig, map) = tcx.replace_late_bound_regions(sig, |br| { - self.infcx.next_region_var(LateBoundRegion( - term.source_info.span, - br.kind, - LateBoundRegionConversionTime::FnCall, - )) + use crate::renumber::{BoundRegionInfo, RegionCtxt}; + use rustc_span::Symbol; + + let region_ctxt_fn = || { + let reg_info = match br.kind { + ty::BoundRegionKind::BrAnon(_, Some(span)) => { + BoundRegionInfo::Span(span) + } + ty::BoundRegionKind::BrAnon(..) => { + BoundRegionInfo::Name(Symbol::intern("anon")) + } + ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name), + ty::BoundRegionKind::BrEnv => { + BoundRegionInfo::Name(Symbol::intern("env")) + } + }; + + RegionCtxt::LateBound(reg_info) + }; + + self.infcx.next_region_var( + LateBoundRegion( + term.source_info.span, + br.kind, + LateBoundRegionConversionTime::FnCall, + ), + region_ctxt_fn, + ) }); debug!(?sig); // IMPORTANT: We have to prove well formed for the function signature before diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 8dd06187877c8..d96372fb99baa 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -4,11 +4,12 @@ use rustc_infer::traits::PredicateObligations; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::{self, Ty}; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use rustc_trait_selection::traits::query::Fallible; use crate::constraints::OutlivesConstraint; use crate::diagnostics::UniverseInfo; +use crate::renumber::{BoundRegionInfo, RegionCtxt}; use crate::type_check::{InstantiateOpaqueType, Locations, TypeChecker}; impl<'a, 'tcx> TypeChecker<'a, 'tcx> { @@ -100,23 +101,65 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> universe } - fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> { + #[instrument(skip(self), level = "debug")] + fn next_existential_region_var( + &mut self, + from_forall: bool, + _name: Option, + ) -> ty::Region<'tcx> { let origin = NllRegionVariableOrigin::Existential { from_forall }; - self.type_checker.infcx.next_nll_region_var(origin) + + let reg_var = + self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(_name)); + + reg_var } + #[instrument(skip(self), level = "debug")] fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> { - self.type_checker + let reg = self + .type_checker .borrowck_context .constraints - .placeholder_region(self.type_checker.infcx, placeholder) + .placeholder_region(self.type_checker.infcx, placeholder); + + let reg_info = match placeholder.name { + ty::BoundRegionKind::BrAnon(_, Some(span)) => BoundRegionInfo::Span(span), + ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(Symbol::intern("anon")), + ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name), + ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(Symbol::intern("env")), + }; + + let reg_var = + reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg)); + let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut(); + let prev = var_to_origin.insert(reg_var, RegionCtxt::Placeholder(reg_info)); + assert!(matches!(prev, None)); + + reg } + #[instrument(skip(self), level = "debug")] fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { - self.type_checker.infcx.next_nll_region_var_in_universe( + let reg = self.type_checker.infcx.next_nll_region_var_in_universe( NllRegionVariableOrigin::Existential { from_forall: false }, universe, - ) + ); + + let reg_var = + reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg)); + + if cfg!(debug_assertions) { + let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut(); + let prev = var_to_origin.insert(reg_var, RegionCtxt::Existential(None)); + + // It only makes sense to track region vars in non-canonicalization contexts. If this + // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin` + // or modify how we track nll region vars for that map. + assert!(matches!(prev, None)); + } + + reg } fn push_outlives( diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index efa5a29c5ddf1..f3ca896cd0de1 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -20,15 +20,18 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::{BodyOwnerKind, HirId}; use rustc_index::vec::{Idx, IndexVec}; -use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; +use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{ self, DefIdTree, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt, }; use rustc_middle::ty::{InternalSubsts, SubstsRef}; +use rustc_span::Symbol; use std::iter; use crate::nll::ToRegionVid; +use crate::renumber::{BoundRegionInfo, RegionCtxt}; +use crate::BorrowckInferCtxt; #[derive(Debug)] pub struct UniversalRegions<'tcx> { @@ -224,7 +227,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// signature. This will also compute the relationships that are /// known between those regions. pub fn new( - infcx: &InferCtxt<'tcx>, + infcx: &BorrowckInferCtxt<'_, 'tcx>, mir_def: ty::WithOptConstParam, param_env: ty::ParamEnv<'tcx>, ) -> Self { @@ -385,7 +388,7 @@ impl<'tcx> UniversalRegions<'tcx> { } struct UniversalRegionsBuilder<'cx, 'tcx> { - infcx: &'cx InferCtxt<'tcx>, + infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, mir_def: ty::WithOptConstParam, mir_hir_id: HirId, param_env: ty::ParamEnv<'tcx>, @@ -403,7 +406,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { assert_eq!(FIRST_GLOBAL_INDEX, self.infcx.num_region_vars()); // Create the "global" region that is always free in all contexts: 'static. - let fr_static = self.infcx.next_nll_region_var(FR).to_region_vid(); + let fr_static = self + .infcx + .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("static"))) + .to_region_vid(); // We've now added all the global regions. The next ones we // add will be external. @@ -435,7 +441,17 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { |r| { debug!(?r); if !indices.indices.contains_key(&r) { - let region_vid = self.infcx.next_nll_region_var(FR); + let region_vid = { + let name = match r.get_name() { + Some(name) => name, + _ => Symbol::intern("anon"), + }; + + self.infcx.next_nll_region_var(FR, || { + RegionCtxt::LateBound(BoundRegionInfo::Name(name)) + }) + }; + debug!(?region_vid); indices.insert_late_bound_region(r, region_vid.to_region_vid()); } @@ -463,7 +479,17 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { for_each_late_bound_region_in_item(self.infcx.tcx, self.mir_def.did, |r| { debug!(?r); if !indices.indices.contains_key(&r) { - let region_vid = self.infcx.next_nll_region_var(FR); + let region_vid = { + let name = match r.get_name() { + Some(name) => name, + _ => Symbol::intern("anon"), + }; + + self.infcx.next_nll_region_var(FR, || { + RegionCtxt::LateBound(BoundRegionInfo::Name(name)) + }) + }; + debug!(?region_vid); indices.insert_late_bound_region(r, region_vid.to_region_vid()); } @@ -480,8 +506,13 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { LangItem::VaList, Some(self.infcx.tcx.def_span(self.mir_def.did)), ); - let region = - self.infcx.tcx.mk_re_var(self.infcx.next_nll_region_var(FR).to_region_vid()); + + let reg_vid = self + .infcx + .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("c-variadic"))) + .to_region_vid(); + + let region = self.infcx.tcx.mk_re_var(reg_vid); let va_list_ty = self.infcx.tcx.type_of(va_list_did).subst(self.infcx.tcx, &[region.into()]); @@ -491,7 +522,11 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } } - let fr_fn_body = self.infcx.next_nll_region_var(FR).to_region_vid(); + let fr_fn_body = self + .infcx + .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("fn_body"))) + .to_region_vid(); + let num_universals = self.infcx.num_region_vars(); debug!("build: global regions = {}..{}", FIRST_GLOBAL_INDEX, first_extern_index); @@ -718,7 +753,8 @@ trait InferCtxtExt<'tcx> { ); } -impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { +impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { + #[instrument(skip(self), level = "debug")] fn replace_free_regions_with_nll_infer_vars( &self, origin: NllRegionVariableOrigin, @@ -727,7 +763,17 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { where T: TypeFoldable<'tcx>, { - self.tcx.fold_regions(value, |_region, _depth| self.next_nll_region_var(origin)) + self.infcx.tcx.fold_regions(value, |region, _depth| { + let name = match region.get_name() { + Some(name) => name, + _ => Symbol::intern("anon"), + }; + debug!(?region, ?name); + + let reg_var = self.next_nll_region_var(origin, || RegionCtxt::Free(name)); + + reg_var + }) } #[instrument(level = "debug", skip(self, indices))] @@ -744,7 +790,15 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| { debug!(?br); let liberated_region = self.tcx.mk_re_free(all_outlive_scope.to_def_id(), br.kind); - let region_vid = self.next_nll_region_var(origin); + let region_vid = { + let name = match br.kind.get_name() { + Some(name) => name, + _ => Symbol::intern("anon"), + }; + + self.next_nll_region_var(origin, || RegionCtxt::Bound(BoundRegionInfo::Name(name))) + }; + indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid()); debug!(?liberated_region, ?region_vid); region_vid @@ -770,7 +824,17 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { for_each_late_bound_region_in_recursive_scope(self.tcx, mir_def_id, |r| { debug!(?r); if !indices.indices.contains_key(&r) { - let region_vid = self.next_nll_region_var(FR); + let region_vid = { + let name = match r.get_name() { + Some(name) => name, + _ => Symbol::intern("anon"), + }; + + self.next_nll_region_var(FR, || { + RegionCtxt::LateBound(BoundRegionInfo::Name(name)) + }) + }; + debug!(?region_vid); indices.insert_late_bound_region(r, region_vid.to_region_vid()); } @@ -786,8 +850,17 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { for_each_late_bound_region_in_item(self.tcx, mir_def_id, |r| { debug!(?r); if !indices.indices.contains_key(&r) { - let region_vid = self.next_nll_region_var(FR); - debug!(?region_vid); + let region_vid = { + let name = match r.get_name() { + Some(name) => name, + _ => Symbol::intern("anon"), + }; + + self.next_nll_region_var(FR, || { + RegionCtxt::LateBound(BoundRegionInfo::Name(name)) + }) + }; + indices.insert_late_bound_region(r, region_vid.to_region_vid()); } }); diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index c8e66eb672cc2..c4b11951ab7a0 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -27,7 +27,7 @@ pub struct Sccs { scc_data: SccData, } -struct SccData { +pub struct SccData { /// For each SCC, the range of `all_successors` where its /// successors can be found. ranges: IndexVec>, @@ -43,6 +43,14 @@ impl Sccs { SccsConstruction::construct(graph) } + pub fn scc_indices(&self) -> &IndexVec { + &self.scc_indices + } + + pub fn scc_data(&self) -> &SccData { + &self.scc_data + } + /// Returns the number of SCCs in the graph. pub fn num_sccs(&self) -> usize { self.scc_data.len() @@ -115,6 +123,14 @@ impl SccData { self.ranges.len() } + pub fn ranges(&self) -> &IndexVec> { + &self.ranges + } + + pub fn all_successors(&self) -> &Vec { + &self.all_successors + } + /// Returns the successors of the given SCC. fn successors(&self, scc: S) -> &[S] { // Annoyingly, `range` does not implement `Copy`, so we have diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index b9cb9732ca3ed..e993fb4c22bb9 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -27,7 +27,7 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, BoundVar, ToPredicate, Ty, TyCtxt}; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use std::fmt::Debug; use std::iter; @@ -683,7 +683,11 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { self.infcx.create_next_universe() } - fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> { + fn next_existential_region_var( + &mut self, + from_forall: bool, + _name: Option, + ) -> ty::Region<'tcx> { let origin = NllRegionVariableOrigin::Existential { from_forall }; self.infcx.next_nll_region_var(origin) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 2dd57e4c039af..29c9af5c43fb9 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1111,11 +1111,13 @@ impl<'tcx> InferCtxt<'tcx> { } /// Just a convenient wrapper of `next_region_var` for using during NLL. + #[instrument(skip(self), level = "debug")] pub fn next_nll_region_var(&self, origin: NllRegionVariableOrigin) -> ty::Region<'tcx> { self.next_region_var(RegionVariableOrigin::Nll(origin)) } /// Just a convenient wrapper of `next_region_var` for using during NLL. + #[instrument(skip(self), level = "debug")] pub fn next_nll_region_var_in_universe( &self, origin: NllRegionVariableOrigin, diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 644774c93c2a4..954334e88b0cb 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -31,7 +31,7 @@ use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::{ir::TypeVisitor, TypeSuperVisitable, TypeVisitable}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use std::fmt::Debug; use std::ops::ControlFlow; @@ -100,7 +100,11 @@ pub trait TypeRelatingDelegate<'tcx> { /// we will invoke this method to instantiate `'a` with an /// inference variable (though `'b` would be instantiated first, /// as a placeholder). - fn next_existential_region_var(&mut self, was_placeholder: bool) -> ty::Region<'tcx>; + fn next_existential_region_var( + &mut self, + was_placeholder: bool, + name: Option, + ) -> ty::Region<'tcx>; /// Creates a new region variable representing a /// higher-ranked region that is instantiated universally. @@ -188,7 +192,7 @@ where let placeholder = ty::PlaceholderRegion { universe, name: br.kind }; delegate.next_placeholder_region(placeholder) } else { - delegate.next_existential_region_var(true) + delegate.next_existential_region_var(true, br.kind.get_name()) } } }; diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 443c1b2d261ef..7f0935fb149fa 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1214,7 +1214,7 @@ impl<'tcx> MirVisitable<'tcx> for Option> { /// Extra information passed to `visit_ty` and friends to give context /// about where the type etc appears. -#[derive(Debug)] +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] pub enum TyContext { LocalDecl { /// The index of the local variable we are visiting. diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index f8d17433cf770..35ff71d888501 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1751,6 +1751,13 @@ impl<'tcx> Region<'tcx> { pub fn is_var(self) -> bool { matches!(self.kind(), ty::ReVar(_)) } + + pub fn as_var(self) -> Option { + match self.kind() { + ty::ReVar(vid) => Some(vid), + _ => None, + } + } } /// Type utilities