Skip to content

Commit ac559af

Browse files
committed
introduce enter_forall
1 parent af88f7d commit ac559af

File tree

15 files changed

+520
-442
lines changed

15 files changed

+520
-442
lines changed

compiler/rustc_infer/src/infer/mod.rs

+12-9
Original file line numberDiff line numberDiff line change
@@ -1032,21 +1032,24 @@ 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+
// FIXME(tree_universes): leaking universes
1036+
self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| {
1037+
Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b))
1038+
})
10391039
}
10401040

10411041
pub fn region_outlives_predicate(
10421042
&self,
10431043
cause: &traits::ObligationCause<'tcx>,
10441044
predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
10451045
) {
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`
1046+
// FIXME(tree_universes): leaking universes
1047+
self.enter_forall(predicate, |ty::OutlivesPredicate(r_a, r_b)| {
1048+
let origin = SubregionOrigin::from_obligation_cause(cause, || {
1049+
RelateRegionParamBound(cause.span)
1050+
});
1051+
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
1052+
})
10501053
}
10511054

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

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

+25-17
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,24 @@ 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+
// FIXME(tree_universes): leaked dead universes
53+
let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime);
54+
if result.is_ok() {
55+
debug!("OK result={result:?}");
56+
}
57+
result.map(|_| ())
58+
})
5959
}
6060
}
6161

@@ -106,6 +106,14 @@ impl<'tcx> InferCtxt<'tcx> {
106106
self.tcx.replace_bound_vars_uncached(binder, delegate)
107107
}
108108

109+
pub fn enter_forall<T, U>(&self, forall: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U) -> U
110+
where
111+
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
112+
{
113+
let value = self.instantiate_binder_with_placeholders(forall);
114+
f(value)
115+
}
116+
109117
/// See [RegionConstraintCollector::leak_check][1]. We only check placeholder
110118
/// leaking into `outer_universe`, i.e. placeholders which cannot be named by that
111119
/// universe.

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

+20-8
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,18 @@ where
309309
replaced
310310
}
311311

312+
fn enter_forall<T, U>(
313+
&mut self,
314+
binder: ty::Binder<'tcx, T>,
315+
f: impl FnOnce(&mut Self, T) -> U,
316+
) -> U
317+
where
318+
T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
319+
{
320+
let value = self.instantiate_binder_with_placeholders(binder);
321+
f(self, value)
322+
}
323+
312324
#[instrument(skip(self), level = "debug")]
313325
fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
314326
where
@@ -630,10 +642,10 @@ where
630642

631643
// Note: the order here is important. Create the placeholders first, otherwise
632644
// 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)?;
645+
self.enter_forall(b, |this, b| {
646+
let a = this.instantiate_binder_with_existentials(a);
647+
this.relate(a, b)
648+
})?;
637649

638650
self.ambient_variance = variance;
639651
}
@@ -650,10 +662,10 @@ where
650662
let variance =
651663
std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
652664

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)?;
665+
self.enter_forall(a, |this, a| {
666+
let b = this.instantiate_binder_with_existentials(b);
667+
this.relate(a, b)
668+
})?;
657669

658670
self.ambient_variance = variance;
659671
}

compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs

+92-89
Original file line numberDiff line numberDiff line change
@@ -77,101 +77,104 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
7777
for (pred, pred_span) in
7878
cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied()
7979
{
80-
let predicate = infcx.instantiate_binder_with_placeholders(pred.kind());
81-
let ty::ClauseKind::Projection(proj) = predicate else {
82-
continue;
83-
};
84-
// Only check types, since those are the only things that may
85-
// have opaques in them anyways.
86-
let Some(proj_term) = proj.term.ty() else { continue };
80+
infcx.enter_forall(pred.kind(), |predicate| {
81+
let ty::ClauseKind::Projection(proj) = predicate else {
82+
return;
83+
};
84+
// Only check types, since those are the only things that may
85+
// have opaques in them anyways.
86+
let Some(proj_term) = proj.term.ty() else { return };
8787

88-
// HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"...
89-
if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind()
90-
&& cx.tcx.parent(opaque_ty.def_id) == def_id
91-
&& matches!(
92-
opaque.origin,
93-
hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_)
94-
)
95-
{
96-
continue;
97-
}
88+
// HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"...
89+
if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind()
90+
&& cx.tcx.parent(opaque_ty.def_id) == def_id
91+
&& matches!(
92+
opaque.origin,
93+
hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_)
94+
)
95+
{
96+
return;
97+
}
9898

99-
// HACK: `async fn() -> Self` in traits is "ok"...
100-
// This is not really that great, but it's similar to why the `-> Self`
101-
// return type is well-formed in traits even when `Self` isn't sized.
102-
if let ty::Param(param_ty) = *proj_term.kind()
103-
&& param_ty.name == kw::SelfUpper
104-
&& matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(_))
105-
&& opaque.in_trait
106-
{
107-
continue;
108-
}
99+
// HACK: `async fn() -> Self` in traits is "ok"...
100+
// This is not really that great, but it's similar to why the `-> Self`
101+
// return type is well-formed in traits even when `Self` isn't sized.
102+
if let ty::Param(param_ty) = *proj_term.kind()
103+
&& param_ty.name == kw::SelfUpper
104+
&& matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(_))
105+
&& opaque.in_trait
106+
{
107+
return;
108+
}
109109

110-
let proj_ty =
111-
Ty::new_projection(cx.tcx, proj.projection_ty.def_id, proj.projection_ty.args);
112-
// For every instance of the projection type in the bounds,
113-
// replace them with the term we're assigning to the associated
114-
// type in our opaque type.
115-
let proj_replacer = &mut BottomUpFolder {
116-
tcx: cx.tcx,
117-
ty_op: |ty| if ty == proj_ty { proj_term } else { ty },
118-
lt_op: |lt| lt,
119-
ct_op: |ct| ct,
120-
};
121-
// For example, in `impl Trait<Assoc = impl Send>`, for all of the bounds on `Assoc`,
122-
// e.g. `type Assoc: OtherTrait`, replace `<impl Trait as Trait>::Assoc: OtherTrait`
123-
// with `impl Send: OtherTrait`.
124-
for (assoc_pred, assoc_pred_span) in cx
125-
.tcx
126-
.explicit_item_bounds(proj.projection_ty.def_id)
127-
.iter_instantiated_copied(cx.tcx, proj.projection_ty.args)
128-
{
129-
let assoc_pred = assoc_pred.fold_with(proj_replacer);
130-
let Ok(assoc_pred) = traits::fully_normalize(
131-
infcx,
132-
traits::ObligationCause::dummy(),
133-
cx.param_env,
134-
assoc_pred,
135-
) else {
136-
continue;
110+
let proj_ty =
111+
Ty::new_projection(cx.tcx, proj.projection_ty.def_id, proj.projection_ty.args);
112+
// For every instance of the projection type in the bounds,
113+
// replace them with the term we're assigning to the associated
114+
// type in our opaque type.
115+
let proj_replacer = &mut BottomUpFolder {
116+
tcx: cx.tcx,
117+
ty_op: |ty| if ty == proj_ty { proj_term } else { ty },
118+
lt_op: |lt| lt,
119+
ct_op: |ct| ct,
137120
};
138-
// If that predicate doesn't hold modulo regions (but passed during type-check),
139-
// then we must've taken advantage of the hack in `project_and_unify_types` where
140-
// we replace opaques with inference vars. Emit a warning!
141-
if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new(
142-
cx.tcx,
143-
traits::ObligationCause::dummy(),
144-
cx.param_env,
145-
assoc_pred,
146-
)) {
147-
// If it's a trait bound and an opaque that doesn't satisfy it,
148-
// then we can emit a suggestion to add the bound.
149-
let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) {
150-
(
151-
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }),
152-
ty::ClauseKind::Trait(trait_pred),
153-
) => Some(AddBound {
154-
suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(),
155-
trait_ref: trait_pred.print_modifiers_and_trait_path(),
156-
}),
157-
_ => None,
121+
// For example, in `impl Trait<Assoc = impl Send>`, for all of the bounds on `Assoc`,
122+
// e.g. `type Assoc: OtherTrait`, replace `<impl Trait as Trait>::Assoc: OtherTrait`
123+
// with `impl Send: OtherTrait`.
124+
for (assoc_pred, assoc_pred_span) in cx
125+
.tcx
126+
.explicit_item_bounds(proj.projection_ty.def_id)
127+
.iter_instantiated_copied(cx.tcx, proj.projection_ty.args)
128+
{
129+
let assoc_pred = assoc_pred.fold_with(proj_replacer);
130+
let Ok(assoc_pred) = traits::fully_normalize(
131+
infcx,
132+
traits::ObligationCause::dummy(),
133+
cx.param_env,
134+
assoc_pred,
135+
) else {
136+
continue;
158137
};
159-
cx.emit_span_lint(
160-
OPAQUE_HIDDEN_INFERRED_BOUND,
161-
pred_span,
162-
OpaqueHiddenInferredBoundLint {
163-
ty: Ty::new_opaque(
164-
cx.tcx,
165-
def_id,
166-
ty::GenericArgs::identity_for_item(cx.tcx, def_id),
167-
),
168-
proj_ty: proj_term,
169-
assoc_pred_span,
170-
add_bound,
171-
},
172-
);
138+
139+
// If that predicate doesn't hold modulo regions (but passed during type-check),
140+
// then we must've taken advantage of the hack in `project_and_unify_types` where
141+
// we replace opaques with inference vars. Emit a warning!
142+
if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new(
143+
cx.tcx,
144+
traits::ObligationCause::dummy(),
145+
cx.param_env,
146+
assoc_pred,
147+
)) {
148+
// If it's a trait bound and an opaque that doesn't satisfy it,
149+
// then we can emit a suggestion to add the bound.
150+
let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) {
151+
(
152+
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }),
153+
ty::ClauseKind::Trait(trait_pred),
154+
) => Some(AddBound {
155+
suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(),
156+
trait_ref: trait_pred.print_modifiers_and_trait_path(),
157+
}),
158+
_ => None,
159+
};
160+
161+
cx.emit_span_lint(
162+
OPAQUE_HIDDEN_INFERRED_BOUND,
163+
pred_span,
164+
OpaqueHiddenInferredBoundLint {
165+
ty: Ty::new_opaque(
166+
cx.tcx,
167+
def_id,
168+
ty::GenericArgs::identity_for_item(cx.tcx, def_id),
169+
),
170+
proj_ty: proj_term,
171+
assoc_pred_span,
172+
add_bound,
173+
},
174+
);
175+
}
173176
}
174-
}
177+
});
175178
}
176179
}
177180
}

compiler/rustc_middle/src/ty/sty.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,7 @@ impl<'tcx, T> Binder<'tcx, T> {
10521052
where
10531053
T: TypeVisitable<TyCtxt<'tcx>>,
10541054
{
1055+
// `self.value` is equivalent to `self.skip_binder()`
10551056
if self.value.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
10561057
}
10571058

0 commit comments

Comments
 (0)