Skip to content

Commit 01a0735

Browse files
committed
Diagnostics ICE when replaying proof trees with next-solver
When diagnostics replay proof tree state, rebuilding a canonical state can fail to match the current inference state. With -Znext-solver=globally, this could panic because inference variables created to replay a canonical state were placed in the wrong universe relative to placeholders bound by the same state. Fix this by threading a `prev_universe` through proof tree replay: `InspectGoal` now stores the caller-side universe at the time the goal was created, and `instantiate_canonical_state` reuses that same base universe (instead of recomputing it) when creating any replay-only fresh variables and when reconstructing placeholders from the canonical state, ensuring all canonical states for a single goal share a consistent universe mapping. Add a regression test for the higher-ranked PartialEq and PartialOrd case. Fixes #151304. Signed-off-by: Vicente Gusmão <vicente.gusmao@tecnico.ulisboa.pt>
1 parent c9ff496 commit 01a0735

6 files changed

Lines changed: 95 additions & 11 deletions

File tree

‎compiler/rustc_next_trait_solver/src/canonical/mod.rs‎

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,27 @@ where
165165
delegate.create_next_universe();
166166
}
167167

168+
compute_query_response_instantiation_values_in_universe(
169+
delegate,
170+
original_values,
171+
response,
172+
span,
173+
prev_universe,
174+
)
175+
}
176+
177+
fn compute_query_response_instantiation_values_in_universe<D, I, T>(
178+
delegate: &D,
179+
original_values: &[I::GenericArg],
180+
response: &Canonical<I, T>,
181+
span: I::Span,
182+
prev_universe: ty::UniverseIndex,
183+
) -> CanonicalVarValues<I>
184+
where
185+
D: SolverDelegate<Interner = I>,
186+
I: Interner,
187+
T: ResponseT<I>,
188+
{
168189
let var_values = response.value.var_values();
169190
assert_eq!(original_values.len(), var_values.len());
170191

@@ -542,6 +563,7 @@ pub fn instantiate_canonical_state<D, I, T>(
542563
delegate: &D,
543564
span: I::Span,
544565
param_env: I::ParamEnv,
566+
prev_universe: ty::UniverseIndex,
545567
orig_values: &mut ThinVec<I::GenericArg>,
546568
state: inspect::CanonicalState<I, T>,
547569
) -> T
@@ -552,14 +574,23 @@ where
552574
{
553575
// In case any fresh inference variables have been created between `state`
554576
// and the previous instantiation, extend `orig_values` for it.
577+
let max_universe = prev_universe + state.max_universe.index();
578+
while delegate.universe() < max_universe {
579+
delegate.create_next_universe();
580+
}
555581
orig_values.extend(
556582
state.value.var_values.var_values.as_slice()[orig_values.len()..]
557583
.iter()
558-
.map(|&arg| delegate.fresh_var_for_kind_with_span(arg, span)),
584+
.map(|&arg| delegate.fresh_var_for_kind(arg, span, max_universe)),
559585
);
560586

561-
let instantiation =
562-
compute_query_response_instantiation_values(delegate, orig_values, &state, span);
587+
let instantiation = compute_query_response_instantiation_values_in_universe(
588+
delegate,
589+
orig_values,
590+
&state,
591+
span,
592+
prev_universe,
593+
);
563594

564595
let inspect::State { var_values, data } = delegate.instantiate_canonical(state, instantiation);
565596

‎compiler/rustc_next_trait_solver/src/delegate.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
2626
span: <Self::Interner as Interner>::Span,
2727
) -> ComputeGoalFastPathOutcome<Self::Interner>;
2828

29-
fn fresh_var_for_kind_with_span(
29+
fn fresh_var_for_kind(
3030
&self,
3131
arg: <Self::Interner as Interner>::GenericArg,
3232
span: <Self::Interner as Interner>::Span,
33+
universe: ty::UniverseIndex,
3334
) -> <Self::Interner as Interner>::GenericArg;
3435

3536
// FIXME: Uplift the leak check into this crate.

‎compiler/rustc_trait_selection/src/solve/delegate.rs‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -285,17 +285,18 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
285285
}
286286
}
287287

