Move param env bound deep normalization to OutlivesEnvironment building
This commit is contained in:
parent
48b7e38c06
commit
8e0909d98a
3 changed files with 37 additions and 45 deletions
|
@ -31,26 +31,14 @@ use crate::traits::query::OutlivesBound;
|
||||||
pub struct OutlivesEnvironment<'tcx> {
|
pub struct OutlivesEnvironment<'tcx> {
|
||||||
pub param_env: ty::ParamEnv<'tcx>,
|
pub param_env: ty::ParamEnv<'tcx>,
|
||||||
free_region_map: FreeRegionMap<'tcx>,
|
free_region_map: FreeRegionMap<'tcx>,
|
||||||
|
/// FIXME: Your first reaction may be that this is a bit strange. `RegionBoundPairs`
|
||||||
// Contains the implied region bounds in scope for our current body.
|
/// does not contain lifetimes, which are instead in the `FreeRegionMap`, and other
|
||||||
//
|
/// known type outlives are stored in the `known_type_outlives` set. So why do we
|
||||||
// Example:
|
/// have these at all? It turns out that removing these and using `known_type_outlives`
|
||||||
//
|
/// everywhere is just enough of a perf regression to matter. This can/should be
|
||||||
// ```
|
/// optimized in the future, though.
|
||||||
// fn foo<'a, 'b, T>(x: &'a T, y: &'b ()) {
|
|
||||||
// bar(x, y, |y: &'b T| { .. } // body B1)
|
|
||||||
// } // body B0
|
|
||||||
// ```
|
|
||||||
//
|
|
||||||
// Here, when checking the body B0, the list would be `[T: 'a]`, because we
|
|
||||||
// infer that `T` must outlive `'a` from the implied bounds on the
|
|
||||||
// fn declaration.
|
|
||||||
//
|
|
||||||
// For the body B1 however, the list would be `[T: 'a, T: 'b]`, because we
|
|
||||||
// also can see that -- within the closure body! -- `T` must
|
|
||||||
// outlive `'b`. This is not necessarily true outside the closure
|
|
||||||
// body, since the closure may never be called.
|
|
||||||
region_bound_pairs: RegionBoundPairs<'tcx>,
|
region_bound_pairs: RegionBoundPairs<'tcx>,
|
||||||
|
known_type_outlives: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// "Region-bound pairs" tracks outlives relations that are known to
|
/// "Region-bound pairs" tracks outlives relations that are known to
|
||||||
|
@ -59,9 +47,10 @@ pub struct OutlivesEnvironment<'tcx> {
|
||||||
pub type RegionBoundPairs<'tcx> = FxIndexSet<ty::OutlivesPredicate<'tcx, GenericKind<'tcx>>>;
|
pub type RegionBoundPairs<'tcx> = FxIndexSet<ty::OutlivesPredicate<'tcx, GenericKind<'tcx>>>;
|
||||||
|
|
||||||
impl<'tcx> OutlivesEnvironment<'tcx> {
|
impl<'tcx> OutlivesEnvironment<'tcx> {
|
||||||
/// Create a new `OutlivesEnvironment` with extra outlives bounds.
|
/// Create a new `OutlivesEnvironment` from normalized outlives bounds.
|
||||||
pub fn with_bounds(
|
pub fn from_normalized_bounds(
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
known_type_outlives: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
|
||||||
extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
|
extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut region_relation = TransitiveRelationBuilder::default();
|
let mut region_relation = TransitiveRelationBuilder::default();
|
||||||
|
@ -96,18 +85,21 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
|
||||||
|
|
||||||
OutlivesEnvironment {
|
OutlivesEnvironment {
|
||||||
param_env,
|
param_env,
|
||||||
|
known_type_outlives,
|
||||||
free_region_map: FreeRegionMap { relation: region_relation.freeze() },
|
free_region_map: FreeRegionMap { relation: region_relation.freeze() },
|
||||||
region_bound_pairs,
|
region_bound_pairs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrows current value of the `free_region_map`.
|
|
||||||
pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> {
|
pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> {
|
||||||
&self.free_region_map
|
&self.free_region_map
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrows current `region_bound_pairs`.
|
|
||||||
pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> {
|
pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> {
|
||||||
&self.region_bound_pairs
|
&self.region_bound_pairs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn known_type_outlives(&self) -> &[ty::PolyTypeOutlivesPredicate<'tcx>] {
|
||||||
|
&self.known_type_outlives
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,6 @@ use rustc_middle::ty::{
|
||||||
self, GenericArgKind, GenericArgsRef, PolyTypeOutlivesPredicate, Region, Ty, TyCtxt,
|
self, GenericArgKind, GenericArgsRef, PolyTypeOutlivesPredicate, Region, Ty, TyCtxt,
|
||||||
TypeFoldable as _, TypeVisitableExt,
|
TypeFoldable as _, TypeVisitableExt,
|
||||||
};
|
};
|
||||||
use rustc_span::DUMMY_SP;
|
|
||||||
use rustc_type_ir::outlives::{Component, push_outlives_components};
|
use rustc_type_ir::outlives::{Component, push_outlives_components};
|
||||||
use smallvec::smallvec;
|
use smallvec::smallvec;
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
@ -142,25 +141,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
) -> Result<(), (PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>)> {
|
) -> Result<(), (PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>)> {
|
||||||
assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot");
|
assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot");
|
||||||
|
|
||||||
let normalized_caller_bounds: Vec<_> = outlives_env
|
|
||||||
.param_env
|
|
||||||
.caller_bounds()
|
|
||||||
.iter()
|
|
||||||
.filter_map(|clause| {
|
|
||||||
let outlives = clause.as_type_outlives_clause()?;
|
|
||||||
Some(
|
|
||||||
deeply_normalize_ty(
|
|
||||||
outlives,
|
|
||||||
SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP),
|
|
||||||
)
|
|
||||||
// FIXME(-Znext-solver): How do we accurately report an error span here :(
|
|
||||||
.map_err(|NoSolution| {
|
|
||||||
(outlives, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP))
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.try_collect()?;
|
|
||||||
|
|
||||||
// Must loop since the process of normalizing may itself register region obligations.
|
// Must loop since the process of normalizing may itself register region obligations.
|
||||||
for iteration in 0.. {
|
for iteration in 0.. {
|
||||||
let my_region_obligations = self.take_registered_region_obligations();
|
let my_region_obligations = self.take_registered_region_obligations();
|
||||||
|
@ -194,7 +174,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
self.tcx,
|
self.tcx,
|
||||||
outlives_env.region_bound_pairs(),
|
outlives_env.region_bound_pairs(),
|
||||||
None,
|
None,
|
||||||
&normalized_caller_bounds,
|
outlives_env.known_type_outlives(),
|
||||||
);
|
);
|
||||||
let category = origin.to_constraint_category();
|
let category = origin.to_constraint_category();
|
||||||
outlives.type_must_outlive(origin, sup_type, sub_region, category);
|
outlives.type_must_outlive(origin, sup_type, sub_region, category);
|
||||||
|
|
|
@ -33,12 +33,32 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
|
||||||
assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
|
assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
|
||||||
implied_bounds_compat: bool,
|
implied_bounds_compat: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let mut bounds = vec![];
|
||||||
|
|
||||||
|
for bound in param_env.caller_bounds() {
|
||||||
|
if let Some(mut type_outlives) = bound.as_type_outlives_clause() {
|
||||||
|
if infcx.next_trait_solver() {
|
||||||
|
match crate::solve::deeply_normalize::<_, ScrubbedTraitError<'tcx>>(
|
||||||
|
infcx.at(&ObligationCause::dummy(), param_env),
|
||||||
|
type_outlives,
|
||||||
|
) {
|
||||||
|
Ok(new) => type_outlives = new,
|
||||||
|
Err(_) => {
|
||||||
|
infcx.dcx().delayed_bug(format!("could not normalize `{bound}`"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bounds.push(type_outlives);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: This needs to be modified so that we normalize the known type
|
// FIXME: This needs to be modified so that we normalize the known type
|
||||||
// outlives obligations then elaborate them into their region/type components.
|
// outlives obligations then elaborate them into their region/type components.
|
||||||
// Otherwise, `<W<'a> as Mirror>::Assoc: 'b` will not imply `'a: 'b` even
|
// Otherwise, `<W<'a> as Mirror>::Assoc: 'b` will not imply `'a: 'b` even
|
||||||
// if we can normalize `'a`.
|
// if we can normalize `'a`.
|
||||||
OutlivesEnvironment::with_bounds(
|
OutlivesEnvironment::from_normalized_bounds(
|
||||||
param_env,
|
param_env,
|
||||||
|
bounds,
|
||||||
infcx.implied_bounds_tys_with_compat(
|
infcx.implied_bounds_tys_with_compat(
|
||||||
body_id,
|
body_id,
|
||||||
param_env,
|
param_env,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue