Skip to content

Commit c29082f

Browse files
committed
Auto merge of rust-lang#120544 - BoxyUwU:enter_forall, r=lcnr
Introduce `enter_forall` to supercede `instantiate_binder_with_placeholders` r? `@lcnr` Long term we'd like to experiment with decrementing the universe count after "exiting" binders so that we do not end up creating infer vars in non-root universes even when they logically reside in the root universe. The fact that we dont do this currently results in a number of issues in the new trait solver where we consider goals to be ambiguous because otherwise it would require lowering the universe of an infer var. i.e. the goal `?x.0 eq <T as Trait<?y.1>>::Assoc` where the alias is rigid would not be able to instantiate `?x` with the alias as there would be a universe error. This PR is the first-ish sort of step towards being able to implement this as eventually we would want to decrement the universe in `enter_forall`. Unfortunately its Difficult to actually implement decrementing universes nicely so this is a separate step which moves us closer to the long term goal ✨
2 parents 1280928 + f867742 commit c29082f

File tree

21 files changed

+627
-547
lines changed

21 files changed

+627
-547
lines changed

compiler/rustc_infer/src/infer/mod.rs

+10-9
Original file line numberDiff line numberDiff line change
@@ -1032,21 +1032,22 @@ impl<'tcx> InferCtxt<'tcx> {
10321032
_ => {}
10331033
}
10341034

1035-
let ty::SubtypePredicate { a_is_expected, a, b } =
1036-
self.instantiate_binder_with_placeholders(predicate);
1037-
1038-
Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b))
1035+
self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| {
1036+
Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b))
1037+
})
10391038
}
10401039

10411040
pub fn region_outlives_predicate(
10421041
&self,
10431042
cause: &traits::ObligationCause<'tcx>,
10441043
predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
10451044
) {
1046-
let ty::OutlivesPredicate(r_a, r_b) = self.instantiate_binder_with_placeholders(predicate);
1047-
let origin =
1048-
SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span));
1049-
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
1045+
self.enter_forall(predicate, |ty::OutlivesPredicate(r_a, r_b)| {
1046+
let origin = SubregionOrigin::from_obligation_cause(cause, || {
1047+
RelateRegionParamBound(cause.span)
1048+
});
1049+
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
1050+
})
10501051
}
10511052

10521053
/// Number of type variables created so far.
@@ -1455,7 +1456,7 @@ impl<'tcx> InferCtxt<'tcx> {
14551456
// Use this method if you'd like to find some substitution of the binder's
14561457
// variables (e.g. during a method call). If there isn't a [`BoundRegionConversionTime`]
14571458
// that corresponds to your use case, consider whether or not you should
1458-
// use [`InferCtxt::instantiate_binder_with_placeholders`] instead.
1459+
// use [`InferCtxt::enter_forall`] instead.
14591460
pub fn instantiate_binder_with_fresh_vars<T>(
14601461
&self,
14611462
span: Span,

compiler/rustc_infer/src/infer/relate/higher_ranked.rs

+46-18
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,25 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
3838
// First, we instantiate each bound region in the supertype with a
3939
// fresh placeholder region. Note that this automatically creates
4040
// a new universe if needed.
41-
let sup_prime = self.infcx.instantiate_binder_with_placeholders(sup);
41+
self.infcx.enter_forall(sup, |sup_prime| {
42+
// Next, we instantiate each bound region in the subtype
43+
// with a fresh region variable. These region variables --
44+
// but no other preexisting region variables -- can name
45+
// the placeholders.
46+
let sub_prime =
47+
self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub);
48+
debug!("a_prime={:?}", sub_prime);
49+
debug!("b_prime={:?}", sup_prime);
4250

43-
// Next, we instantiate each bound region in the subtype
44-
// with a fresh region variable. These region variables --
45-
// but no other preexisting region variables -- can name
46-
// the placeholders.
47-
let sub_prime = self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub);
48-
49-
debug!("a_prime={:?}", sub_prime);
50-
debug!("b_prime={:?}", sup_prime);
51-
52-
// Compare types now that bound regions have been replaced.
53-
let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime)?;
54-
55-
debug!("OK result={result:?}");
56-
// NOTE: returning the result here would be dangerous as it contains
57-
// placeholders which **must not** be named afterwards.
58-
Ok(())
51+
// Compare types now that bound regions have been replaced.
52+
let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime);
53+
if result.is_ok() {
54+
debug!("OK result={result:?}");
55+
}
56+
// NOTE: returning the result here would be dangerous as it contains
57+
// placeholders which **must not** be named afterwards.
58+
result.map(|_| ())
59+
})
5960
}
6061
}
6162

