Skip to content

Commit 8f63b79

Browse files
Normalize known type outlives within creation of OutlivesEnvironment
1 parent eee9781 commit 8f63b79

File tree

3 files changed

+89
-81
lines changed

3 files changed

+89
-81
lines changed
Lines changed: 37 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
use rustc_data_structures::fx::FxIndexSet;
22
use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
33
use rustc_middle::{bug, ty};
4-
use tracing::debug;
54

6-
use super::explicit_outlives_bounds;
75
use crate::infer::GenericKind;
86
use crate::infer::free_regions::FreeRegionMap;
9-
use crate::traits::query::OutlivesBound;
107

118
/// The `OutlivesEnvironment` collects information about what outlives
129
/// what in a given type-checking setting. For example, if we have a
@@ -31,26 +28,7 @@ use crate::traits::query::OutlivesBound;
3128
pub struct OutlivesEnvironment<'tcx> {
3229
pub param_env: ty::ParamEnv<'tcx>,
3330
free_region_map: FreeRegionMap<'tcx>,
34-
35-
// Contains the implied region bounds in scope for our current body.
36-
//
37-
// Example:
38-
//
39-
// ```
40-
// fn foo<'a, 'b, T>(x: &'a T, y: &'b ()) {
41-
// bar(x, y, |y: &'b T| { .. } // body B1)
42-
// } // body B0
43-
// ```
44-
//
45-
// Here, when checking the body B0, the list would be `[T: 'a]`, because we
46-
// infer that `T` must outlive `'a` from the implied bounds on the
47-
// fn declaration.
48-
//
49-
// For the body B1 however, the list would be `[T: 'a, T: 'b]`, because we
50-
// also can see that -- within the closure body! -- `T` must
51-
// outlive `'b`. This is not necessarily true outside the closure
52-
// body, since the closure may never be called.
53-
region_bound_pairs: RegionBoundPairs<'tcx>,
31+
known_type_outlives: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
5432
}
5533

5634
/// "Region-bound pairs" tracks outlives relations that are known to
@@ -59,45 +37,54 @@ pub struct OutlivesEnvironment<'tcx> {
5937
pub type RegionBoundPairs<'tcx> = FxIndexSet<ty::OutlivesPredicate<'tcx, GenericKind<'tcx>>>;
6038

6139
impl<'tcx> OutlivesEnvironment<'tcx> {
62-
/// Create a new `OutlivesEnvironment` with extra outlives bounds.
63-
pub fn with_bounds(
40+
/// Create a new `OutlivesEnvironment` from normalized outlives bounds.
41+
pub fn from_normalized_bounds(
6442
param_env: ty::ParamEnv<'tcx>,
65-
extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
43+
bounds: impl IntoIterator<
44+
Item = ty::Binder<'tcx, ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>>,
45+
>,
6646
) -> Self {
47+
let mut known_type_outlives = vec![];
6748
let mut region_relation = TransitiveRelationBuilder::default();
68-
let mut region_bound_pairs = RegionBoundPairs::default();
6949

7050
// Record relationships such as `T:'x` that don't go into the
7151
// free-region-map but which we use here.
72-
for outlives_bound in explicit_outlives_bounds(param_env).chain(extra_bounds) {
73-
debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
74-
match outlives_bound {
75-
OutlivesBound::RegionSubParam(r_a, param_b) => {
76-
region_bound_pairs
77-
.insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
52+
for bound in bounds {
53+
let ty::OutlivesPredicate(arg_b, r_a) = bound.skip_binder();
54+
match arg_b.unpack() {
55+
ty::GenericArgKind::Lifetime(r_b) => {
56+
match (*r_a, *r_b) {
57+
(
58+
ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_),
59+
ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_),
60+
) => region_relation.add(r_a, r_b),
61+
// Do nothing for higher-ranked region predicates.
62+
(
63+
ty::ReBound(..),
64+
ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_),
65+
)
66+
| (
67+
ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_),
68+
ty::ReBound(..),
69+
) => {}
70+
(ty::ReError(_), _) | (_, ty::ReError(_)) => {}
71+
// FIXME(#109628): We shouldn't have existential variables in implied bounds.
72+
// Panic here once the linked issue is resolved!
73+
(ty::ReVar(_), _) | (_, ty::ReVar(_)) => {}
74+
_ => bug!("add_outlives_bounds: unexpected regions: ({r_a:?}, {r_b:?})"),
75+
}
7876
}
79-
OutlivesBound::RegionSubAlias(r_a, alias_b) => {
80-
region_bound_pairs
81-
.insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
77+
ty::GenericArgKind::Type(ty_b) => {
78+
known_type_outlives.push(bound.rebind(ty::OutlivesPredicate(ty_b, r_a)));
8279
}
83-
OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) {
84-
(
85-
ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_),
86-
ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_),
87-
) => region_relation.add(r_a, r_b),
88-
(ty::ReError(_), _) | (_, ty::ReError(_)) => {}
89-
// FIXME(#109628): We shouldn't have existential variables in implied bounds.
90-
// Panic here once the linked issue is resolved!
91-
(ty::ReVar(_), _) | (_, ty::ReVar(_)) => {}
92-
_ => bug!("add_outlives_bounds: unexpected regions: ({r_a:?}, {r_b:?})"),
93-
},
80+
ty::GenericArgKind::Const(_) => unreachable!(),
9481
}
9582
}
9683

9784
OutlivesEnvironment {
9885
param_env,
86+
known_type_outlives,
9987
free_region_map: FreeRegionMap { relation: region_relation.freeze() },
100-
region_bound_pairs,
10188
}
10289
}
10390

@@ -107,7 +94,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
10794
}
10895

