Skip to content

Commit d563a32

Browse files
committed
Cleanup free_region_relations a bit
1 parent 56b625b commit d563a32

File tree

6 files changed

+129
-72
lines changed

6 files changed

+129
-72
lines changed

compiler/rustc_borrowck/src/region_infer/values.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ pub(crate) struct PlaceholderIndices {
183183
}
184184

185185
impl PlaceholderIndices {
186+
/// Returns the `PlaceholderIndex` for the inserted `PlaceholderRegion`
186187
pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
187188
let (index, _) = self.indices.insert_full(placeholder);
188189
index.into()

compiler/rustc_borrowck/src/type_check/free_region_relations.rs

Lines changed: 122 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -218,64 +218,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
218218
self.inverse_outlives.add(fr_b, fr_a);
219219
}
220220

221+
#[instrument(level = "debug", skip(self))]
221222
pub(crate) fn create(mut self) -> CreateResult<'tcx> {
222-
let unnormalized_input_output_tys = self
223-
.universal_regions
224-
.unnormalized_input_tys
225-
.iter()
226-
.cloned()
227-
.chain(Some(self.universal_regions.unnormalized_output_ty));
228-
229-
// For each of the input/output types:
230-
// - Normalize the type. This will create some region
231-
// constraints, which we buffer up because we are
232-
// not ready to process them yet.
233-
// - Then compute the implied bounds. This will adjust
234-
// the `region_bound_pairs` and so forth.
235-
// - After this is done, we'll process the constraints, once
236-
// the `relations` is built.
237-
let mut normalized_inputs_and_output =
238-
Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
239-
let constraint_sets: Vec<_> = unnormalized_input_output_tys
240-
.flat_map(|ty| {
241-
debug!("build: input_or_output={:?}", ty);
242-
// We add implied bounds from both the unnormalized and normalized ty.
243-
// See issue #87748
244-
let constraints_implied1 = self.add_implied_bounds(ty);
245-
let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
246-
.param_env
247-
.and(type_op::normalize::Normalize::new(ty))
248-
.fully_perform(self.infcx)
249-
.unwrap_or_else(|_| {
250-
self.infcx
251-
.tcx
252-
.sess
253-
.delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty));
254-
TypeOpOutput {
255-
output: self.infcx.tcx.ty_error(),
256-
constraints: None,
257-
error_info: None,
258-
}
259-
});
260-
// Note: we need this in examples like
261-
// ```
262-
// trait Foo {
263-
// type Bar;
264-
// fn foo(&self) -> &Self::Bar;
265-
// }
266-
// impl Foo for () {
267-
// type Bar = ();
268-
// fn foo(&self) -> &() {}
269-
// }
270-
// ```
271-
// Both &Self::Bar and &() are WF
272-
let constraints_implied2 =
273-
if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None };
274-
normalized_inputs_and_output.push(norm_ty);
275-
constraints1.into_iter().chain(constraints_implied1).chain(constraints_implied2)
276-
})
277-
.collect();
278-
279223
// Insert the facts we know from the predicates. Why? Why not.
280224
let param_env = self.param_env;
281225
self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env));
@@ -294,19 +238,109 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
294238
self.relate_universal_regions(fr, fr_fn_body);
295239
}
296240

