Skip to content

Commit 516814c

Browse files
committedMar 18, 2025
Implement support for binders with clauses in new solver
1 parent 2c6b416 commit 516814c

File tree

11 files changed

+210
-6
lines changed

11 files changed

+210
-6
lines changed
 

‎compiler/rustc_infer/src/infer/context.rs

+20
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,17 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
113113
)
114114
}
115115

116+
fn instantiate_binder_with_infer_and_goals<T: TypeFoldable<TyCtxt<'tcx>> + Copy>(
117+
&self,
118+
value: ty::Binder<'tcx, T>,
119+
) -> (T, ty::Clauses<'tcx>) {
120+
self.instantiate_binder_with_fresh_vars_and_goals(
121+
DUMMY_SP,
122+
BoundRegionConversionTime::HigherRankedType,
123+
value,
124+
)
125+
}
126+
116127
fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>>, U>(
117128
&self,
118129
value: ty::Binder<'tcx, T>,
@@ -121,6 +132,15 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
121132
self.enter_forall(value, f)
122133
}
123134

135+
fn enter_forall_with_assumptions<T: TypeFoldable<TyCtxt<'tcx>>, U>(
136+
&self,
137+
value: ty::Binder<'tcx, T>,
138+
param_env: ty::ParamEnv<'tcx>,
139+
f: impl FnOnce(T, ty::ParamEnv<'tcx>) -> U,
140+
) -> U {
141+
self.enter_forall_with_assumptions(value, param_env, f)
142+
}
143+
124144
fn equate_ty_vids_raw(&self, a: rustc_type_ir::TyVid, b: rustc_type_ir::TyVid) {
125145
self.inner.borrow_mut().type_variables().equate(a, b);
126146
}

‎compiler/rustc_infer/src/infer/mod.rs

+46
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,52 @@ impl<'tcx> InferCtxt<'tcx> {
12091209
self.tcx.replace_bound_vars_uncached(value, delegate)
12101210
}
12111211

1212+
pub fn instantiate_binder_with_fresh_vars_and_goals<T>(
1213+
&self,
1214+
span: Span,
1215+
lbrct: BoundRegionConversionTime,
1216+
binder: ty::Binder<'tcx, T>,
1217+
) -> (T, ty::Clauses<'tcx>)
1218+
where
1219+
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
1220+
{
1221+
if !binder.as_ref().skip_binder_with_clauses().has_escaping_bound_vars() {
1222+
return binder.skip_binder_with_clauses();
1223+
}
1224+
1225+
let bound_vars = binder.bound_vars();
1226+
let mut args = Vec::with_capacity(bound_vars.len());
1227+
1228+
for bound_var_kind in bound_vars {
1229+
let arg: ty::GenericArg<'_> = match bound_var_kind {
1230+
ty::BoundVariableKind::Ty(_) => self.next_ty_var(span).into(),
1231+
ty::BoundVariableKind::Region(br) => {
1232+
self.next_region_var(BoundRegion(span, br, lbrct)).into()
1233+
}
1234+
ty::BoundVariableKind::Const => self.next_const_var(span).into(),
1235+
};
1236+
args.push(arg);
1237+
}
1238+
1239+
struct ToFreshVars<'tcx> {
1240+
args: Vec<ty::GenericArg<'tcx>>,
1241+
}
1242+
1243+
impl<'tcx> BoundVarReplacerDelegate<'tcx> for ToFreshVars<'tcx> {
1244+
fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx> {
1245+
self.args[br.var.index()].expect_region()
1246+
}
1247+
fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> {
1248+
self.args[bt.var.index()].expect_ty()
1249+
}
1250+
fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> {
1251+
self.args[bv.index()].expect_const()
1252+
}
1253+
}
1254+
let delegate = ToFreshVars { args };
1255+
self.tcx.replace_bound_vars_uncached_with_clauses(binder, delegate)
1256+
}
1257+
12121258
/// See the [`region_constraints::RegionConstraintCollector::verify_generic_bound`] method.
12131259
pub(crate) fn verify_generic_bound(
12141260
&self,

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

+63
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,49 @@ impl<'tcx> InferCtxt<'tcx> {
5757
self.tcx.replace_bound_vars_uncached(binder, delegate)
5858
}
5959

60+
pub fn enter_forall_with_assumptions_and_leak_universe<T>(
61+
&self,
62+
binder: ty::Binder<'tcx, T>,
63+
param_env: ty::ParamEnv<'tcx>,
64+
) -> (T, ty::ParamEnv<'tcx>)
65+
where
66+
T: TypeFoldable<TyCtxt<'tcx>>,
67+
{
68+
if !binder.as_ref().skip_binder_with_clauses().has_escaping_bound_vars() {
69+
let (value, assumptions) = binder.skip_binder_with_clauses();
70+
return (value, param_env.extend(self.tcx, assumptions));
71+
}
72+
73+
let next_universe = self.create_next_universe();
74+
75+
// TODO: Deduplicate this with above.
76+
let delegate = FnMutDelegate {
77+
regions: &mut |br: ty::BoundRegion| {
78+
ty::Region::new_placeholder(
79+
self.tcx,
80+
ty::PlaceholderRegion { universe: next_universe, bound: br },
81+
)
82+
},
83+
types: &mut |bound_ty: ty::BoundTy| {
84+
Ty::new_placeholder(
85+
self.tcx,
86+
ty::PlaceholderType { universe: next_universe, bound: bound_ty },
87+
)
88+
},
89+
consts: &mut |bound_var: ty::BoundVar| {
90+
ty::Const::new_placeholder(
91+
self.tcx,
92+
ty::PlaceholderConst { universe: next_universe, bound: bound_var },
93+
)
94+
},
95+
};
96+
97+
debug!(?next_universe);
98+
let (value, assumptions) =
99+
self.tcx.replace_bound_vars_uncached_with_clauses(binder, delegate);
100+
(value, param_env.extend(self.tcx, assumptions))
101+
}
102+
60103
/// Replaces all bound variables (lifetimes, types, and constants) bound by
61104
/// `binder` with placeholder variables in a new universe and then calls the
62105
/// closure `f` with the instantiated value. The new placeholders can only be
@@ -82,6 +125,26 @@ impl<'tcx> InferCtxt<'tcx> {
82125
f(value)
83126
}
84127

128+
#[instrument(level = "debug", skip(self, f))]
129+
pub fn enter_forall_with_assumptions<T, U>(
130+
&self,
131+
forall: ty::Binder<'tcx, T>,
132+
param_env: ty::ParamEnv<'tcx>,
133+
f: impl FnOnce(T, ty::ParamEnv<'tcx>) -> U,
134+
) -> U
135+
where
136+
T: TypeFoldable<TyCtxt<'tcx>>,
137+
{
138+
// FIXME: currently we do nothing to prevent placeholders with the new universe being
139+
// used after exiting `f`. For example region subtyping can result in outlives constraints
140+
// that name placeholders created in this function. Nested goals from type relations can
141+
// also contain placeholders created by this function.
142+
let (value, param_env) =
143+
self.enter_forall_with_assumptions_and_leak_universe(forall, param_env);
144+
debug!(?value);
145+
f(value, param_env)
146+
}
147+
85148
/// See [RegionConstraintCollector::leak_check][1]. We only check placeholder
86149
/// leaking into `outer_universe`, i.e. placeholders which cannot be named by that
87150
/// universe.

‎compiler/rustc_middle/src/ty/fold.rs

+8
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,14 @@ impl<'tcx> TyCtxt<'tcx> {
258258
self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate)
259259
}
260260

261+
pub fn replace_bound_vars_uncached_with_clauses<T: TypeFoldable<TyCtxt<'tcx>>>(
262+
self,
263+
value: Binder<'tcx, T>,
264+
delegate: impl BoundVarReplacerDelegate<'tcx>,
265+
) -> (T, ty::Clauses<'tcx>) {
266+
self.replace_escaping_bound_vars_uncached(value.skip_binder_with_clauses(), delegate)
267+
}
268+
261269
/// Replaces any late-bound regions bound in `value` with
262270
/// free variants attached to `all_outlive_scope`.
263271
pub fn liberate_late_bound_regions<T>(

‎compiler/rustc_middle/src/ty/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,20 @@ impl<'tcx> ParamEnv<'tcx> {
999999
pub fn and<T: TypeVisitable<TyCtxt<'tcx>>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
10001000
ParamEnvAnd { param_env: self, value }
10011001
}
1002+
1003+
/// TODO:
1004+
pub fn extend(self, tcx: TyCtxt<'tcx>, assumptions: ty::Clauses<'tcx>) -> Self {
1005+
if assumptions.is_empty() {
1006+
self
1007+
} else if self.caller_bounds.is_empty() {
1008+
ParamEnv { caller_bounds: assumptions }
1009+
} else {
1010+
ParamEnv {
1011+
caller_bounds: tcx
1012+
.mk_clauses_from_iter(self.caller_bounds.iter().chain(assumptions)),
1013+
}
1014+
}
1015+
}
10021016
}
10031017

10041018
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]

‎compiler/rustc_next_trait_solver/src/solve/effect_goals.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,18 @@ where
5555
}
5656

