summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_traits/src/implied_outlives_bounds.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_traits/src/implied_outlives_bounds.rs')
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs69
1 files changed, 36 insertions, 33 deletions
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index e3e78f70b..691b79f10 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -49,7 +49,8 @@ fn compute_implied_outlives_bounds<'tcx>(
let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
let mut wf_args = vec![ty.into()];
- let mut implied_bounds = vec![];
+ let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> =
+ vec![];
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
@@ -65,30 +66,17 @@ fn compute_implied_outlives_bounds<'tcx>(
// than the ultimate set. (Note: normally there won't be
// unresolved inference variables here anyway, but there might be
// during typeck under some circumstances.)
+ //
+ // FIXME(@lcnr): It's not really "always fine", having fewer implied
+ // bounds can be backward incompatible, e.g. #101951 was caused by
+ // us not dealing with inference vars in `TypeOutlives` predicates.
let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP)
.unwrap_or_default();
- // N.B., all of these predicates *ought* to be easily proven
- // true. In fact, their correctness is (mostly) implied by
- // other parts of the program. However, in #42552, we had
- // an annoying scenario where:
- //
- // - Some `T::Foo` gets normalized, resulting in a
- // variable `_1` and a `T: Trait<Foo=_1>` constraint
- // (not sure why it couldn't immediately get
- // solved). This result of `_1` got cached.
- // - These obligations were dropped on the floor here,
- // rather than being registered.
- // - Then later we would get a request to normalize
- // `T::Foo` which would result in `_1` being used from
- // the cache, but hence without the `T: Trait<Foo=_1>`
- // constraint. As a result, `_1` never gets resolved,
- // and we get an ICE (in dropck).
- //
- // Therefore, we register any predicates involving
- // inference variables. We restrict ourselves to those
- // involving inference variables both for efficiency and
- // to avoids duplicate errors that otherwise show up.
+ // While these predicates should all be implied by other parts of
+ // the program, they are still relevant as they may constrain
+ // inference variables, which is necessary to add the correct
+ // implied bounds in some cases, mostly when dealing with projections.
fulfill_cx.register_predicate_obligations(
infcx,
obligations.iter().filter(|o| o.predicate.has_infer_types_or_consts()).cloned(),
@@ -96,10 +84,10 @@ fn compute_implied_outlives_bounds<'tcx>(
// From the full set of obligations, just filter down to the
// region relationships.
- implied_bounds.extend(obligations.into_iter().flat_map(|obligation| {
+ outlives_bounds.extend(obligations.into_iter().filter_map(|obligation| {
assert!(!obligation.has_escaping_bound_vars());
match obligation.predicate.kind().no_bound_vars() {
- None => vec![],
+ None => None,
Some(pred) => match pred {
ty::PredicateKind::Trait(..)
| ty::PredicateKind::Subtype(..)
@@ -109,21 +97,18 @@ fn compute_implied_outlives_bounds<'tcx>(
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
- | ty::PredicateKind::TypeWellFormedFromEnv(..) => vec![],
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
ty::PredicateKind::WellFormed(arg) => {
wf_args.push(arg);
- vec![]
+ None
}
ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
- vec![OutlivesBound::RegionSubRegion(r_b, r_a)]
+ Some(ty::OutlivesPredicate(r_a.into(), r_b))
}
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => {
- let ty_a = infcx.resolve_vars_if_possible(ty_a);
- let mut components = smallvec![];
- push_outlives_components(tcx, ty_a, &mut components);
- implied_bounds_from_components(r_b, components)
+ Some(ty::OutlivesPredicate(ty_a.into(), r_b))
}
},
}
@@ -133,9 +118,27 @@ fn compute_implied_outlives_bounds<'tcx>(
// Ensure that those obligations that we had to solve
// get solved *here*.
match fulfill_cx.select_all_or_error(infcx).as_slice() {
- [] => Ok(implied_bounds),
- _ => Err(NoSolution),
+ [] => (),
+ _ => return Err(NoSolution),
}
+
+ // We lazily compute the outlives components as
+ // `select_all_or_error` constrains inference variables.
+ let implied_bounds = outlives_bounds
+ .into_iter()
+ .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() {
+ ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)],
+ ty::GenericArgKind::Type(ty_a) => {
+ let ty_a = infcx.resolve_vars_if_possible(ty_a);
+ let mut components = smallvec![];
+ push_outlives_components(tcx, ty_a, &mut components);
+ implied_bounds_from_components(r_b, components)
+ }
+ ty::GenericArgKind::Const(_) => unreachable!(),
+ })
+ .collect();
+
+ Ok(implied_bounds)
}
/// When we have an implied bound that `T: 'a`, we can further break