Skip to content

Commit 870f77c

Browse files
Normalize type outlives obligations in NLL
1 parent 0eaa536 commit 870f77c

File tree

5 files changed

+156
-50
lines changed

5 files changed

+156
-50
lines changed

compiler/rustc_borrowck/src/type_check/constraint_conversion.rs

+76-21
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,15 @@ use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelega
55
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
66
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
77
use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
8+
use rustc_middle::traits::ObligationCause;
89
use rustc_middle::ty::GenericArgKind;
910
use rustc_middle::ty::{self, TyCtxt};
1011
use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
1112
use rustc_span::{Span, DUMMY_SP};
13+
use rustc_trait_selection::solve::deeply_normalize;
14+
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
15+
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
16+
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
1217

1318
use crate::{
1419
constraints::OutlivesConstraint,
@@ -33,6 +38,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
3338
/// our special inference variable there, we would mess that up.
3439
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
3540
implicit_region_bound: ty::Region<'tcx>,
41+
param_env: ty::ParamEnv<'tcx>,
3642
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
3743
locations: Locations,
3844
span: Span,
@@ -47,6 +53,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
4753
universal_regions: &'a UniversalRegions<'tcx>,
4854
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
4955
implicit_region_bound: ty::Region<'tcx>,
56+
param_env: ty::ParamEnv<'tcx>,
5057
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
5158
locations: Locations,
5259
span: Span,
@@ -59,6 +66,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
5966
universal_regions,
6067
region_bound_pairs,
6168
implicit_region_bound,
69+
param_env,
6270
known_type_outlives_obligations,
6371
locations,
6472
span,
@@ -137,36 +145,83 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
137145
// Extract out various useful fields we'll need below.
138146
let ConstraintConversion {
139147
tcx,
148+
infcx,
149+
param_env,
140150
region_bound_pairs,
141151
implicit_region_bound,
142152
known_type_outlives_obligations,
143153
..
144154
} = *self;
145155

146-
let ty::OutlivesPredicate(k1, r2) = predicate;
147-
match k1.unpack() {
148-
GenericArgKind::Lifetime(r1) => {
149-
let r1_vid = self.to_region_vid(r1);
150-
let r2_vid = self.to_region_vid(r2);
151-
self.add_outlives(r1_vid, r2_vid, constraint_category);
152-
}
156+
let mut outlives_predicates = vec![(predicate, constraint_category)];
157+
while let Some((ty::OutlivesPredicate(k1, r2), constraint_category)) =
158+
outlives_predicates.pop()
159+
{
160+
match k1.unpack() {
161+
GenericArgKind::Lifetime(r1) => {
162+
let r1_vid = self.to_region_vid(r1);
163+
let r2_vid = self.to_region_vid(r2);
164+
self.add_outlives(r1_vid, r2_vid, constraint_category);
165+
}
153166

154-
GenericArgKind::Type(t1) => {
155-
// we don't actually use this for anything, but
156-
// the `TypeOutlives` code needs an origin.
157-
let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
167+
GenericArgKind::Type(mut t1) => {
168+
// Normalize the type we receive from a `TypeOutlives` obligation
169+
// in the new trait solver.
170+
if infcx.next_trait_solver() {
171+
let result = CustomTypeOp::new(
172+
|ocx| {
173+
match deeply_normalize(
174+
ocx.infcx.at(
175+
&ObligationCause::dummy_with_span(self.span),
176+
param_env,
177+
),
178+
t1,
179+
) {
180+
Ok(normalized_ty) => {
181+
t1 = normalized_ty;
182+
}
183+
Err(e) => {
184+
infcx.err_ctxt().report_fulfillment_errors(e);
185+
}
186+
}
158187

159-
TypeOutlives::new(
160-
&mut *self,
161-
tcx,
162-
region_bound_pairs,
163-
Some(implicit_region_bound),
164-
known_type_outlives_obligations,
165-
)
166-
.type_must_outlive(origin, t1, r2, constraint_category);
167-
}
188+
Ok(())
189+
},
190+
"normalize type outlives obligation",
191+
)
192+
.fully_perform(infcx, self.span);
193+
194+
match result {
195+
Ok(TypeOpOutput { output: (), constraints, .. }) => {
196+
if let Some(constraints) = constraints {
197+
assert!(
198+
constraints.member_constraints.is_empty(),
199+
"FIXME(-Znext-solver): How do I handle these?"
200+
);
201+
outlives_predicates
202+
.extend(constraints.outlives.iter().copied());
203+
}
204+
}
205+
Err(_) => {}
206+
}
207+
}
168208

169-
GenericArgKind::Const(_) => unreachable!(),
209+
// we don't actually use this for anything, but
210+
// the `TypeOutlives` code needs an origin.
211+
let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
212+
213+
TypeOutlives::new(
214+
&mut *self,
215+
tcx,
216+
region_bound_pairs,
217+
Some(implicit_region_bound),
218+
known_type_outlives_obligations,
219+
)
220+
.type_must_outlive(origin, t1, r2, constraint_category);
221+
}
222+
223+
GenericArgKind::Const(_) => unreachable!(),
224+
}
170225
}
171226
}
172227

compiler/rustc_borrowck/src/type_check/free_region_relations.rs

+47-25
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ use rustc_infer::infer::region_constraints::GenericKind;
88
use rustc_infer::infer::InferCtxt;
99
use rustc_middle::mir::ConstraintCategory;
1010
use rustc_middle::traits::query::OutlivesBound;
11+
use rustc_middle::traits::ObligationCause;
1112
use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
12-
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
13+
use rustc_span::{ErrorGuaranteed, DUMMY_SP};
14+
use rustc_trait_selection::solve::deeply_normalize_with_skipped_universes;
15+
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
1316
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
1417
use std::rc::Rc;
1518
use type_op::TypeOpOutput;
@@ -52,15 +55,13 @@ pub(crate) struct CreateResult<'tcx> {
5255
pub(crate) fn create<'tcx>(
5356
infcx: &InferCtxt<'tcx>,
5457
param_env: ty::ParamEnv<'tcx>,
55-
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
5658
implicit_region_bound: ty::Region<'tcx>,
5759
universal_regions: &Rc<UniversalRegions<'tcx>>,
5860
constraints: &mut MirTypeckRegionConstraints<'tcx>,
5961
) -> CreateResult<'tcx> {
6062
UniversalRegionRelationsBuilder {
6163
infcx,
6264
param_env,
63-
known_type_outlives_obligations,
6465
implicit_region_bound,
6566
constraints,
6667
universal_regions: universal_regions.clone(),
@@ -178,7 +179,6 @@ impl UniversalRegionRelations<'_> {
178179
struct UniversalRegionRelationsBuilder<'this, 'tcx> {
179180
infcx: &'this InferCtxt<'tcx>,
180181
param_env: ty::ParamEnv<'tcx>,
181-
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
182182
universal_regions: Rc<UniversalRegions<'tcx>>,
183183
implicit_region_bound: ty::Region<'tcx>,
184184
constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
@@ -222,6 +222,35 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
222222
self.relate_universal_regions(fr, fr_fn_body);
223223
}
224224

225+
// Normalize the assumptions we use to borrowck the program.
226+
let mut constraints = vec![];
227+
let mut known_type_outlives_obligations = vec![];
228+
for bound in param_env.caller_bounds() {
229+
let Some(outlives) = bound.as_type_outlives_clause() else { continue };
230+
let ty::OutlivesPredicate(mut ty, region) = outlives.skip_binder();
231+
232+
// In the new solver, normalize the type-outlives obligation assumptions.
233+
if self.infcx.next_trait_solver() {
234+
match deeply_normalize_with_skipped_universes(
235+
self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), self.param_env),
236+
ty,
237+
vec![None; ty.outer_exclusive_binder().as_usize()],
238+
) {
239+
Ok(normalized_ty) => {
240+
ty = normalized_ty;
241+
}
242+
Err(e) => {
243+
self.infcx.err_ctxt().report_fulfillment_errors(e);
244+
}
245+
}
246+
}
247+
248+
known_type_outlives_obligations
249+
.push(outlives.rebind(ty::OutlivesPredicate(ty, region)));
250+
}
251+
let known_type_outlives_obligations =
252+
self.infcx.tcx.arena.alloc_slice(&known_type_outlives_obligations);
253+
225254
let unnormalized_input_output_tys = self
226255
.universal_regions
227256
.unnormalized_input_tys
@@ -239,7 +268,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
239268
// the `relations` is built.
240269
let mut normalized_inputs_and_output =
241270
Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
242-
let mut constraints = vec![];
243271
for ty in unnormalized_input_output_tys {
244272
debug!("build: input_or_output={:?}", ty);
245273
// We add implied bounds from both the unnormalized and normalized ty.
@@ -304,7 +332,19 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
304332
}
305333

