diff options
Diffstat (limited to 'compiler/rustc_infer/src/infer/outlives')
7 files changed, 80 insertions, 85 deletions
diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index 38819e8ad..47038cfd4 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -11,6 +11,7 @@ use smallvec::{smallvec, SmallVec}; pub enum Component<'tcx> { Region(ty::Region<'tcx>), Param(ty::ParamTy), + Placeholder(ty::PlaceholderType), UnresolvedInferenceVariable(ty::InferTy), // Projections like `T::Foo` are tricky because a constraint like @@ -97,12 +98,12 @@ fn compute_components<'tcx>( compute_components(tcx, element, out, visited); } - ty::Closure(_, ref args) => { + ty::Closure(_, args) => { let tupled_ty = args.as_closure().tupled_upvars_ty(); compute_components(tcx, tupled_ty, out, visited); } - ty::Coroutine(_, ref args, _) => { + ty::Coroutine(_, args, _) => { // Same as the closure case let tupled_ty = args.as_coroutine().tupled_upvars_ty(); compute_components(tcx, tupled_ty, out, visited); @@ -120,6 +121,10 @@ fn compute_components<'tcx>( out.push(Component::Param(p)); } + ty::Placeholder(p) => { + out.push(Component::Placeholder(p)); + } + // For projections, we prefer to generate an obligation like // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the // regionck more ways to prove that it holds. However, @@ -176,7 +181,6 @@ fn compute_components<'tcx>( ty::Tuple(..) | // ... ty::FnPtr(_) | // OutlivesFunction (*) ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) - ty::Placeholder(..) | ty::Bound(..) | ty::Error(_) => { // (*) Function pointers and trait objects are both binders. @@ -199,7 +203,9 @@ pub(super) fn compute_alias_components_recursive<'tcx>( out: &mut SmallVec<[Component<'tcx>; 4]>, visited: &mut SsoHashSet<GenericArg<'tcx>>, ) { - let ty::Alias(kind, alias_ty) = alias_ty.kind() else { bug!() }; + let ty::Alias(kind, alias_ty) = alias_ty.kind() else { + unreachable!("can only call `compute_alias_components_recursive` on an alias type") + }; let opt_variances = if *kind == ty::Opaque { tcx.variances_of(alias_ty.def_id) } else { &[] }; for (index, child) in alias_ty.args.iter().enumerate() { if opt_variances.get(index) == Some(&ty::Bivariant) { @@ -213,8 +219,8 @@ pub(super) fn compute_alias_components_recursive<'tcx>( compute_components(tcx, ty, out, visited); } GenericArgKind::Lifetime(lt) => { - // Ignore late-bound regions. - if !lt.is_late_bound() { + // Ignore higher ranked regions. + if !lt.is_bound() { out.push(Component::Region(lt)); } } @@ -241,8 +247,8 @@ fn compute_components_recursive<'tcx>( compute_components(tcx, ty, out, visited); } GenericArgKind::Lifetime(lt) => { - // Ignore late-bound regions. - if !lt.is_late_bound() { + // Ignore higher ranked regions. + if !lt.is_bound() { out.push(Component::Region(lt)); } } diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 47e3dd762..f8dbfdde3 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -138,8 +138,8 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> { } OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) { ( - ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_), - ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_), + ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_), + ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_), ) => self.region_relation.add(r_a, r_b), (ty::ReError(_), _) | (_, ty::ReError(_)) => {} // FIXME(#109628): We shouldn't have existential variables in implied bounds. diff --git a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs index 398ac94ee..42e3d6cad 100644 --- a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs +++ b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs @@ -37,7 +37,7 @@ where fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { match *r { // ignore bound regions, keep visiting - ty::ReLateBound(_, _) => ControlFlow::Continue(()), + ty::ReBound(_, _) => ControlFlow::Continue(()), _ => { (self.op)(r); ControlFlow::Continue(()) @@ -84,7 +84,6 @@ where } else { test_type_match::extract_verify_if_eq( tcx, - param_env, &outlives.map_bound(|ty::OutlivesPredicate(ty, bound)| { VerifyIfEq { ty, bound } }), @@ -112,7 +111,9 @@ where }; for (idx, s) in args.iter().enumerate() { - if variances.map(|variances| variances[idx]) != Some(ty::Variance::Bivariant) { + if variances.map(|variances| variances[idx]) + != Some(ty::Variance::Bivariant) + { s.visit_with(self)?; } } diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 0987915f4..6379f84aa 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -3,7 +3,7 @@ use self::env::OutlivesEnvironment; use super::region_constraints::RegionConstraintData; use super::{InferCtxt, RegionResolutionError}; use crate::infer::free_regions::RegionRelations; -use crate::infer::lexical_region_resolve::{self, LexicalRegionResolutions}; +use crate::infer::lexical_region_resolve; use rustc_middle::traits::query::OutlivesBound; use rustc_middle::ty; @@ -37,32 +37,6 @@ pub fn explicit_outlives_bounds<'tcx>( } impl<'tcx> InferCtxt<'tcx> { - pub fn skip_region_resolution(&self) { - let (var_infos, _) = { - let mut inner = self.inner.borrow_mut(); - let inner = &mut *inner; - // Note: `inner.region_obligations` may not be empty, because we - // didn't necessarily call `process_registered_region_obligations`. - // This is okay, because that doesn't introduce new vars. - inner - .region_constraint_storage - .take() - .expect("regions already resolved") - .with_log(&mut inner.undo_log) - .into_infos_and_data() - }; - - let lexical_region_resolutions = LexicalRegionResolutions { - values: rustc_index::IndexVec::from_elem_n( - crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased), - var_infos.len(), - ), - }; - - let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions)); - assert!(old_value.is_none()); - } - /// Process the region constraints and return any errors that /// result. After this, no more unification operations should be /// done -- or the compiler will panic -- but it is legal to use @@ -93,7 +67,7 @@ impl<'tcx> InferCtxt<'tcx> { let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map()); let (lexical_region_resolutions, errors) = - lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data); + lexical_region_resolve::resolve(region_rels, var_infos, data); let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions)); assert!(old_value.is_none()); diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index f36802e12..395830d93 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -136,7 +136,7 @@ impl<'tcx> InferCtxt<'tcx> { let outlives = &mut TypeOutlives::new( self, self.tcx, - &outlives_env.region_bound_pairs(), + outlives_env.region_bound_pairs(), None, outlives_env.param_env, ); @@ -243,15 +243,18 @@ where Component::Param(param_ty) => { self.param_ty_must_outlive(origin, region, *param_ty); } + Component::Placeholder(placeholder_ty) => { + self.placeholder_ty_must_outlive(origin, region, *placeholder_ty); + } Component::Alias(alias_ty) => self.alias_ty_must_outlive(origin, region, *alias_ty), Component::EscapingAlias(subcomponents) => { - self.components_must_outlive(origin, &subcomponents, region, category); + self.components_must_outlive(origin, subcomponents, region, category); } Component::UnresolvedInferenceVariable(v) => { // ignore this, we presume it will yield an error // later, since if a type variable is not resolved by // this point it never will be - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( origin.span(), format!("unresolved inference variable in outlives: {v:?}"), ); @@ -267,11 +270,29 @@ where region: ty::Region<'tcx>, param_ty: ty::ParamTy, ) { - let verify_bound = self.verify_bound.param_bound(param_ty); + let verify_bound = self.verify_bound.param_or_placeholder_bound(param_ty.to_ty(self.tcx)); self.delegate.push_verify(origin, GenericKind::Param(param_ty), region, verify_bound); } #[instrument(level = "debug", skip(self))] + fn placeholder_ty_must_outlive( + &mut self, + origin: infer::SubregionOrigin<'tcx>, + region: ty::Region<'tcx>, + placeholder_ty: ty::PlaceholderType, + ) { + let verify_bound = self + .verify_bound + .param_or_placeholder_bound(Ty::new_placeholder(self.tcx, placeholder_ty)); + self.delegate.push_verify( + origin, + GenericKind::Placeholder(placeholder_ty), + region, + verify_bound, + ); + } + + #[instrument(level = "debug", skip(self))] fn alias_ty_must_outlive( &mut self, origin: infer::SubregionOrigin<'tcx>, diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 6f973ee37..236dc4ec3 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -36,19 +36,18 @@ use crate::infer::region_constraints::VerifyIfEq; /// like are used. This is a particular challenge since this function is invoked /// very late in inference and hence cannot make use of the normal inference /// machinery. -#[instrument(level = "debug", skip(tcx, param_env))] +#[instrument(level = "debug", skip(tcx))] pub fn extract_verify_if_eq<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, verify_if_eq_b: &ty::Binder<'tcx, VerifyIfEq<'tcx>>, test_ty: Ty<'tcx>, ) -> Option<ty::Region<'tcx>> { assert!(!verify_if_eq_b.has_escaping_bound_vars()); - let mut m = MatchAgainstHigherRankedOutlives::new(tcx, param_env); + let mut m = MatchAgainstHigherRankedOutlives::new(tcx); let verify_if_eq = verify_if_eq_b.skip_binder(); m.relate(verify_if_eq.ty, test_ty).ok()?; - if let ty::RegionKind::ReLateBound(depth, br) = verify_if_eq.bound.kind() { + if let ty::RegionKind::ReBound(depth, br) = verify_if_eq.bound.kind() { assert!(depth == ty::INNERMOST); match m.map.get(&br) { Some(&r) => Some(r), @@ -73,10 +72,9 @@ pub fn extract_verify_if_eq<'tcx>( } /// True if a (potentially higher-ranked) outlives -#[instrument(level = "debug", skip(tcx, param_env))] +#[instrument(level = "debug", skip(tcx))] pub(super) fn can_match_erased_ty<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, outlives_predicate: ty::Binder<'tcx, ty::TypeOutlivesPredicate<'tcx>>, erased_ty: Ty<'tcx>, ) -> bool { @@ -87,25 +85,20 @@ pub(super) fn can_match_erased_ty<'tcx>( // pointless micro-optimization true } else { - MatchAgainstHigherRankedOutlives::new(tcx, param_env).relate(outlives_ty, erased_ty).is_ok() + MatchAgainstHigherRankedOutlives::new(tcx).relate(outlives_ty, erased_ty).is_ok() } } struct MatchAgainstHigherRankedOutlives<'tcx> { tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, pattern_depth: ty::DebruijnIndex, map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>, } impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> { - fn new( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> MatchAgainstHigherRankedOutlives<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> MatchAgainstHigherRankedOutlives<'tcx> { MatchAgainstHigherRankedOutlives { tcx, - param_env, pattern_depth: ty::INNERMOST, map: FxHashMap::default(), } @@ -144,15 +137,13 @@ impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> { impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> { fn tag(&self) -> &'static str { - "Match" + "MatchAgainstHigherRankedOutlives" } fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } + fn a_is_expected(&self) -> bool { true } // irrelevant @@ -177,7 +168,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> { value: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { debug!("self.pattern_depth = {:?}", self.pattern_depth); - if let ty::RegionKind::ReLateBound(depth, br) = pattern.kind() + if let ty::RegionKind::ReBound(depth, br) = pattern.kind() && depth == self.pattern_depth { self.bind(br, value) diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 7f0a4717d..90282f58e 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,7 +1,7 @@ use crate::infer::outlives::components::{compute_alias_components_recursive, Component}; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::region_constraints::VerifyIfEq; -use crate::infer::VerifyBound; +use crate::infer::{GenericKind, VerifyBound}; use rustc_data_structures::sso::SsoHashSet; use rustc_middle::ty::GenericArg; use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt}; @@ -37,11 +37,11 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> { + pub fn param_or_placeholder_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { // Start with anything like `T: 'a` we can scrape from the // environment. If the environment contains something like // `for<'a> T: 'a`, then we know that `T` outlives everything. - let declared_bounds_from_env = self.declared_generic_bounds_from_env(param_ty); + let declared_bounds_from_env = self.declared_generic_bounds_from_env(ty); debug!(?declared_bounds_from_env); let mut param_bounds = vec![]; for declared_bound in declared_bounds_from_env { @@ -51,7 +51,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { param_bounds.push(VerifyBound::OutlivedBy(region)); } else { // This is `for<'a> T: 'a`. This means that `T` outlives everything! All done here. - debug!("found that {param_ty:?} outlives any lifetime, returning empty vector"); + debug!("found that {ty:?} outlives any lifetime, returning empty vector"); return VerifyBound::AllBounds(vec![]); } } @@ -130,12 +130,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // see the extensive comment in projection_must_outlive let recursive_bound = { let mut components = smallvec![]; - compute_alias_components_recursive( - self.tcx, - alias_ty_as_ty.into(), - &mut components, - visited, - ); + compute_alias_components_recursive(self.tcx, alias_ty_as_ty, &mut components, visited); self.bound_from_components(&components, visited) }; @@ -168,7 +163,10 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { ) -> VerifyBound<'tcx> { match *component { Component::Region(lt) => VerifyBound::OutlivedBy(lt), - Component::Param(param_ty) => self.param_bound(param_ty), + Component::Param(param_ty) => self.param_or_placeholder_bound(param_ty.to_ty(self.tcx)), + Component::Placeholder(placeholder_ty) => { + self.param_or_placeholder_bound(Ty::new_placeholder(self.tcx, placeholder_ty)) + } Component::Alias(alias_ty) => self.alias_bound(alias_ty, visited), Component::EscapingAlias(ref components) => { self.bound_from_components(components, visited) @@ -177,7 +175,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // ignore this, we presume it will yield an error // later, since if a type variable is not resolved by // this point it never will be - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( rustc_span::DUMMY_SP, format!("unresolved inference variable in outlives: {v:?}"), ); @@ -195,9 +193,9 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// bounds, but all the bounds it returns can be relied upon. fn declared_generic_bounds_from_env( &self, - param_ty: ty::ParamTy, + generic_ty: Ty<'tcx>, ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> { - let generic_ty = param_ty.to_ty(self.tcx); + assert!(matches!(generic_ty.kind(), ty::Param(_) | ty::Placeholder(_))); self.declared_generic_bounds_from_env_for_erased_ty(generic_ty) } @@ -242,10 +240,20 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { "declared_generic_bounds_from_env_for_erased_ty: region_bound_pair = {:?}", (r, p) ); + // Fast path for the common case. + match (&p, erased_ty.kind()) { + // In outlive routines, all types are expected to be fully normalized. + // And therefore we can safely use structural equality for alias types. + (GenericKind::Param(p1), ty::Param(p2)) if p1 == p2 => {} + (GenericKind::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => {} + (GenericKind::Alias(a1), ty::Alias(_, a2)) if a1.def_id == a2.def_id => {} + _ => return None, + } + let p_ty = p.to_ty(tcx); let erased_p_ty = self.tcx.erase_regions(p_ty); (erased_p_ty == erased_ty) - .then_some(ty::Binder::dummy(ty::OutlivesPredicate(p.to_ty(tcx), r))) + .then_some(ty::Binder::dummy(ty::OutlivesPredicate(p_ty, r))) }); param_bounds @@ -314,14 +322,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { ) -> impl Iterator<Item = ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> { let tcx = self.tcx; - let param_env = self.param_env; clauses.filter_map(|p| p.as_type_outlives_clause()).filter(move |outlives_predicate| { - super::test_type_match::can_match_erased_ty( - tcx, - param_env, - *outlives_predicate, - erased_ty, - ) + super::test_type_match::can_match_erased_ty(tcx, *outlives_predicate, erased_ty) }) } } |