Skip to content

Commit c12e623

Browse files
committed
canonicalize everything in nested goals
1 parent 55a7f9f commit c12e623

File tree

7 files changed

+254
-135
lines changed

7 files changed

+254
-135
lines changed

compiler/rustc_middle/src/traits/solve.rs

-6
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,3 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
229229
self.opaque_types.visit_with(visitor)
230230
}
231231
}
232-
233-
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
234-
pub enum IsNormalizesToHack {
235-
Yes,
236-
No,
237-
}

compiler/rustc_middle/src/traits/solve/inspect.rs

+32-13
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,73 @@
1-
use super::{
2-
CanonicalInput, Certainty, Goal, IsNormalizesToHack, NoSolution, QueryInput, QueryResult,
3-
};
1+
use super::{CanonicalInput, Certainty, Goal, NoSolution, QueryResult};
2+
use crate::infer::canonical::{Canonical, CanonicalVarValues};
43
use crate::ty;
54
use format::ProofTreeFormatter;
65
use std::fmt::{Debug, Write};
76

87
mod format;
98

9+
#[derive(Debug, Clone, Eq, PartialEq, Hash, HashStable, TypeFoldable, TypeVisitable)]
10+
pub struct State<'tcx, T> {
11+
pub var_values: CanonicalVarValues<'tcx>,
12+
pub data: T,
13+
}
14+
pub type CanonicalState<'tcx, T> = Canonical<'tcx, State<'tcx, T>>;
15+
1016
#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
1117
pub enum CacheHit {
1218
Provisional,
1319
Global,
1420
}
1521

22+
#[derive(Debug, PartialEq, Eq, Hash, HashStable)]
23+
pub enum IsNormalizesToHack {
24+
Yes,
25+
No,
26+
}
27+
1628
#[derive(Eq, PartialEq, Hash, HashStable)]
17-
pub struct GoalEvaluation<'tcx> {
18-
pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
19-
pub is_normalizes_to_hack: IsNormalizesToHack,
29+
pub struct RootGoalEvaluation<'tcx> {
30+
pub goal: Goal<'tcx, ty::Predicate<'tcx>>,
31+
pub orig_values: Vec<ty::GenericArg<'tcx>>,
2032
pub evaluation: CanonicalGoalEvaluation<'tcx>,
2133
pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
2234
}
2335

36+
#[derive(Eq, PartialEq, Hash, HashStable)]
37+
pub struct NestedGoalEvaluation<'tcx> {
38+
pub goal: CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>,
39+
pub orig_values: CanonicalState<'tcx, Vec<ty::GenericArg<'tcx>>>,
40+
pub is_normalizes_to_hack: IsNormalizesToHack,
41+
pub evaluation: CanonicalGoalEvaluation<'tcx>,
42+
pub returned_goals: Vec<CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>>,
43+
}
44+
2445
#[derive(Eq, PartialEq, Hash, HashStable)]
2546
pub struct CanonicalGoalEvaluation<'tcx> {
2647
pub goal: CanonicalInput<'tcx>,
27-
pub kind: GoalEvaluationKind<'tcx>,
48+
pub data: GoalEvaluationData<'tcx>,
2849
pub result: QueryResult<'tcx>,
2950
}
3051

3152
#[derive(Eq, PartialEq, Hash, HashStable)]
32-
pub enum GoalEvaluationKind<'tcx> {
53+
pub enum GoalEvaluationData<'tcx> {
3354
CacheHit(CacheHit),
3455
Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> },
3556
}
36-
impl Debug for GoalEvaluation<'_> {
57+
impl Debug for RootGoalEvaluation<'_> {
3758
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38-
ProofTreeFormatter::new(f).format_goal_evaluation(self)
59+
ProofTreeFormatter::new(f).format_root_goal_evaluation(self)
3960
}
4061
}
4162

