1
Fork 0

Update implied_outlives_bounds to properly register implied bounds behind normalization

This commit is contained in:
Jack Huey 2022-09-11 04:27:25 -04:00
parent 1a663c0f53
commit 0637b6b471
4 changed files with 62 additions and 43 deletions

View file

@ -226,7 +226,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
let param_env = self.param_env; let param_env = self.param_env;
self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env)); self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env));
// Finally:
// - outlives is reflexive, so `'r: 'r` for every region `'r` // - outlives is reflexive, so `'r: 'r` for every region `'r`
// - `'static: 'r` for every region `'r` // - `'static: 'r` for every region `'r`
// - `'r: 'fn_body` for every (other) universally quantified // - `'r: 'fn_body` for every (other) universally quantified
@ -263,7 +262,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
// We add implied bounds from both the unnormalized and normalized ty. // We add implied bounds from both the unnormalized and normalized ty.
// See issue #87748 // See issue #87748
let constraints_unnorm = self.add_implied_bounds(ty); let constraints_unnorm = self.add_implied_bounds(ty);
constraints_unnorm.map(|c| constraints.push(c)); if let Some(c) = constraints_unnorm {
constraints.push(c)
}
let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self
.param_env .param_env
.and(type_op::normalize::Normalize::new(ty)) .and(type_op::normalize::Normalize::new(ty))
@ -279,7 +280,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
error_info: None, error_info: None,
} }
}); });
constraints_normalize.map(|c| constraints.push(c)); if let Some(c) = constraints_normalize {
constraints.push(c)
}
// Note: we need this in examples like // Note: we need this in examples like
// ``` // ```
@ -295,7 +298,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
// Both &Self::Bar and &() are WF // Both &Self::Bar and &() are WF
if ty != norm_ty { if ty != norm_ty {
let constraints_norm = self.add_implied_bounds(norm_ty); let constraints_norm = self.add_implied_bounds(norm_ty);
constraints_norm.map(|c| constraints.push(c)); if let Some(c) = constraints_norm {
constraints.push(c)
}
} }
normalized_inputs_and_output.push(norm_ty); normalized_inputs_and_output.push(norm_ty);

View file

@ -910,7 +910,7 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> {
} }
impl<'tcx> MirTypeckRegionConstraints<'tcx> { impl<'tcx> MirTypeckRegionConstraints<'tcx> {
/// Creates a `Region` that for a given `PlaceholderRegion`, or returns the /// Creates a `Region` for a given `PlaceholderRegion`, or returns the
/// region that corresponds to a previously created one. /// region that corresponds to a previously created one.
fn placeholder_region( fn placeholder_region(
&mut self, &mut self,

View file

@ -70,48 +70,61 @@ fn compute_implied_outlives_bounds<'tcx>(
let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP) let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP)
.unwrap_or_default(); .unwrap_or_default();
// While these predicates should all be implied by other parts of for obligation in obligations {
// 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.
ocx.register_obligations(
obligations.iter().filter(|o| o.predicate.has_non_region_infer()).cloned(),
);
// From the full set of obligations, just filter down to the
// region relationships.
outlives_bounds.extend(obligations.into_iter().filter_map(|obligation| {
debug!(?obligation); debug!(?obligation);
assert!(!obligation.has_escaping_bound_vars()); assert!(!obligation.has_escaping_bound_vars());
match obligation.predicate.kind().no_bound_vars() {
None => None, // While these predicates should all be implied by other parts of
Some(pred) => match pred { // the program, they are still relevant as they may constrain
ty::PredicateKind::Clause(ty::Clause::Trait(..)) // inference variables, which is necessary to add the correct
| ty::PredicateKind::Subtype(..) // implied bounds in some cases, mostly when dealing with projections.
| ty::PredicateKind::Coerce(..) //
| ty::PredicateKind::Clause(ty::Clause::Projection(..)) // Another important point here: we only register `Projection`
| ty::PredicateKind::ClosureKind(..) // predicates, since otherwise we might register outlives
| ty::PredicateKind::ObjectSafe(..) // predicates containing inference variables, and we don't
| ty::PredicateKind::ConstEvaluatable(..) // learn anything new from those.
| ty::PredicateKind::ConstEquate(..) if obligation.predicate.has_non_region_infer() {
| ty::PredicateKind::Ambiguous match obligation.predicate.kind().skip_binder() {
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None, ty::PredicateKind::Clause(ty::Clause::Projection(..)) => {
ty::PredicateKind::WellFormed(arg) => { ocx.register_obligation(obligation.clone());
wf_args.push(arg);
None
} }
_ => {}
ty::PredicateKind::Clause(ty::Clause::RegionOutlives( }
ty::OutlivesPredicate(r_a, r_b),
)) => Some(ty::OutlivesPredicate(r_a.into(), r_b)),
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
ty_a,
r_b,
))) => Some(ty::OutlivesPredicate(ty_a.into(), r_b)),
},
} }
}));
let pred = match obligation.predicate.kind().no_bound_vars() {
None => continue,
Some(pred) => pred,
};
match pred {
ty::PredicateKind::Clause(ty::Clause::Trait(..))
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::Clause(ty::Clause::Projection(..))
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Ambiguous
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
// We need to search through *all* WellFormed predicates
ty::PredicateKind::WellFormed(arg) => {
wf_args.push(arg);
}
// We need to register region relationships
ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(
r_a,
r_b,
))) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)),
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
ty_a,
r_b,
))) => outlives_bounds.push(ty::OutlivesPredicate(ty_a.into(), r_b)),
}
}
} }
// This call to `select_all_or_error` is necessary to constrain inference variables, which we // This call to `select_all_or_error` is necessary to constrain inference variables, which we

View file

@ -4,6 +4,7 @@
#![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)] #![deny(rustc::diagnostic_outside_of_impl)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(drain_filter)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#[macro_use] #[macro_use]