288-
fn fresh_var_for_kind_with_span(
288+
fn fresh_var_for_kind(
289289
&self,
290290
arg: ty::GenericArg<'tcx>,
291291
span: Span,
292+
universe: ty::UniverseIndex,
292293
) -> ty::GenericArg<'tcx> {
293294
match arg.kind() {
294295
ty::GenericArgKind::Lifetime(_) => {
295-
self.next_region_var(RegionVariableOrigin::Misc(span)).into()
296+
self.next_region_var_in_universe(RegionVariableOrigin::Misc(span), universe).into()
296297
}
297-
ty::GenericArgKind::Type(_) => self.next_ty_var(span).into(),
298-
ty::GenericArgKind::Const(_) => self.next_const_var(span).into(),
298+
ty::GenericArgKind::Type(_) => self.next_ty_var_in_universe(span, universe).into(),
299+
ty::GenericArgKind::Const(_) => self.next_const_var_in_universe(span, universe).into(),
299300
}
300301
}
301302

‎compiler/rustc_trait_selection/src/solve/inspect/analyse.rs‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ pub struct InspectGoal<'a, 'tcx> {
3232
infcx: &'a SolverDelegate<'tcx>,
3333
depth: usize,
3434
orig_values: ThinVec<ty::GenericArg<'tcx>>,
35+
prev_universe: ty::UniverseIndex,
3536
goal: Goal<'tcx, ty::Predicate<'tcx>>,
3637
result: Result<Certainty, NoSolution>,
3738
final_revision: &'tcx inspect::Probe<TyCtxt<'tcx>>,
@@ -102,16 +103,29 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
102103
match **step {
103104
inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push((
104105
source,
105-
instantiate_canonical_state(infcx, span, param_env, &mut orig_values, goal),
106+
instantiate_canonical_state(
107+
infcx,
108+
span,
109+
param_env,
110+
self.goal.prev_universe,
111+
&mut orig_values,
112+
goal,
113+
),
106114
)),
107115
inspect::ProbeStep::RecordImplArgs { .. } => {}
108116
inspect::ProbeStep::MakeCanonicalResponse { .. }
109117
| inspect::ProbeStep::NestedProbe(_) => unreachable!(),
110118
}
111119
}
112120

113-
let () =
114-
instantiate_canonical_state(infcx, span, param_env, &mut orig_values, self.final_state);
121+
let () = instantiate_canonical_state(
122+
infcx,
123+
span,
124+
param_env,
125+
self.goal.prev_universe,
126+
&mut orig_values,
127+
self.final_state,
128+
);
115129

116130
instantiated_goals
117131
.into_iter()
@@ -139,6 +153,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
139153
infcx,
140154
span,
141155
param_env,
156+
self.goal.prev_universe,
142157
&mut orig_values,
143158
impl_args,
144159
);
@@ -147,6 +162,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
147162
infcx,
148163
span,
149164
param_env,
165+
self.goal.prev_universe,
150166
&mut orig_values,
151167
self.final_state,
152168
);
@@ -320,6 +336,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
320336
source: GoalSource,
321337
) -> Self {
322338
let infcx = <&SolverDelegate<'tcx>>::from(infcx);
339+
let prev_universe = infcx.universe();
323340

324341
let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, final_revision, result } =
325342
root;
@@ -331,6 +348,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
331348
infcx,
332349
depth,
333350
orig_values,
351+
prev_universe,
334352
goal: eager_resolve_vars(&**infcx, uncanonicalized_goal),
335353
result,
336354
final_revision,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@ compile-flags: -Znext-solver=globally
2+
3+
#![allow(incomplete_features)]
4+
#![feature(non_lifetime_binders)]
5+
6+
fn auto_trait()
7+
where
8+
for<T> T: PartialEq + PartialOrd,
9+
{}
10+
11+
fn main() {
12+
auto_trait();
13+
//~^ ERROR can't compare `T` with `T`
14+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0277]: can't compare `T` with `T`
2+
--> $DIR/foreach-partial-eq-next-solver.rs:12:5
3+
|
4+
LL | auto_trait();
5+
| ^^^^^^^^^^^^ no implementation for `T < T` and `T > T`
6+
|
7+
= help: the trait `PartialOrd` is not implemented for `T`
8+
note: required by a bound in `auto_trait`
9+
--> $DIR/foreach-partial-eq-next-solver.rs:8:27
10+
|
11+
LL | fn auto_trait()
12+
| ---------- required by a bound in this function
13+
LL | where
14+
LL | for<T> T: PartialEq + PartialOrd,
15+
| ^^^^^^^^^^ required by this bound in `auto_trait`
16+
17+
error: aborting due to 1 previous error
18+
19+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)