diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_borrowck/src/region_infer/mod.rs | 233 | ||||
-rw-r--r-- | compiler/rustc_borrowck/src/region_infer/opaque_types.rs | 393 | ||||
-rw-r--r-- | compiler/rustc_borrowck/src/region_infer/values.rs | 4 |
3 files changed, 187 insertions, 443 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 2894c6d29..8b63294fb 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -15,7 +15,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin}; use rustc_middle::mir::{ Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, - ConstraintCategory, Local, Location, ReturnConstraint, + ConstraintCategory, Local, Location, ReturnConstraint, TerminatorKind, }; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCauseCode; @@ -135,7 +135,6 @@ pub struct RegionInferenceContext<'tcx> { /// adds a new lower bound to the SCC it is analyzing: so you wind up /// with `'R: 'O` where `'R` is the pick-region and `'O` is the /// minimal viable option. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub(crate) struct AppliedMemberConstraint { /// The SCC that was affected. (The "member region".) /// @@ -246,6 +245,11 @@ enum Trace<'tcx> { NotVisited, } +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum ExtraConstraintInfo { + PlaceholderFromPredicate(Span), +} + impl<'tcx> RegionInferenceContext<'tcx> { /// Creates a new region inference context with a total of /// `num_region_variables` valid inference variables; the first N @@ -561,7 +565,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { #[instrument(skip(self, infcx, body, polonius_output), level = "debug")] pub(super) fn solve( &mut self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, polonius_output: Option<Rc<PoloniusOutput>>, @@ -591,13 +595,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { // constraints were too strong, and if so, emit or propagate those errors. if infcx.tcx.sess.opts.unstable_opts.polonius { self.check_polonius_subset_errors( - body, outlives_requirements.as_mut(), &mut errors_buffer, polonius_output.expect("Polonius output is unavailable despite `-Z polonius`"), ); } else { - self.check_universal_regions(body, outlives_requirements.as_mut(), &mut errors_buffer); + self.check_universal_regions(outlives_requirements.as_mut(), &mut errors_buffer); } if errors_buffer.is_empty() { @@ -832,7 +835,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// 'a`. See `TypeTest` for more details. fn check_type_tests( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>, @@ -920,7 +923,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { #[instrument(level = "debug", skip(self, infcx, propagated_outlives_requirements))] fn try_promote_type_test( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, type_test: &TypeTest<'tcx>, @@ -1033,7 +1036,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { #[instrument(level = "debug", skip(self, infcx))] fn try_promote_type_test_subject( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>, ) -> Option<ClosureOutlivesSubject<'tcx>> { let tcx = infcx.tcx; @@ -1139,7 +1142,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// include the CFG anyhow. /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding /// a result `'y`. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid { debug!(r = %self.region_value_str(r)); @@ -1151,8 +1154,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { lub = self.universal_region_relations.postdom_upper_bound(lub, ur); } - debug!(?lub); - lub } @@ -1167,8 +1168,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Therefore, this method should only be used in diagnostic code, /// where displaying *some* named universal region is better than /// falling back to 'static. + #[instrument(level = "debug", skip(self))] pub(crate) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid { - debug!("approx_universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); + debug!("{}", self.region_value_str(r)); // Find the smallest universal region that contains all other // universal regions within `region`. @@ -1177,7 +1179,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let static_r = self.universal_regions.fr_static; for ur in self.scc_values.universal_regions_outlived_by(r_scc) { let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur); - debug!("approx_universal_upper_bound: ur={:?} lub={:?} new_lub={:?}", ur, lub, new_lub); + debug!(?ur, ?lub, ?new_lub); // The upper bound of two non-static regions is static: this // means we know nothing about the relationship between these // two regions. Pick a 'better' one to use when constructing @@ -1201,7 +1203,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - debug!("approx_universal_upper_bound: r={:?} lub={:?}", r, lub); + debug!(?r, ?lub); lub } @@ -1210,7 +1212,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// `point`. fn eval_verify_bound( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, generic_ty: Ty<'tcx>, @@ -1260,7 +1262,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn eval_if_eq( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, generic_ty: Ty<'tcx>, lower_bound: RegionVid, @@ -1332,15 +1334,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // Evaluate whether `sup_region: sub_region`. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool { debug!( - "eval_outlives: sup_region's value = {:?} universal={:?}", + "sup_region's value = {:?} universal={:?}", self.region_value_str(sup_region), self.universal_regions.is_universal_region(sup_region), ); debug!( - "eval_outlives: sub_region's value = {:?} universal={:?}", + "sub_region's value = {:?} universal={:?}", self.region_value_str(sub_region), self.universal_regions.is_universal_region(sub_region), ); @@ -1353,7 +1355,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // true if `'sup` outlives static. if !self.universe_compatible(sub_region_scc, sup_region_scc) { debug!( - "eval_outlives: sub universe `{sub_region_scc:?}` is not nameable \ + "sub universe `{sub_region_scc:?}` is not nameable \ by super `{sup_region_scc:?}`, promoting to static", ); @@ -1374,9 +1376,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { }); if !universal_outlives { - debug!( - "eval_outlives: returning false because sub region contains a universal region not present in super" - ); + debug!("sub region contains a universal region not present in super"); return false; } @@ -1385,22 +1385,20 @@ impl<'tcx> RegionInferenceContext<'tcx> { if self.universal_regions.is_universal_region(sup_region) { // Micro-opt: universal regions contain all points. - debug!( - "eval_outlives: returning true because super is universal and hence contains all points" - ); + debug!("super is universal and hence contains all points"); return true; } - let result = self.scc_values.contains_points(sup_region_scc, sub_region_scc); - debug!("returning {} because of comparison between points in sup/sub", result); - result + debug!("comparison between points in sup/sub"); + + self.scc_values.contains_points(sup_region_scc, sub_region_scc) } /// Once regions have been propagated, this method is used to see /// whether any of the constraints were too strong. In particular, /// we want to check for a case where a universally quantified /// region exceeded its bounds. Consider: - /// ```compile_fail,E0312 + /// ```compile_fail /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } /// ``` /// In this case, returning `x` requires `&'a u32 <: &'b u32` @@ -1415,7 +1413,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// report them as errors. fn check_universal_regions( &self, - body: &Body<'tcx>, mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>, errors_buffer: &mut RegionErrors<'tcx>, ) { @@ -1426,7 +1423,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { // they did not grow too large, accumulating any requirements // for our caller into the `outlives_requirements` vector. self.check_universal_region( - body, fr, &mut propagated_outlives_requirements, errors_buffer, @@ -1455,7 +1451,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// <https://smallcultfollowing.com/babysteps/blog/2019/01/17/polonius-and-region-errors/> /// /// In the canonical example - /// ```compile_fail,E0312 + /// ```compile_fail /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } /// ``` /// returning `x` requires `&'a u32 <: &'b u32` and hence we establish (transitively) a @@ -1467,7 +1463,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// report them as errors. fn check_polonius_subset_errors( &self, - body: &Body<'tcx>, mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>, errors_buffer: &mut RegionErrors<'tcx>, polonius_output: Rc<PoloniusOutput>, @@ -1514,7 +1509,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { let propagated = self.try_propagate_universal_region_error( *longer_fr, *shorter_fr, - body, &mut propagated_outlives_requirements, ); if propagated == RegionRelationCheckResult::Error { @@ -1554,13 +1548,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// Things that are to be propagated are accumulated into the /// `outlives_requirements` vector. - #[instrument( - skip(self, body, propagated_outlives_requirements, errors_buffer), - level = "debug" - )] + #[instrument(skip(self, propagated_outlives_requirements, errors_buffer), level = "debug")] fn check_universal_region( &self, - body: &Body<'tcx>, longer_fr: RegionVid, propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>, errors_buffer: &mut RegionErrors<'tcx>, @@ -1583,7 +1573,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { if let RegionRelationCheckResult::Error = self.check_universal_region_relation( longer_fr, representative, - body, propagated_outlives_requirements, ) { errors_buffer.push(RegionErrorKind::RegionError { @@ -1603,7 +1592,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { if let RegionRelationCheckResult::Error = self.check_universal_region_relation( longer_fr, shorter_fr, - body, propagated_outlives_requirements, ) { // We only report the first region error. Subsequent errors are hidden so as @@ -1628,7 +1616,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, longer_fr: RegionVid, shorter_fr: RegionVid, - body: &Body<'tcx>, propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>, ) -> RegionRelationCheckResult { // If it is known that `fr: o`, carry on. @@ -1644,7 +1631,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.try_propagate_universal_region_error( longer_fr, shorter_fr, - body, propagated_outlives_requirements, ) } @@ -1656,7 +1642,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, longer_fr: RegionVid, shorter_fr: RegionVid, - body: &Body<'tcx>, propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>, ) -> RegionRelationCheckResult { if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { @@ -1668,7 +1653,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus); let blame_span_category = self.find_outlives_blame_span( - body, longer_fr, NllRegionVariableOrigin::FreeRegion, shorter_fr, @@ -1734,7 +1718,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn check_member_constraints( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, errors_buffer: &mut RegionErrors<'tcx>, ) { let member_constraints = self.member_constraints.clone(); @@ -1822,50 +1806,26 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn retrieve_closure_constraint_info( &self, - _body: &Body<'tcx>, - constraint: &OutlivesConstraint<'tcx>, - ) -> BlameConstraint<'tcx> { - let loc = match constraint.locations { - Locations::All(span) => { - return BlameConstraint { - category: constraint.category, - from_closure: false, - cause: ObligationCause::dummy_with_span(span), - variance_info: constraint.variance_info, - }; + constraint: OutlivesConstraint<'tcx>, + ) -> Option<(ConstraintCategory<'tcx>, Span)> { + match constraint.locations { + Locations::All(_) => None, + Locations::Single(loc) => { + self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub)).copied() } - Locations::Single(loc) => loc, - }; - - let opt_span_category = - self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub)); - opt_span_category - .map(|&(category, span)| BlameConstraint { - category, - from_closure: true, - cause: ObligationCause::dummy_with_span(span), - variance_info: constraint.variance_info, - }) - .unwrap_or(BlameConstraint { - category: constraint.category, - from_closure: false, - cause: ObligationCause::dummy_with_span(constraint.span), - variance_info: constraint.variance_info, - }) + } } /// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`. pub(crate) fn find_outlives_blame_span( &self, - body: &Body<'tcx>, fr1: RegionVid, fr1_origin: NllRegionVariableOrigin, fr2: RegionVid, ) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>) { - let BlameConstraint { category, cause, .. } = - self.best_blame_constraint(body, fr1, fr1_origin, |r| { - self.provides_universal_region(r, fr1, fr2) - }); + let BlameConstraint { category, cause, .. } = self + .best_blame_constraint(fr1, fr1_origin, |r| self.provides_universal_region(r, fr1, fr2)) + .0; (category, cause) } @@ -1970,7 +1930,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Finds some region R such that `fr1: R` and `R` is live at `elem`. - #[instrument(skip(self), level = "trace")] + #[instrument(skip(self), level = "trace", ret)] pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid { trace!(scc = ?self.constraint_sccs.scc(fr1)); trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]); @@ -2048,23 +2008,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// creating a constraint path that forces `R` to outlive /// `from_region`, and then finding the best choices within that /// path to blame. + #[instrument(level = "debug", skip(self, target_test))] pub(crate) fn best_blame_constraint( &self, - body: &Body<'tcx>, from_region: RegionVid, from_region_origin: NllRegionVariableOrigin, target_test: impl Fn(RegionVid) -> bool, - ) -> BlameConstraint<'tcx> { - debug!( - "best_blame_constraint(from_region={:?}, from_region_origin={:?})", - from_region, from_region_origin - ); - + ) -> (BlameConstraint<'tcx>, Vec<ExtraConstraintInfo>) { // Find all paths let (path, target_region) = self.find_constraint_paths_between_regions(from_region, target_test).unwrap(); debug!( - "best_blame_constraint: path={:#?}", + "path={:#?}", path.iter() .map(|c| format!( "{:?} ({:?}: {:?})", @@ -2075,6 +2030,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { .collect::<Vec<_>>() ); + let mut extra_info = vec![]; + for constraint in path.iter() { + let outlived = constraint.sub; + let Some(origin) = self.var_infos.get(outlived) else { continue; }; + let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(p)) = origin.origin else { continue; }; + debug!(?constraint, ?p); + let ConstraintCategory::Predicate(span) = constraint.category else { continue; }; + extra_info.push(ExtraConstraintInfo::PlaceholderFromPredicate(span)); + // We only want to point to one + break; + } + // We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint. // Instead, we use it to produce an improved `ObligationCauseCode`. // FIXME - determine what we should do if we encounter multiple `ConstraintCategory::Predicate` @@ -2100,23 +2067,33 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut categorized_path: Vec<BlameConstraint<'tcx>> = path .iter() .map(|constraint| { - if constraint.category == ConstraintCategory::ClosureBounds { - self.retrieve_closure_constraint_info(body, &constraint) - } else { - BlameConstraint { - category: constraint.category, - from_closure: false, - cause: ObligationCause::new( - constraint.span, - CRATE_HIR_ID, - cause_code.clone(), - ), - variance_info: constraint.variance_info, - } + let (category, span, from_closure, cause_code) = + if constraint.category == ConstraintCategory::ClosureBounds { + if let Some((category, span)) = + self.retrieve_closure_constraint_info(*constraint) + { + (category, span, true, ObligationCauseCode::MiscObligation) + } else { + ( + constraint.category, + constraint.span, + false, + ObligationCauseCode::MiscObligation, + ) + } + } else { + (constraint.category, constraint.span, false, cause_code.clone()) + }; + BlameConstraint { + category, + from_closure, + cause: ObligationCause::new(span, CRATE_HIR_ID, cause_code), + variance_info: constraint.variance_info, + outlives_constraint: *constraint, } }) .collect(); - debug!("best_blame_constraint: categorized_path={:#?}", categorized_path); + debug!("categorized_path={:#?}", categorized_path); // To find the best span to cite, we first try to look for the // final constraint that is interesting and where the `sup` is @@ -2214,10 +2191,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let best_choice = if blame_source { range.rev().find(find_region) } else { range.find(find_region) }; - debug!( - "best_blame_constraint: best_choice={:?} blame_source={}", - best_choice, blame_source - ); + debug!(?best_choice, ?blame_source, ?extra_info); if let Some(i) = best_choice { if let Some(next) = categorized_path.get(i + 1) { @@ -2226,7 +2200,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { { // The return expression is being influenced by the return type being // impl Trait, point at the return type and not the return expr. - return next.clone(); + return (next.clone(), extra_info); } } @@ -2246,7 +2220,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - return categorized_path[i].clone(); + return (categorized_path[i].clone(), extra_info); } // If that search fails, that is.. unusual. Maybe everything @@ -2254,14 +2228,35 @@ impl<'tcx> RegionInferenceContext<'tcx> { // appears to be the most interesting point to report to the // user via an even more ad-hoc guess. categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category)); - debug!("best_blame_constraint: sorted_path={:#?}", categorized_path); + debug!("sorted_path={:#?}", categorized_path); - categorized_path.remove(0) + (categorized_path.remove(0), extra_info) } pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { self.universe_causes[&universe].clone() } + + /// Tries to find the terminator of the loop in which the region 'r' resides. + /// Returns the location of the terminator if found. + pub(crate) fn find_loop_terminator_location( + &self, + r: RegionVid, + body: &Body<'_>, + ) -> Option<Location> { + let scc = self.constraint_sccs.scc(r.to_region_vid()); + let locations = self.scc_values.locations_outlived_by(scc); + for location in locations { + let bb = &body[location.block]; + if let Some(terminator) = &bb.terminator { + // terminator of a loop should be TerminatorKind::FalseUnwind + if let TerminatorKind::FalseUnwind { .. } = terminator.kind { + return Some(location); + } + } + } + None + } } impl<'tcx> RegionDefinition<'tcx> { @@ -2338,7 +2333,13 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx outlives_requirement={:?}", region, outlived_region, outlives_requirement, ); - ty::Binder::dummy(ty::OutlivesPredicate(region.into(), outlived_region)) + ( + ty::Binder::dummy(ty::OutlivesPredicate( + region.into(), + outlived_region, + )), + ConstraintCategory::BoringNoLocation, + ) } ClosureOutlivesSubject::Ty(ty) => { @@ -2348,7 +2349,10 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx outlives_requirement={:?}", ty, outlived_region, outlives_requirement, ); - ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region)) + ( + ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region)), + ConstraintCategory::BoringNoLocation, + ) } } }) @@ -2362,4 +2366,5 @@ pub struct BlameConstraint<'tcx> { pub from_closure: bool, pub cause: ObligationCause<'tcx>, pub variance_info: ty::VarianceDiagInfo<'tcx>, + pub outlives_constraint: OutlivesConstraint<'tcx>, } diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index d6712b6a4..465f353aa 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -2,18 +2,16 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::vec_map::VecMap; use rustc_hir::def_id::LocalDefId; use rustc_hir::OpaqueTyOrigin; -use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_infer::infer::{DefiningAnchor, InferCtxt}; use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine}; -use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts}; +use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{ self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt, TypeFoldable, }; use rustc_span::Span; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::TraitEngineExt as _; use super::RegionInferenceContext; @@ -58,10 +56,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`, /// which has no `external_name` in which case we use `'empty` as the /// region to pass to `infer_opaque_definition_from_instantiation`. - #[instrument(level = "debug", skip(self, infcx))] + #[instrument(level = "debug", skip(self, infcx), ret)] pub(crate) fn infer_opaque_types( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, ) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>> { let mut result: VecMap<LocalDefId, OpaqueHiddenType<'tcx>> = VecMap::new(); @@ -107,7 +105,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .iter() .find(|ur_vid| self.eval_equal(vid, **ur_vid)) .and_then(|ur_vid| self.definitions[*ur_vid].external_name) - .unwrap_or(infcx.tcx.lifetimes.re_root_empty), + .unwrap_or(infcx.tcx.lifetimes.re_erased), _ => region, }); @@ -192,7 +190,7 @@ pub trait InferCtxtExt<'tcx> { ) -> Ty<'tcx>; } -impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { +impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { /// Given the fully resolved, instantiated type for an opaque /// type, i.e., the value of an inference variable like C1 or C2 /// (*), computes the "definition type" for an opaque type @@ -227,31 +225,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return self.tcx.ty_error(); } - let OpaqueTypeKey { def_id, substs } = opaque_type_key; - - // Use substs to build up a reverse map from regions to their - // identity mappings. This is necessary because of `impl - // Trait` lifetimes are computed by replacing existing - // lifetimes with 'static and remapping only those used in the - // `impl Trait` return type, resulting in the parameters - // shifting. - let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id()); - debug!(?id_substs); - let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = - substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect(); - debug!("map = {:#?}", map); - - // Convert the type from the function into a type valid outside - // the function, by replacing invalid regions with 'static, - // after producing an error for each of them. - let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new( - self.tcx, - opaque_type_key, - map, - instantiated_ty.ty, - instantiated_ty.span, - )); - debug!(?definition_ty); + let definition_ty = instantiated_ty + .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false, origin) + .ty; if !check_opaque_type_parameter_valid( self.tcx, @@ -264,72 +240,70 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs` // on stable and we'd break that. - if let OpaqueTyOrigin::TyAlias = origin { - // This logic duplicates most of `check_opaque_meets_bounds`. - // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely. - let param_env = self.tcx.param_env(def_id); - let body_id = self.tcx.local_def_id_to_hir_id(def_id); - // HACK This bubble is required for this tests to pass: - // type-alias-impl-trait/issue-67844-nested-opaque.rs - self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter( - move |infcx| { - // Require the hidden type to be well-formed with only the generics of the opaque type. - // Defining use functions may have more bounds than the opaque type, which is ok, as long as the - // hidden type is well formed even without those bounds. - let predicate = - ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into())) - .to_predicate(infcx.tcx); - let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx); + let OpaqueTyOrigin::TyAlias = origin else { + return definition_ty; + }; + let def_id = opaque_type_key.def_id; + // This logic duplicates most of `check_opaque_meets_bounds`. + // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely. + let param_env = self.tcx.param_env(def_id); + let body_id = self.tcx.local_def_id_to_hir_id(def_id); + // HACK This bubble is required for this tests to pass: + // type-alias-impl-trait/issue-67844-nested-opaque.rs + let infcx = + self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).build(); + // Require the hidden type to be well-formed with only the generics of the opaque type. + // Defining use functions may have more bounds than the opaque type, which is ok, as long as the + // hidden type is well formed even without those bounds. + let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into())) + .to_predicate(infcx.tcx); + let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx); + + let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id()); - // Require that the hidden type actually fulfills all the bounds of the opaque type, even without - // the bounds that the function supplies. - match infcx.register_hidden_type( - OpaqueTypeKey { def_id, substs: id_substs }, - ObligationCause::misc(instantiated_ty.span, body_id), - param_env, + // Require that the hidden type actually fulfills all the bounds of the opaque type, even without + // the bounds that the function supplies. + let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs); + match infcx + .at(&ObligationCause::misc(instantiated_ty.span, body_id), param_env) + .eq(opaque_ty, definition_ty) + { + Ok(infer_ok) => { + for obligation in infer_ok.obligations { + fulfillment_cx.register_predicate_obligation(&infcx, obligation); + } + } + Err(err) => { + infcx + .err_ctxt() + .report_mismatched_types( + &ObligationCause::misc(instantiated_ty.span, body_id), + opaque_ty, definition_ty, - origin, - ) { - Ok(infer_ok) => { - for obligation in infer_ok.obligations { - fulfillment_cx.register_predicate_obligation(&infcx, obligation); - } - } - Err(err) => { - infcx - .report_mismatched_types( - &ObligationCause::misc(instantiated_ty.span, body_id), - self.tcx.mk_opaque(def_id.to_def_id(), id_substs), - definition_ty, - err, - ) - .emit(); - } - } + err, + ) + .emit(); + } + } - fulfillment_cx.register_predicate_obligation( - &infcx, - Obligation::misc(instantiated_ty.span, body_id, param_env, predicate), - ); + fulfillment_cx.register_predicate_obligation( + &infcx, + Obligation::misc(instantiated_ty.span, body_id, param_env, predicate), + ); - // Check that all obligations are satisfied by the implementation's - // version. - let errors = fulfillment_cx.select_all_or_error(&infcx); + // Check that all obligations are satisfied by the implementation's + // version. + let errors = fulfillment_cx.select_all_or_error(&infcx); - // This is still required for many(half of the tests in ui/type-alias-impl-trait) - // tests to pass - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + // This is still required for many(half of the tests in ui/type-alias-impl-trait) + // tests to pass + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - if errors.is_empty() { - definition_ty - } else { - infcx.report_fulfillment_errors(&errors, None, false); - self.tcx.ty_error() - } - }, - ) - } else { + if errors.is_empty() { definition_ty + } else { + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); + self.tcx.ty_error() } } } @@ -425,238 +399,3 @@ fn check_opaque_type_parameter_valid( } true } - -struct ReverseMapper<'tcx> { - tcx: TyCtxt<'tcx>, - - key: ty::OpaqueTypeKey<'tcx>, - map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, - map_missing_regions_to_empty: bool, - - /// initially `Some`, set to `None` once error has been reported - hidden_ty: Option<Ty<'tcx>>, - - /// Span of function being checked. - span: Span, -} - -impl<'tcx> ReverseMapper<'tcx> { - fn new( - tcx: TyCtxt<'tcx>, - key: ty::OpaqueTypeKey<'tcx>, - map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, - hidden_ty: Ty<'tcx>, - span: Span, - ) -> Self { - Self { - tcx, - key, - map, - map_missing_regions_to_empty: false, - hidden_ty: Some(hidden_ty), - span, - } - } - - fn fold_kind_mapping_missing_regions_to_empty( - &mut self, - kind: GenericArg<'tcx>, - ) -> GenericArg<'tcx> { - assert!(!self.map_missing_regions_to_empty); - self.map_missing_regions_to_empty = true; - let kind = kind.fold_with(self); - self.map_missing_regions_to_empty = false; - kind - } - - fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { - assert!(!self.map_missing_regions_to_empty); - kind.fold_with(self) - } -} - -impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - #[instrument(skip(self), level = "debug")] - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { - // Ignore bound regions and `'static` regions that appear in the - // type, we only need to remap regions that reference lifetimes - // from the function declaration. - // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`. - ty::ReLateBound(..) | ty::ReStatic => return r, - - // If regions have been erased (by writeback), don't try to unerase - // them. - ty::ReErased => return r, - - // The regions that we expect from borrow checking. - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {} - - ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => { - // All of the regions in the type should either have been - // erased by writeback, or mapped back to named regions by - // borrow checking. - bug!("unexpected region kind in opaque type: {:?}", r); - } - } - - let generics = self.tcx().generics_of(self.key.def_id); - match self.map.get(&r.into()).map(|k| k.unpack()) { - Some(GenericArgKind::Lifetime(r1)) => r1, - Some(u) => panic!("region mapped to unexpected kind: {:?}", u), - None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty, - None if generics.parent.is_some() => { - if let Some(hidden_ty) = self.hidden_ty.take() { - unexpected_hidden_region_diagnostic( - self.tcx, - self.tcx.def_span(self.key.def_id), - hidden_ty, - r, - self.key, - ) - .emit(); - } - self.tcx.lifetimes.re_root_empty - } - None => { - self.tcx - .sess - .struct_span_err(self.span, "non-defining opaque type use in defining scope") - .span_label( - self.span, - format!( - "lifetime `{}` is part of concrete type but not used in \ - parameter list of the `impl Trait` type alias", - r - ), - ) - .emit(); - - self.tcx().lifetimes.re_static - } - } - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match *ty.kind() { - ty::Closure(def_id, substs) => { - // I am a horrible monster and I pray for death. When - // we encounter a closure here, it is always a closure - // from within the function that we are currently - // type-checking -- one that is now being encapsulated - // in an opaque type. Ideally, we would - // go through the types/lifetimes that it references - // and treat them just like we would any other type, - // which means we would error out if we find any - // reference to a type/region that is not in the - // "reverse map". - // - // **However,** in the case of closures, there is a - // somewhat subtle (read: hacky) consideration. The - // problem is that our closure types currently include - // all the lifetime parameters declared on the - // enclosing function, even if they are unused by the - // closure itself. We can't readily filter them out, - // so here we replace those values with `'empty`. This - // can't really make a difference to the rest of the - // compiler; those regions are ignored for the - // outlives relation, and hence don't affect trait - // selection or auto traits, and they are erased - // during codegen. - - let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { - if index < generics.parent_count { - // Accommodate missing regions in the parent kinds... - self.fold_kind_mapping_missing_regions_to_empty(kind) - } else { - // ...but not elsewhere. - self.fold_kind_normally(kind) - } - })); - - self.tcx.mk_closure(def_id, substs) - } - - ty::Generator(def_id, substs, movability) => { - let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { - if index < generics.parent_count { - // Accommodate missing regions in the parent kinds... - self.fold_kind_mapping_missing_regions_to_empty(kind) - } else { - // ...but not elsewhere. - self.fold_kind_normally(kind) - } - })); - - self.tcx.mk_generator(def_id, substs, movability) - } - - ty::Param(param) => { - // Look it up in the substitution list. - match self.map.get(&ty.into()).map(|k| k.unpack()) { - // Found it in the substitution list; replace with the parameter from the - // opaque type. - Some(GenericArgKind::Type(t1)) => t1, - Some(u) => panic!("type mapped to unexpected kind: {:?}", u), - None => { - debug!(?param, ?self.map); - self.tcx - .sess - .struct_span_err( - self.span, - &format!( - "type parameter `{}` is part of concrete type but not \ - used in parameter list for the `impl Trait` type alias", - ty - ), - ) - .emit(); - - self.tcx().ty_error() - } - } - } - - _ => ty.super_fold_with(self), - } - } - - fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - trace!("checking const {:?}", ct); - // Find a const parameter - match ct.kind() { - ty::ConstKind::Param(..) => { - // Look it up in the substitution list. - match self.map.get(&ct.into()).map(|k| k.unpack()) { - // Found it in the substitution list, replace with the parameter from the - // opaque type. - Some(GenericArgKind::Const(c1)) => c1, - Some(u) => panic!("const mapped to unexpected kind: {:?}", u), - None => { - self.tcx - .sess - .struct_span_err( - self.span, - &format!( - "const parameter `{}` is part of concrete type but not \ - used in parameter list for the `impl Trait` type alias", - ct - ), - ) - .emit(); - - self.tcx().const_error(ct.ty()) - } - } - } - - _ => ct, - } - } -} diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index c81ef10f7..de20a4bb4 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -25,7 +25,7 @@ impl RegionValueElements { pub(crate) fn new(body: &Body<'_>) -> Self { let mut num_points = 0; let statements_before_block: IndexVec<BasicBlock, usize> = body - .basic_blocks() + .basic_blocks .iter() .map(|block_data| { let v = num_points; @@ -37,7 +37,7 @@ impl RegionValueElements { debug!("RegionValueElements: num_points={:#?}", num_points); let mut basic_blocks = IndexVec::with_capacity(num_points); - for (bb, bb_data) in body.basic_blocks().iter_enumerated() { + for (bb, bb_data) in body.basic_blocks.iter_enumerated() { basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb)); } |