5757
ecx.probe_trait_candidate(source).enter(|ecx| {
58-
let assumption_trait_pred = ecx.instantiate_binder_with_infer(host_clause);
58+
let (assumption_trait_pred, goals) =
59+
ecx.instantiate_binder_with_infer_and_goals(host_clause);
5960
ecx.eq(
6061
goal.param_env,
6162
goal.predicate.trait_ref,
6263
assumption_trait_pred.trait_ref,
6364
)?;
65+
let cx = ecx.cx();
66+
ecx.add_goals(
67+
GoalSource::Misc,
68+
goals.iter().map(|clause| goal.with(cx, clause)),
69+
);
6470
then(ecx)
6571
})
6672
} else {

‎compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs

+21-2
Original file line numberDiff line numberDiff line change
@@ -582,8 +582,8 @@ where
582582
}
583583
}
584584
} else {
585-
self.enter_forall(kind, |ecx, kind| {
586-
let goal = goal.with(ecx.cx(), ty::Binder::dummy(kind));
585+
self.enter_forall_with_assumptions(kind, goal.param_env, |ecx, kind, param_env| {
586+
let goal = Goal::new(ecx.cx(), param_env, ty::Binder::dummy(kind));
587587
ecx.add_goal(GoalSource::InstantiateHigherRanked, goal);
588588
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
589589
})
@@ -1005,6 +1005,13 @@ where
10051005
self.delegate.instantiate_binder_with_infer(value)
10061006
}
10071007

1008+
pub(super) fn instantiate_binder_with_infer_and_goals<T: TypeFoldable<I> + Copy>(
1009+
&self,
1010+
value: ty::Binder<I, T>,
1011+
) -> (T, I::Clauses) {
1012+
self.delegate.instantiate_binder_with_infer_and_goals(value)
1013+
}
1014+
10081015
/// `enter_forall`, but takes `&mut self` and passes it back through the
10091016
/// callback since it can't be aliased during the call.
10101017
pub(super) fn enter_forall<T: TypeFoldable<I>, U>(
@@ -1015,6 +1022,18 @@ where
10151022
self.delegate.enter_forall(value, |value| f(self, value))
10161023
}
10171024

1025+
/// UwU
1026+
pub(super) fn enter_forall_with_assumptions<T: TypeFoldable<I>, U>(
1027+
&mut self,
1028+
value: ty::Binder<I, T>,
1029+
param_env: I::ParamEnv,
1030+
f: impl FnOnce(&mut Self, T, I::ParamEnv) -> U,
1031+
) -> U {
1032+
self.delegate.enter_forall_with_assumptions(value, param_env, |value, param_env| {
1033+
f(self, value, param_env)
1034+
})
1035+
}
1036+
10181037
pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
10191038
where
10201039
T: TypeFoldable<I>,

‎compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,17 @@ where
121121
return Err(NoSolution);
122122
}
123123
ecx.probe_trait_candidate(source).enter(|ecx| {
124-
let assumption_projection_pred =
125-
ecx.instantiate_binder_with_infer(projection_pred);
124+
let (assumption_projection_pred, goals) =
125+
ecx.instantiate_binder_with_infer_and_goals(projection_pred);
126126
ecx.eq(
127127
goal.param_env,
128128
goal.predicate.alias,
129129
assumption_projection_pred.projection_term,
130130
)?;
131+
ecx.add_goals(
132+
GoalSource::Misc,
133+
goals.iter().map(|clause| goal.with(cx, clause)),
134+
);
131135

132136
ecx.instantiate_normalizes_to_term(goal, assumption_projection_pred.term);
133137

‎compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,18 @@ where
143143
}
144144

145145
ecx.probe_trait_candidate(source).enter(|ecx| {
146-
let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
146+
let (assumption_trait_pred, goals) =
147+
ecx.instantiate_binder_with_infer_and_goals(trait_clause);
147148
ecx.eq(
148149
goal.param_env,
149150
goal.predicate.trait_ref,
150151
assumption_trait_pred.trait_ref,
151152
)?;
153+
let cx = ecx.cx();
154+
ecx.add_goals(
155+
GoalSource::Misc,
156+
goals.iter().map(|clause| goal.with(cx, clause)),
157+
);
152158
then(ecx)
153159
})
154160
} else {

‎compiler/rustc_type_ir/src/infer_ctxt.rs

+12
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,24 @@ pub trait InferCtxtLike: Sized {
154154
value: ty::Binder<Self::Interner, T>,
155155
) -> T;
156156

157+
fn instantiate_binder_with_infer_and_goals<T: TypeFoldable<Self::Interner> + Copy>(
158+
&self,
159+
value: ty::Binder<Self::Interner, T>,
160+
) -> (T, <Self::Interner as Interner>::Clauses);
161+
157162
fn enter_forall<T: TypeFoldable<Self::Interner>, U>(
158163
&self,
159164
value: ty::Binder<Self::Interner, T>,
160165
f: impl FnOnce(T) -> U,
161166
) -> U;
162167

168+
fn enter_forall_with_assumptions<T: TypeFoldable<Self::Interner>, U>(
169+
&self,
170+
value: ty::Binder<Self::Interner, T>,
171+
param_env: <Self::Interner as Interner>::ParamEnv,
172+
f: impl FnOnce(T, <Self::Interner as Interner>::ParamEnv) -> U,
173+
) -> U;
174+
163175
fn equate_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid);
164176
fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid);
165177
fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid);

‎compiler/rustc_type_ir/src/visit.rs

+6
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@ pub trait TypeVisitor<I: Interner>: Sized {
132132
///////////////////////////////////////////////////////////////////////////
133133
// Traversal implementations.
134134

135+
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for &T {
136+
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
137+
(**self).visit_with(visitor)
138+
}
139+
}
140+
135141
impl<I: Interner, T: TypeVisitable<I>, U: TypeVisitable<I>> TypeVisitable<I> for (T, U) {
136142
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
137143
try_visit!(self.0.visit_with(visitor));

0 commit comments

Comments
 (0)