Skip to content

Commit 78d5ab6

Browse files
committed
Auto merge of rust-lang#120513 - compiler-errors:normalize-regions-for-nll, r=<try>
Normalize type outlives obligations in NLL for new solver Normalize the type outlives assumptions and obligations in MIR borrowck. This should fix any of the lazy-norm-related MIR borrowck problems. Also some cleanups from last PR: 1. Normalize obligations in a loop in lexical region resolution 2. Use `deeply_normalize_with_skipped_universes` in lexical resolution since we may have, e.g. `for<'a> Alias<'a>: 'b`. r? lcnr
2 parents cb4d9a1 + 870f77c commit 78d5ab6

File tree

8 files changed

+188
-68
lines changed

8 files changed

+188
-68
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.

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

+22-16
Original file line numberDiff line numberDiff line change
@@ -153,22 +153,28 @@ impl<'tcx> InferCtxt<'tcx> {
153153
.try_collect()
154154
.map_err(|e| (e, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)))?;
155155

156-
let my_region_obligations = self.take_registered_region_obligations();
157-
158-
for RegionObligation { sup_type, sub_region, origin } in my_region_obligations {
159-
let sup_type =
160-
deeply_normalize_ty(sup_type, origin.clone()).map_err(|e| (e, origin.clone()))?;
161-
debug!(?sup_type, ?sub_region, ?origin);
162-
163-
let outlives = &mut TypeOutlives::new(
164-
self,
165-
self.tcx,
166-
outlives_env.region_bound_pairs(),
167-
None,
168-
&normalized_caller_bounds,
169-
);
170-
let category = origin.to_constraint_category();
171-
outlives.type_must_outlive(origin, sup_type, sub_region, category);
156+
// Must loop since the process of normalizing may itself register region obligations.
157+
loop {
158+
let my_region_obligations = self.take_registered_region_obligations();
159+
if my_region_obligations.is_empty() {
160+
break;
161+
}
162+
163+
for RegionObligation { sup_type, sub_region, origin } in my_region_obligations {
164+
let sup_type = deeply_normalize_ty(sup_type, origin.clone())
165+
.map_err(|e| (e, origin.clone()))?;
166+
debug!(?sup_type, ?sub_region, ?origin);
167+
168+
let outlives = &mut TypeOutlives::new(
169+
self,
170+
self.tcx,
171+
outlives_env.region_bound_pairs(),
172+
None,
173+
&normalized_caller_bounds,
174+
);
175+
let category = origin.to_constraint_category();
176+
outlives.type_must_outlive(origin, sup_type, sub_region, category);
177+
}
172178
}
173179

174180
Ok(())

compiler/rustc_trait_selection/src/regions.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@ impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> {
2424
let ty = self.resolve_vars_if_possible(ty);
2525

2626
if self.next_trait_solver() {
27-
crate::solve::deeply_normalize(
27+
crate::solve::deeply_normalize_with_skipped_universes(
2828
self.at(
2929
&ObligationCause::dummy_with_span(origin.span()),
3030
outlives_env.param_env,
3131
),
3232
ty,
33+
vec![None; ty.outer_exclusive_binder().as_usize()],
3334
)
3435
.map_err(|_| ty)
3536
} else {
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// revisions: normalize_param_env normalize_obligation
1+
// revisions: normalize_param_env normalize_obligation hrtb
22
// check-pass
33
// compile-flags: -Znext-solver
44

@@ -7,16 +7,23 @@ trait Foo {
77
type Gat<'a> where <Self as Mirror>::Assoc: 'a;
88
#[cfg(normalize_obligation)]
99
type Gat<'a> where Self: 'a;
10+
#[cfg(hrtb)]
11+
type Gat<'b> where for<'a> <Self as MirrorRegion<'a>>::Assoc: 'b;
1012
}
1113

1214
trait Mirror { type Assoc: ?Sized; }
1315
impl<T: ?Sized> Mirror for T { type Assoc = T; }
1416

17+
trait MirrorRegion<'a> { type Assoc: ?Sized; }
18+
impl<'a, T> MirrorRegion<'a> for T { type Assoc = T; }
19+
1520
impl<T> Foo for T {
1621
#[cfg(normalize_param_env)]
1722
type Gat<'a> = i32 where T: 'a;
1823
#[cfg(normalize_obligation)]
1924
type Gat<'a> = i32 where <T as Mirror>::Assoc: 'a;
25+
#[cfg(hrtb)]
26+
type Gat<'b> = i32 where Self: 'b;
2027
}
2128

2229
fn main() {}

0 commit comments

Comments
 (0)