4263
#[derive(Eq, PartialEq, Hash, HashStable)]
4364
pub struct AddedGoalsEvaluation<'tcx> {
44-
pub evaluations: Vec<Vec<GoalEvaluation<'tcx>>>,
65+
pub evaluations: Vec<Vec<NestedGoalEvaluation<'tcx>>>,
4566
pub result: Result<Certainty, NoSolution>,
4667
}
4768

4869
#[derive(Eq, PartialEq, Hash, HashStable)]
4970
pub struct GoalEvaluationStep<'tcx> {
50-
pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
51-
5271
pub added_goals_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
5372
pub candidates: Vec<GoalCandidate<'tcx>>,
5473

compiler/rustc_middle/src/traits/solve/inspect/format.rs

+33-11
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,36 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
3939
func(&mut ProofTreeFormatter { f: &mut Indentor { f: self.f, on_newline: true } })
4040
}
4141

42-
pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<'_>) -> std::fmt::Result {
42+
pub(super) fn format_root_goal_evaluation(
43+
&mut self,
44+
eval: &RootGoalEvaluation<'_>,
45+
) -> std::fmt::Result {
46+
writeln!(self.f, "ROOT GOAL: {:?}", eval.goal)?;
47+
self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation))?;
48+
if eval.returned_goals.len() > 0 {
49+
writeln!(self.f, "NESTED GOALS ADDED TO CALLER: [")?;
50+
self.nested(|this| {
51+
for goal in eval.returned_goals.iter() {
52+
writeln!(this.f, "ADDED GOAL: {goal:?},")?;
53+
}
54+
Ok(())
55+
})?;
56+
57+
writeln!(self.f, "]")
58+
} else {
59+
Ok(())
60+
}
61+
}
62+
63+
pub(super) fn format_nested_goal_evaluation(
64+
&mut self,
65+
eval: &NestedGoalEvaluation<'_>,
66+
) -> std::fmt::Result {
4367
let goal_text = match eval.is_normalizes_to_hack {
4468
IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL",
45-
IsNormalizesToHack::No => "GOAL",
69+
IsNormalizesToHack::No => "NESTED GOAL",
4670
};
47-
writeln!(self.f, "{}: {:?}", goal_text, eval.uncanonicalized_goal)?;
71+
writeln!(self.f, "{}: {:?}", goal_text, eval.goal)?;
4872
self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation))?;
4973
if eval.returned_goals.len() > 0 {
5074
writeln!(self.f, "NESTED GOALS ADDED TO CALLER: [")?;
@@ -67,17 +91,17 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
6791
) -> std::fmt::Result {
6892
writeln!(self.f, "GOAL: {:?}", eval.goal)?;
6993

70-
match &eval.kind {
71-
GoalEvaluationKind::CacheHit(CacheHit::Global) => {
94+
match &eval.data {
95+
GoalEvaluationData::CacheHit(CacheHit::Global) => {
7296
writeln!(self.f, "GLOBAL CACHE HIT: {:?}", eval.result)
7397
}
74-
GoalEvaluationKind::CacheHit(CacheHit::Provisional) => {
98+
GoalEvaluationData::CacheHit(CacheHit::Provisional) => {
7599
writeln!(self.f, "PROVISIONAL CACHE HIT: {:?}", eval.result)
76100
}
77-
GoalEvaluationKind::Uncached { revisions } => {
101+
GoalEvaluationData::Uncached { revisions } => {
78102
for (n, step) in revisions.iter().enumerate() {
79103
writeln!(self.f, "REVISION {n}: {:?}", step.result)?;
80-
self.nested(|this| this.format_evaluation_step(step))?;
104+
self.format_evaluation_step(step)?;
81105
}
82106
writeln!(self.f, "RESULT: {:?}", eval.result)
83107
}
@@ -88,8 +112,6 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
88112
&mut self,
89113
evaluation_step: &GoalEvaluationStep<'_>,
90114
) -> std::fmt::Result {
91-
writeln!(self.f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?;
92-
93115
for candidate in &evaluation_step.candidates {
94116
self.nested(|this| this.format_candidate(candidate))?;
95117
}
@@ -137,7 +159,7 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
137159
writeln!(self.f, "ITERATION {n}")?;
138160
self.nested(|this| {
139161
for goal_evaluation in iterations {
140-
this.format_goal_evaluation(goal_evaluation)?;
162+
this.format_nested_goal_evaluation(goal_evaluation)?;
141163
}
142164
Ok(())
143165
})?;

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

+19-18
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use rustc_middle::infer::canonical::CanonicalVarInfos;
1212
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
1313
use rustc_middle::traits::solve::inspect;
1414
use rustc_middle::traits::solve::{
15-
CanonicalInput, CanonicalResponse, Certainty, IsNormalizesToHack, PredefinedOpaques,
16-
PredefinedOpaquesData, QueryResult,
15+
CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaques, PredefinedOpaquesData,
16+
QueryResult,
1717
};
1818
use rustc_middle::traits::{specialization_graph, DefiningAnchor};
1919
use rustc_middle::ty::{
@@ -28,8 +28,8 @@ use std::ops::ControlFlow;
2828
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
2929

3030
use super::inspect::ProofTreeBuilder;
31-
use super::search_graph;
3231
use super::SolverMode;
32+
use super::{search_graph, GoalEvaluationKind};
3333
use super::{search_graph::SearchGraph, Goal};
3434
pub use select::InferCtxtSelectExt;
3535

@@ -85,7 +85,7 @@ pub struct EvalCtxt<'a, 'tcx> {
8585
// evaluation code.
8686
tainted: Result<(), NoSolution>,
8787

88-
inspect: ProofTreeBuilder<'tcx>,
88+
pub(super) inspect: ProofTreeBuilder<'tcx>,
8989
}
9090

9191
#[derive(Debug, Clone)]
@@ -149,7 +149,7 @@ pub trait InferCtxtEvalExt<'tcx> {
149149
generate_proof_tree: GenerateProofTree,
150150
) -> (
151151
Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>,
152-
Option<inspect::GoalEvaluation<'tcx>>,
152+
Option<inspect::RootGoalEvaluation<'tcx>>,
153153
);
154154
}
155155

@@ -161,10 +161,10 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
161161
generate_proof_tree: GenerateProofTree,
162162
) -> (
163163
Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>,
164-
Option<inspect::GoalEvaluation<'tcx>>,
164+
Option<inspect::RootGoalEvaluation<'tcx>>,
165165
) {
166166
EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
167-
ecx.evaluate_goal(IsNormalizesToHack::No, goal)
167+
ecx.evaluate_goal(GoalEvaluationKind::Root, goal)
168168
})
169169
}
170170
}
@@ -185,7 +185,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
185185
infcx: &InferCtxt<'tcx>,
186186
generate_proof_tree: GenerateProofTree,
187187
f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R,
188-
) -> (R, Option<inspect::GoalEvaluation<'tcx>>) {
188+
) -> (R, Option<inspect::RootGoalEvaluation<'tcx>>) {
189189
let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
190190
let mut search_graph = search_graph::SearchGraph::new(infcx.tcx, mode);
191191

@@ -260,7 +260,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
260260
search_graph,
261261
nested_goals: NestedGoals::new(),
262262
tainted: Ok(()),
263-
inspect: canonical_goal_evaluation.new_goal_evaluation_step(input),
263+
inspect: canonical_goal_evaluation.new_goal_evaluation_step(),
264264
};
265265

266266
for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
@@ -340,11 +340,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
340340
/// been constrained and the certainty of the result.
341341
fn evaluate_goal(
342342
&mut self,
343-
is_normalizes_to_hack: IsNormalizesToHack,
343+
goal_evaluation_kind: GoalEvaluationKind,
344344
goal: Goal<'tcx, ty::Predicate<'tcx>>,
345345
) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
346346
let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
347-
let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, is_normalizes_to_hack);
347+
348+
let mut goal_evaluation =
349+
ProofTreeBuilder::new_goal_evaluation(self, goal, &orig_values, goal_evaluation_kind);
348350
let encountered_overflow = self.search_graph.encountered_overflow();
349351
let canonical_response = EvalCtxt::evaluate_canonical_goal(
350352
self.tcx(),
@@ -354,7 +356,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
354356
);
355357
let canonical_response = match canonical_response {
356358
Err(e) => {
357-
self.inspect.goal_evaluation(goal_evaluation);
359+
ProofTreeBuilder::goal_evaluation(self, goal_evaluation, &[]);
358360
return Err(e);
359361
}
360362
Ok(response) => response,
@@ -368,13 +370,12 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
368370
canonical_response,
369371
) {
370372
Err(e) => {
371-
self.inspect.goal_evaluation(goal_evaluation);
373+
ProofTreeBuilder::goal_evaluation(self, goal_evaluation, &[]);
372374
return Err(e);
373375
}
374376
Ok(response) => response,
375377
};
376-
goal_evaluation.returned_goals(&nested_goals);
377-
self.inspect.goal_evaluation(goal_evaluation);
378+
ProofTreeBuilder::goal_evaluation(self, goal_evaluation, &nested_goals);
378379

