improve infer var handling for implied bounds
This commit is contained in:
parent
efa717bc2d
commit
71f8fd5c58
4 changed files with 41 additions and 34 deletions
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue