summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_infer/src/infer/outlives
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_infer/src/infer/outlives')
-rw-r--r--compiler/rustc_infer/src/infer/outlives/components.rs22
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs4
-rw-r--r--compiler/rustc_infer/src/infer/outlives/for_liveness.rs7
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs30
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs29
-rw-r--r--compiler/rustc_infer/src/infer/outlives/test_type_match.rs27
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs46
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)
})
}
}