10996
/// Borrows current `region_bound_pairs`.
110-
pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> {
111-
&self.region_bound_pairs
97+
pub fn known_type_outlives(&self) -> &[ty::PolyTypeOutlivesPredicate<'tcx>] {
98+
&self.known_type_outlives
11299
}
113100
}

compiler/rustc_infer/src/infer/outlives/obligations.rs

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ use rustc_middle::ty::{
6767
self, GenericArgKind, GenericArgsRef, PolyTypeOutlivesPredicate, Region, Ty, TyCtxt,
6868
TypeFoldable as _, TypeVisitableExt,
6969
};
70-
use rustc_span::DUMMY_SP;
7170
use rustc_type_ir::outlives::{Component, push_outlives_components};
7271
use smallvec::smallvec;
7372
use tracing::{debug, instrument};
@@ -142,25 +141,6 @@ impl<'tcx> InferCtxt<'tcx> {
142141
) -> Result<(), (PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>)> {
143142
assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot");
144143

145-
let normalized_caller_bounds: Vec<_> = outlives_env
146-
.param_env
147-
.caller_bounds()
148-
.iter()
149-
.filter_map(|clause| {
150-
let outlives = clause.as_type_outlives_clause()?;
151-
Some(
152-
deeply_normalize_ty(
153-
outlives,
154-
SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP),
155-
)
156-
// FIXME(-Znext-solver): How do we accurately report an error span here :(
157-
.map_err(|NoSolution| {
158-
(outlives, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP))
159-
}),
160-
)
161-
})
162-
.try_collect()?;
163-
164144
// Must loop since the process of normalizing may itself register region obligations.
165145
for iteration in 0.. {
166146
let my_region_obligations = self.take_registered_region_obligations();
@@ -189,12 +169,14 @@ impl<'tcx> InferCtxt<'tcx> {
189169

190170
debug!(?sup_type, ?sub_region, ?origin);
191171

172+
let region_bound_pairs = &Default::default();
192173
let outlives = &mut TypeOutlives::new(
193174
self,
194175
self.tcx,
195-
outlives_env.region_bound_pairs(),
176+
// TODO:
177+
region_bound_pairs,
196178
None,
197-
&normalized_caller_bounds,
179+
outlives_env.known_type_outlives(),
198180
);
199181
let category = origin.to_constraint_category();
200182
outlives.type_must_outlive(origin, sup_type, sub_region, category);

compiler/rustc_trait_selection/src/regions.rs

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc_hir::def_id::LocalDefId;
22
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
33
use rustc_infer::infer::{InferCtxt, RegionResolutionError};
4+
use rustc_infer::traits::query::OutlivesBound;
45
use rustc_macros::extension;
56
use rustc_middle::traits::ObligationCause;
67
use rustc_middle::traits::query::NoSolution;
@@ -33,19 +34,57 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
3334
assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
3435
implied_bounds_compat: bool,
3536
) -> Self {
37+
let mut bounds = vec![];
38+
39+
for bound in param_env.caller_bounds() {
40+
if let Some(region_outlives) = bound.as_region_outlives_clause() {
41+
bounds.push(region_outlives.map_bound(|o| ty::OutlivesPredicate(o.0.into(), o.1)));
42+
} else if let Some(mut type_outlives) = bound.as_type_outlives_clause() {
43+
if infcx.next_trait_solver() {
44+
match crate::solve::deeply_normalize::<_, ScrubbedTraitError<'tcx>>(
45+
infcx.at(&ObligationCause::dummy(), param_env),
46+
type_outlives,
47+
) {
48+
Ok(new) => type_outlives = new,
49+
Err(_) => {
50+
infcx.dcx().delayed_bug(format!("could not normalize `{bound}`"));
51+
}
52+
}
53+
}
54+
bounds.push(type_outlives.map_bound(|o| ty::OutlivesPredicate(o.0.into(), o.1)));
55+
}
56+
}
57+
58+
for bound in infcx.implied_bounds_tys_with_compat(
59+
body_id,
60+
param_env,
61+
assumed_wf_tys,
62+
implied_bounds_compat,
63+
) {
64+
match bound {
65+
OutlivesBound::RegionSubRegion(r_a, r_b) => {
66+
bounds.push(ty::Binder::dummy(ty::OutlivesPredicate(r_b.into(), r_a)));
67+
}
68+
OutlivesBound::RegionSubParam(r_a, param) => {
69+
bounds.push(ty::Binder::dummy(ty::OutlivesPredicate(
70+
Ty::new_param(infcx.tcx, param.index, param.name).into(),
71+
r_a,
72+
)));
73+
}
74+
OutlivesBound::RegionSubAlias(r_a, alias) => {
75+
bounds.push(ty::Binder::dummy(ty::OutlivesPredicate(
76+
Ty::new_alias(infcx.tcx, alias.kind(infcx.tcx), alias).into(),
77+
r_a,
78+
)));
79+
}
80+
}
81+
}
82+
3683
// FIXME: This needs to be modified so that we normalize the known type
3784
// outlives obligations then elaborate them into their region/type components.
3885
// Otherwise, `<W<'a> as Mirror>::Assoc: 'b` will not imply `'a: 'b` even
3986
// if we can normalize `'a`.
40-
OutlivesEnvironment::with_bounds(
41-
param_env,
42-
infcx.implied_bounds_tys_with_compat(
43-
body_id,
44-
param_env,
45-
assumed_wf_tys,
46-
implied_bounds_compat,
47-
),
48-
)
87+
OutlivesEnvironment::from_normalized_bounds(param_env, bounds)
4988
}
5089
}
5190

0 commit comments

Comments
 (0)