306334
for c in constraints {
307-
self.push_region_constraints(c, span);
335+
constraint_conversion::ConstraintConversion::new(
336+
self.infcx,
337+
&self.universal_regions,
338+
&self.region_bound_pairs,
339+
self.implicit_region_bound,
340+
param_env,
341+
known_type_outlives_obligations,
342+
Locations::All(span),
343+
span,
344+
ConstraintCategory::Internal,
345+
self.constraints,
346+
)
347+
.convert_all(c);
308348
}
309349

310350
CreateResult {
@@ -313,30 +353,12 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
313353
outlives: self.outlives.freeze(),
314354
inverse_outlives: self.inverse_outlives.freeze(),
315355
}),
316-
known_type_outlives_obligations: self.known_type_outlives_obligations,
356+
known_type_outlives_obligations,
317357
region_bound_pairs: self.region_bound_pairs,
318358
normalized_inputs_and_output,
319359
}
320360
}
321361

322-
#[instrument(skip(self, data), level = "debug")]
323-
fn push_region_constraints(&mut self, data: &QueryRegionConstraints<'tcx>, span: Span) {
324-
debug!("constraints generated: {:#?}", data);
325-
326-
constraint_conversion::ConstraintConversion::new(
327-
self.infcx,
328-
&self.universal_regions,
329-
&self.region_bound_pairs,
330-
self.implicit_region_bound,
331-
self.known_type_outlives_obligations,
332-
Locations::All(span),
333-
span,
334-
ConstraintCategory::Internal,
335-
self.constraints,
336-
)
337-
.convert_all(data);
338-
}
339-
340362
/// Update the type of a single local, which should represent
341363
/// either the return type of the MIR or one of its arguments. At
342364
/// the same time, compute and add any implied bounds that come