@@ -68,9 +69,11 @@ impl<'tcx> InferCtxt<'tcx> {
6869
/// This is the first step of checking subtyping when higher-ranked things are involved.
6970
/// For more details visit the relevant sections of the [rustc dev guide].
7071
///
72+
/// `fn enter_forall` should be preferred over this method.
73+
///
7174
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
7275
#[instrument(level = "debug", skip(self), ret)]
73-
pub fn instantiate_binder_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T
76+
pub fn enter_forall_and_leak_universe<T>(&self, binder: ty::Binder<'tcx, T>) -> T
7477
where
7578
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
7679
{
@@ -106,6 +109,31 @@ impl<'tcx> InferCtxt<'tcx> {
106109
self.tcx.replace_bound_vars_uncached(binder, delegate)
107110
}
108111

112+
/// Replaces all bound variables (lifetimes, types, and constants) bound by
113+
/// `binder` with placeholder variables in a new universe and then calls the
114+
/// closure `f` with the instantiated value. The new placeholders can only be
115+
/// named by inference variables created inside of the closure `f` or afterwards.
116+
///
117+
/// This is the first step of checking subtyping when higher-ranked things are involved.
118+
/// For more details visit the relevant sections of the [rustc dev guide].
119+
///
120+
/// This method should be preferred over `fn enter_forall_and_leak_universe`.
121+
///
122+
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
123+
#[instrument(level = "debug", skip(self, f))]
124+
pub fn enter_forall<T, U>(&self, forall: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U) -> U
125+
where
126+
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
127+
{
128+
// FIXME: currently we do nothing to prevent placeholders with the new universe being
129+
// used after exiting `f`. For example region subtyping can result in outlives constraints
130+
// that name placeholders created in this function. Nested goals from type relations can
131+
// also contain placeholders created by this function.
132+
let value = self.enter_forall_and_leak_universe(forall);
133+
debug!("?value");
134+
f(value)
135+
}
136+
109137
/// See [RegionConstraintCollector::leak_check][1]. We only check placeholder
110138
/// leaking into `outer_universe`, i.e. placeholders which cannot be named by that
111139
/// universe.

compiler/rustc_infer/src/infer/relate/nll.rs

+50-47
Original file line numberDiff line numberDiff line change
@@ -261,52 +261,55 @@ where
261261
Ok(a)
262262
}
263263

264-
#[instrument(skip(self), level = "debug")]
265-
fn instantiate_binder_with_placeholders<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
264+
fn enter_forall<T, U>(
265+
&mut self,
266+
binder: ty::Binder<'tcx, T>,
267+
f: impl FnOnce(&mut Self, T) -> U,
268+
) -> U
266269
where
267270
T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
268271
{
269-
if let Some(inner) = binder.no_bound_vars() {
270-
return inner;
271-
}
272-
273-
let mut next_region = {
274-
let nll_delegate = &mut self.delegate;
275-
let mut lazy_universe = None;
272+
let value = if let Some(inner) = binder.no_bound_vars() {
273+
inner
274+
} else {
275+
let mut next_region = {
276+
let nll_delegate = &mut self.delegate;
277+
let mut lazy_universe = None;
278+
279+
move |br: ty::BoundRegion| {
280+
// The first time this closure is called, create a
281+
// new universe for the placeholders we will make
282+
// from here out.
283+
let universe = lazy_universe.unwrap_or_else(|| {
284+
let universe = nll_delegate.create_next_universe();
285+
lazy_universe = Some(universe);
286+
universe
287+
});
288+
289+
let placeholder = ty::PlaceholderRegion { universe, bound: br };
290+
debug!(?placeholder);
291+
let placeholder_reg = nll_delegate.next_placeholder_region(placeholder);
292+
debug!(?placeholder_reg);
293+
294+
placeholder_reg
295+
}
296+
};
276297

277-
move |br: ty::BoundRegion| {
278-
// The first time this closure is called, create a
279-
// new universe for the placeholders we will make
280-
// from here out.
281-
let universe = lazy_universe.unwrap_or_else(|| {
282-
let universe = nll_delegate.create_next_universe();
283-
lazy_universe = Some(universe);
284-
universe
285-
});
286-
287-
let placeholder = ty::PlaceholderRegion { universe, bound: br };
288-
debug!(?placeholder);
289-
let placeholder_reg = nll_delegate.next_placeholder_region(placeholder);
290-
debug!(?placeholder_reg);
291-
292-
placeholder_reg
293-
}
294-
};
298+
let delegate = FnMutDelegate {
299+
regions: &mut next_region,
300+
types: &mut |_bound_ty: ty::BoundTy| {
301+
unreachable!("we only replace regions in nll_relate, not types")
302+
},
303+
consts: &mut |_bound_var: ty::BoundVar, _ty| {
304+
unreachable!("we only replace regions in nll_relate, not consts")
305+
},
306+
};
295307

296-
let delegate = FnMutDelegate {
297-
regions: &mut next_region,
298-
types: &mut |_bound_ty: ty::BoundTy| {
299-
unreachable!("we only replace regions in nll_relate, not types")
300-
},
301-
consts: &mut |_bound_var: ty::BoundVar, _ty| {
302-
unreachable!("we only replace regions in nll_relate, not consts")
303-
},
308+
self.infcx.tcx.replace_bound_vars_uncached(binder, delegate)
304309
};
305310

306-
let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate);
307-
debug!(?replaced);
308-
309-
replaced
311+
debug!(?value);
312+
f(self, value)
310313
}
311314

312315
#[instrument(skip(self), level = "debug")]
@@ -630,10 +633,10 @@ where
630633

631634
// Note: the order here is important. Create the placeholders first, otherwise
632635
// we assign the wrong universe to the existential!
633-
let b_replaced = self.instantiate_binder_with_placeholders(b);
634-
let a_replaced = self.instantiate_binder_with_existentials(a);
635-
636-
self.relate(a_replaced, b_replaced)?;
636+
self.enter_forall(b, |this, b| {
637+
let a = this.instantiate_binder_with_existentials(a);
638+
this.relate(a, b)
639+
})?;
637640

638641
self.ambient_variance = variance;
639642
}
@@ -650,10 +653,10 @@ where
650653
let variance =
651654
std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
652655

653-
let a_replaced = self.instantiate_binder_with_placeholders(a);
654-
let b_replaced = self.instantiate_binder_with_existentials(b);
655-
656-
self.relate(a_replaced, b_replaced)?;
656+
self.enter_forall(a, |this, a| {
657+
let b = this.instantiate_binder_with_existentials(b);
658+
this.relate(a, b)
659+
})?;
657660

658661
self.ambient_variance = variance;
659662
}

0 commit comments

Comments
 (0)