summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_traits/src/implied_outlives_bounds.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs76
1 files changed, 41 insertions, 35 deletions
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index e3e78f70b..7d36b9558 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -35,7 +35,7 @@ fn implied_outlives_bounds<'tcx>(
}
fn compute_implied_outlives_bounds<'tcx>(
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
) -> Fallible<Vec<OutlivesBound<'tcx>>> {
@@ -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,41 +66,28 @@ 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(),
+ obligations.iter().filter(|o| o.predicate.has_non_region_infer()).cloned(),
);
// 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
@@ -153,6 +156,9 @@ fn implied_bounds_from_components<'tcx>(
Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
Component::Projection(p) => Some(OutlivesBound::RegionSubProjection(sub_region, p)),
+ Component::Opaque(def_id, substs) => {
+ Some(OutlivesBound::RegionSubOpaque(sub_region, def_id, substs))
+ }
Component::EscapingProjection(_) =>
// If the projection has escaping regions, don't
// try to infer any implied bounds even for its