compiler/rustc_borrowck/src/type_check/mod.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
156156
} = free_region_relations::create(
157157
infcx,
158158
param_env,
159-
// FIXME(-Znext-solver): These are unnormalized. Normalize them.
160-
infcx.tcx.arena.alloc_from_iter(
161-
param_env.caller_bounds().iter().filter_map(|clause| clause.as_type_outlives_clause()),
162-
),
163159
implicit_region_bound,
164160
universal_regions,
165161
&mut constraints,
@@ -1136,6 +1132,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
11361132
self.borrowck_context.universal_regions,
11371133
self.region_bound_pairs,
11381134
self.implicit_region_bound,
1135+
self.param_env,
11391136
self.known_type_outlives_obligations,
11401137
locations,
11411138
locations.span(self.body),
@@ -2740,6 +2737,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
27402737
self.borrowck_context.universal_regions,
27412738
self.region_bound_pairs,
27422739
self.implicit_region_bound,
2740+
self.param_env,
27432741
self.known_type_outlives_obligations,
27442742
locations,
27452743
DUMMY_SP, // irrelevant; will be overridden.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// check-pass
2+
// compile-flags: -Znext-solver
3+
4+
trait Mirror {
5+
type Assoc;
6+
}
7+
8+
impl<T> Mirror for T {
9+
type Assoc = T;
10+
}
11+
12+
fn is_static<T: 'static>() {}
13+
14+
fn test<T>() where <T as Mirror>::Assoc: 'static {
15+
is_static::<T>();
16+
}
17+
18+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// check-pass
2+
3+
trait Tr<'a> {
4+
type Assoc;
5+
}
6+
7+
fn outlives<'o, T: 'o>() {}
8+
9+
fn foo<'a, 'b, T: Tr<'a, Assoc = ()>>() {
10+
outlives::<'b, T::Assoc>();
11+
}
12+
13+
fn main() {}

0 commit comments

Comments
 (0)