297-
for data in &constraint_sets {
298-
constraint_conversion::ConstraintConversion::new(
299-
self.infcx,
300-
&self.universal_regions,
301-
&self.region_bound_pairs,
302-
self.implicit_region_bound,
303-
self.param_env,
304-
Locations::All(DUMMY_SP),
305-
DUMMY_SP,
306-
ConstraintCategory::Internal,
307-
&mut self.constraints,
308-
)
309-
.convert_all(data);
241+
let unnormalized_input_output_tys = self
242+
.universal_regions
243+
.unnormalized_input_tys
244+
.iter()
245+
.cloned()
246+
.chain(Some(self.universal_regions.unnormalized_output_ty));
247+
248+
// For each of the input/output types:
249+
// - Normalize the type. This will create some region
250+
// constraints, which we buffer up because we are
251+
// not ready to process them yet.
252+
// - Then compute the implied bounds. This will adjust
253+
// the `region_bound_pairs` and so forth.
254+
// - After this is done, we'll process the constraints, once
255+
// the `relations` is built.
256+
let mut normalized_inputs_and_output =
257+
Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
258+
for ty in unnormalized_input_output_tys {
259+
debug!("build: input_or_output={:?}", ty);
260+
// We add implied bounds from both the unnormalized and normalized ty.
261+
// See issue #87748
262+
let constraints_unnorm = self.add_implied_bounds(ty);
263+
let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self
264+
.param_env
265+
.and(type_op::normalize::Normalize::new(ty))
266+
.fully_perform(self.infcx)
267+
.unwrap_or_else(|_| {
268+
self.infcx
269+
.tcx
270+
.sess
271+
.delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty));
272+
TypeOpOutput {
273+
output: self.infcx.tcx.ty_error(),
274+
constraints: None,
275+
error_info: None,
276+
}
277+
});
278+
279+
// Note: we need this in examples like
280+
// ```
281+
// trait Foo {
282+
// type Bar;
283+
// fn foo(&self) -> &Self::Bar;
284+
// }
285+
// impl Foo for () {
286+
// type Bar = ();
287+
// fn foo(&self) ->&() {}
288+
// }
289+
// ```
290+
// Both &Self::Bar and &() are WF
291+
let constraints_norm = self.add_implied_bounds(norm_ty);
292+
293+
// Okay, I should explain why these are all the way down here. Turns
294+
// out, it's actually a bit subtle. I'll use the test `issue-52057`
295+
// as an example (well, because it's the only test that failed
296+
// putting these calls immediately after the `add_implied_bounds`
297+
// calls.)
298+
//
299+
// So, the key bit is this impl:
300+
// ```rust,ignore (example)
301+
// impl<'a, I, P: ?Sized> Parser for &'a mut P
302+
// where P: Parser<Input = I>,
303+
// {
304+
// type Input = I;
305+
// fn parse_first<'x>(_: &'x mut Self::Input) {}
306+
// }
307+
//
308+
// As part of querying the implied bounds for `&mut Self::Input`
309+
// (note the unnormalized form), we query the obligations to prove
310+
// that it is WF. This turns out to be
311+
// [
312+
// <&'_#0r mut P as Parser>::Input: '_#1r,
313+
// Self: Parser,
314+
// P: '_#0r,
315+
// ]
316+
//
317+
// The wf code normalizes these obligations, so we actually end up with
318+
// [
319+
// _#0t: '_#1r,
320+
// &'_#0r mut P as Parser>::Input == _#0t,
321+
// Self: Parser,
322+
// P: '_#0r,
323+
// ]
324+
//
325+
// The implied bounds code then registers both the first two
326+
// predicates to be solved, since they contain type variables. Then
327+
// the implied bounds code goes through each of these obligations to
328+
// check if they should be registered as implied bounds. For
329+
// `_#0t: '_#1r`, there is an unresolved type variable, so it gets
330+
// skipped. The next two predicates never would registered. The last
331+
// predicate gets registered.
332+
//
333+
// At the end of this, for the unnormalized type
334+
// `&'x mut Self::Input`, `P: '_#0r' ends up as a implied bound and
335+
// `I: '_#1r` ends up as a constraint.
336+
//
337+
// Later, for the normalized type (`&'x mut I`), we don't do any
338+
// normalization, so we only end up with the implied bound `I: 'x`.
339+
constraints_unnorm.map(|c| self.push_region_constraints(c));
340+
constraints_normalize.map(|c| self.push_region_constraints(c));
341+
constraints_norm.map(|c| self.push_region_constraints(c));
342+
343+
normalized_inputs_and_output.push(norm_ty);
310344
}
311345

312346
CreateResult {
@@ -320,6 +354,24 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
320354
}
321355
}
322356

357+
#[instrument(skip(self, data), level = "debug")]
358+
fn push_region_constraints(&mut self, data: &QueryRegionConstraints<'tcx>) {
359+
debug!("constraints generated: {:#?}", data);
360+
361+
constraint_conversion::ConstraintConversion::new(
362+
self.infcx,
363+
&self.universal_regions,
364+
&self.region_bound_pairs,
365+
self.implicit_region_bound,
366+
self.param_env,
367+
Locations::All(DUMMY_SP),
368+
DUMMY_SP,
369+
ConstraintCategory::Internal,
370+
&mut self.constraints,
371+
)
372+
.convert_all(data);
373+
}
374+
323375
/// Update the type of a single local, which should represent
324376
/// either the return type of the MIR or one of its arguments. At
325377
/// the same time, compute and add any implied bounds that come

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,8 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> {
918918
}
919919

920920
impl<'tcx> MirTypeckRegionConstraints<'tcx> {
921+
/// Creates a `Region` that for a given `PlaceholderRegion`, or returns the
922+
/// region that corresponds to a previously created one.
921923
fn placeholder_region(
922924
&mut self,
923925
infcx: &InferCtxt<'_, 'tcx>,

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
238238
///
239239
/// In some cases, such as when `erased_ty` represents a `ty::Param`, however,
240240
/// the result is precise.
241+
#[instrument(level = "debug", skip(self))]
241242
fn declared_generic_bounds_from_env_for_erased_ty(
242243
&self,
243244
erased_ty: Ty<'tcx>,

compiler/rustc_traits/src/implied_outlives_bounds.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ fn compute_implied_outlives_bounds<'tcx>(
9797
// From the full set of obligations, just filter down to the
9898
// region relationships.
9999
implied_bounds.extend(obligations.into_iter().flat_map(|obligation| {
100+
debug!(?obligation);
100101
assert!(!obligation.has_escaping_bound_vars());
101102
match obligation.predicate.kind().no_bound_vars() {
102103
None => vec![],

src/test/ui/nll/issue-52057.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Regression test for #52057. There is an implied bound
2-
// that `I: 'a` where `'a` is the lifetime of `self` in `parse_first`;
3-
// but to observe that, one must normalize first.
2+
// that `I: 'x` where `'x` is the lifetime of the reference `&mut Self::Input`
3+
// in `parse_first`; but to observe that, one must normalize first.
44
//
55
// run-pass
66

0 commit comments

Comments
 (0)