379380
if !has_changed && !nested_goals.is_empty() {
380381
bug!("an unchanged goal shouldn't have any side-effects on instantiation");
@@ -389,7 +390,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
389390
// solver cycle.
390391
if cfg!(debug_assertions)
391392
&& has_changed
392-
&& is_normalizes_to_hack == IsNormalizesToHack::No
393+
&& goal_evaluation_kind != GoalEvaluationKind::NormalizesToHack
393394
&& !self.search_graph.in_cycle()
394395
{
395396
// The nested evaluation has to happen with the original state
@@ -562,7 +563,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
562563
);
563564

564565
let (_, certainty, instantiate_goals) =
565-
self.evaluate_goal(IsNormalizesToHack::Yes, unconstrained_goal)?;
566+
self.evaluate_goal(GoalEvaluationKind::NormalizesToHack, unconstrained_goal)?;
566567
self.add_goals(instantiate_goals);
567568

568569
// Finally, equate the goal's RHS with the unconstrained var.
@@ -597,7 +598,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
597598

598599
for goal in goals.goals.drain(..) {
599600
let (has_changed, certainty, instantiate_goals) =
600-
self.evaluate_goal(IsNormalizesToHack::No, goal)?;
601+
self.evaluate_goal(GoalEvaluationKind::Nested, goal)?;
601602
self.add_goals(instantiate_goals);
602603
if has_changed {
603604
unchanged_certainty = None;

compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs

+17
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//! [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
1111
use super::{CanonicalInput, Certainty, EvalCtxt, Goal};
1212
use crate::solve::canonicalize::{CanonicalizeMode, Canonicalizer};
13+
use crate::solve::inspect;
1314
use crate::solve::{response_no_constraints_raw, CanonicalResponse, QueryResult, Response};
1415
use rustc_data_structures::fx::FxHashSet;
1516
use rustc_index::IndexVec;
@@ -331,6 +332,22 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
331332
}
332333
}
333334

335+
impl<'tcx> inspect::ProofTreeBuilder<'tcx> {
336+
pub fn make_canonical_state<T: TypeFoldable<TyCtxt<'tcx>>>(
337+
ecx: &EvalCtxt<'_, 'tcx>,
338+
data: T,
339+
) -> inspect::CanonicalState<'tcx, T> {
340+
let state = inspect::State { var_values: ecx.var_values, data };
341+
let state = state.fold_with(&mut EagerResolver { infcx: ecx.infcx });
342+
Canonicalizer::canonicalize(
343+
ecx.infcx,
344+
CanonicalizeMode::Response { max_input_universe: ecx.max_input_universe },
345+
&mut vec![],
346+
state,
347+
)
348+
}
349+
}
350+
334351
/// Resolves ty, region, and const vars to their inferred values or their root vars.
335352
struct EagerResolver<'a, 'tcx> {
336353
infcx: &'a InferCtxt<'tcx>,

0 commit comments

Comments
 (0)