about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/traits/solve/inspect.rs15
-rw-r--r--compiler/rustc_middle/src/traits/solve/inspect/format.rs18
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect.rs81
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph/mod.rs11
5 files changed, 75 insertions, 56 deletions
diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs
index a2dfde2f0d4..d8b3a061b77 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect.rs
@@ -31,6 +31,7 @@ pub struct CanonicalGoalEvaluation<'tcx> {
 
 #[derive(Eq, PartialEq)]
 pub enum GoalEvaluationKind<'tcx> {
+    Overflow,
     CacheHit(CacheHit),
     Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> },
 }
@@ -50,10 +51,8 @@ pub struct AddedGoalsEvaluation<'tcx> {
 pub struct GoalEvaluationStep<'tcx> {
     pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
 
-    pub added_goals_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
-    pub candidates: Vec<GoalCandidate<'tcx>>,
-
-    pub result: QueryResult<'tcx>,
+    /// The actual evaluation of the goal, always `ProbeKind::Root`.
+    pub evaluation: GoalCandidate<'tcx>,
 }
 
 #[derive(Eq, PartialEq)]
@@ -63,8 +62,16 @@ pub struct GoalCandidate<'tcx> {
     pub kind: ProbeKind<'tcx>,
 }
 
+impl Debug for GoalCandidate<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        ProofTreeFormatter::new(f).format_candidate(self)
+    }
+}
+
 #[derive(Debug, PartialEq, Eq)]
 pub enum ProbeKind<'tcx> {
+    /// The root inference context while proving a goal.
+    Root { result: QueryResult<'tcx> },
     /// Probe entered when normalizing the self ty during candidate assembly
     NormalizedSelfTyAssembly,
     /// Some candidate to prove the current goal.
diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
index 7c077beeed6..d916e80a625 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
@@ -68,6 +68,9 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
         writeln!(self.f, "GOAL: {:?}", eval.goal)?;
 
         match &eval.kind {
+            GoalEvaluationKind::Overflow => {
+                writeln!(self.f, "OVERFLOW: {:?}", eval.result)
+            }
             GoalEvaluationKind::CacheHit(CacheHit::Global) => {
                 writeln!(self.f, "GLOBAL CACHE HIT: {:?}", eval.result)
             }
@@ -76,7 +79,7 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
             }
             GoalEvaluationKind::Uncached { revisions } => {
                 for (n, step) in revisions.iter().enumerate() {
-                    writeln!(self.f, "REVISION {n}: {:?}", step.result)?;
+                    writeln!(self.f, "REVISION {n}")?;
                     self.nested(|this| this.format_evaluation_step(step))?;
                 }
                 writeln!(self.f, "RESULT: {:?}", eval.result)
@@ -89,19 +92,14 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
         evaluation_step: &GoalEvaluationStep<'_>,
     ) -> std::fmt::Result {
         writeln!(self.f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?;
-
-        for candidate in &evaluation_step.candidates {
-            self.nested(|this| this.format_candidate(candidate))?;
-        }
-        for nested in &evaluation_step.added_goals_evaluations {
-            self.nested(|this| this.format_added_goals_evaluation(nested))?;
-        }
-
-        Ok(())
+        self.format_candidate(&evaluation_step.evaluation)
     }
 
     pub(super) fn format_candidate(&mut self, candidate: &GoalCandidate<'_>) -> std::fmt::Result {
         match &candidate.kind {
+            ProbeKind::Root { result } => {
+                writeln!(self.f, "ROOT RESULT: {result:?}")
+            }
             ProbeKind::NormalizedSelfTyAssembly => {
                 writeln!(self.f, "NORMALIZING SELF TY FOR ASSEMBLY:")
             }
diff --git a/compiler/rustc_trait_selection/src/solve/inspect.rs b/compiler/rustc_trait_selection/src/solve/inspect.rs
index f38edd8b9a0..46025da7683 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect.rs
@@ -29,27 +29,33 @@ impl<'tcx> WipGoalEvaluation<'tcx> {
 }
 
 #[derive(Eq, PartialEq, Debug)]
+pub enum WipGoalEvaluationKind {
+    Overflow,
+    CacheHit(CacheHit),
+}
+
+#[derive(Eq, PartialEq, Debug)]
 pub struct WipCanonicalGoalEvaluation<'tcx> {
     pub goal: CanonicalInput<'tcx>,
-    pub cache_hit: Option<CacheHit>,
-    pub evaluation_steps: Vec<WipGoalEvaluationStep<'tcx>>,
+    pub kind: Option<WipGoalEvaluationKind>,
+    pub revisions: Vec<WipGoalEvaluationStep<'tcx>>,
     pub result: Option<QueryResult<'tcx>>,
 }
 
 impl<'tcx> WipCanonicalGoalEvaluation<'tcx> {
     pub fn finalize(self) -> inspect::CanonicalGoalEvaluation<'tcx> {
-        let kind = match self.cache_hit {
-            Some(hit) => inspect::GoalEvaluationKind::CacheHit(hit),
-            None => {
-                assert!(!self.evaluation_steps.is_empty());
-                inspect::GoalEvaluationKind::Uncached {
-                    revisions: self
-                        .evaluation_steps
-                        .into_iter()
-                        .map(WipGoalEvaluationStep::finalize)
-                        .collect(),
-                }
+        let kind = match self.kind {
+            Some(WipGoalEvaluationKind::Overflow) => inspect::GoalEvaluationKind::Overflow,
+            Some(WipGoalEvaluationKind::CacheHit(hit)) => {
+                inspect::GoalEvaluationKind::CacheHit(hit)
             }
+            None => inspect::GoalEvaluationKind::Uncached {
+                revisions: self
+                    .revisions
+                    .into_iter()
+                    .map(WipGoalEvaluationStep::finalize)
+                    .collect(),
+            },
         };
 
         inspect::CanonicalGoalEvaluation { goal: self.goal, kind, result: self.result.unwrap() }
@@ -81,24 +87,17 @@ impl<'tcx> WipAddedGoalsEvaluation<'tcx> {
 pub struct WipGoalEvaluationStep<'tcx> {
     pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
 
-    pub added_goals_evaluations: Vec<WipAddedGoalsEvaluation<'tcx>>,
-    pub candidates: Vec<WipGoalCandidate<'tcx>>,
-
-    pub result: Option<QueryResult<'tcx>>,
+    pub evaluation: WipGoalCandidate<'tcx>,
 }
 
 impl<'tcx> WipGoalEvaluationStep<'tcx> {
     pub fn finalize(self) -> inspect::GoalEvaluationStep<'tcx> {
-        inspect::GoalEvaluationStep {
-            instantiated_goal: self.instantiated_goal,
-            added_goals_evaluations: self
-                .added_goals_evaluations
-                .into_iter()
-                .map(WipAddedGoalsEvaluation::finalize)
-                .collect(),
-            candidates: self.candidates.into_iter().map(WipGoalCandidate::finalize).collect(),
-            result: self.result.unwrap(),
+        let evaluation = self.evaluation.finalize();
+        match evaluation.kind {
+            ProbeKind::Root { .. } => (),
+            _ => unreachable!("unexpected root evaluation: {evaluation:?}"),
         }
+        inspect::GoalEvaluationStep { instantiated_goal: self.instantiated_goal, evaluation }
     }
 }
 
@@ -269,8 +268,8 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
     ) -> ProofTreeBuilder<'tcx> {
         self.nested(|| WipCanonicalGoalEvaluation {
             goal,
-            cache_hit: None,
-            evaluation_steps: vec![],
+            kind: None,
+            revisions: vec![],
             result: None,
         })
     }
@@ -287,11 +286,11 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         }
     }
 
-    pub fn cache_hit(&mut self, cache_hit: CacheHit) {
+    pub fn goal_evaluation_kind(&mut self, kind: WipGoalEvaluationKind) {
         if let Some(this) = self.as_mut() {
             match this {
                 DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => {
-                    assert_eq!(canonical_goal_evaluation.cache_hit.replace(cache_hit), None);
+                    assert_eq!(canonical_goal_evaluation.kind.replace(kind), None);
                 }
                 _ => unreachable!(),
             };
@@ -330,9 +329,11 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
     ) -> ProofTreeBuilder<'tcx> {
         self.nested(|| WipGoalEvaluationStep {
             instantiated_goal,
-            added_goals_evaluations: vec![],
-            candidates: vec![],
-            result: None,
+            evaluation: WipGoalCandidate {
+                added_goals_evaluations: vec![],
+                candidates: vec![],
+                kind: None,
+            },
         })
     }
     pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<'tcx>) {
@@ -342,7 +343,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
                     DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluations),
                     DebugSolver::GoalEvaluationStep(goal_evaluation_step),
                 ) => {
-                    canonical_goal_evaluations.evaluation_steps.push(goal_evaluation_step);
+                    canonical_goal_evaluations.revisions.push(goal_evaluation_step);
                 }
                 _ => unreachable!(),
             }
@@ -373,7 +374,10 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
             match (this, candidate.state.unwrap().tree) {
                 (
                     DebugSolver::GoalCandidate(WipGoalCandidate { candidates, .. })
-                    | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { candidates, .. }),
+                    | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep {
+                        evaluation: WipGoalCandidate { candidates, .. },
+                        ..
+                    }),
                     DebugSolver::GoalCandidate(candidate),
                 ) => candidates.push(candidate),
                 _ => unreachable!(),
@@ -412,7 +416,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
             match (this, added_goals_evaluation.state.unwrap().tree) {
                 (
                     DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep {
-                        added_goals_evaluations,
+                        evaluation: WipGoalCandidate { added_goals_evaluations, .. },
                         ..
                     })
                     | DebugSolver::GoalCandidate(WipGoalCandidate {
@@ -432,7 +436,10 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
                     assert_eq!(canonical_goal_evaluation.result.replace(result), None);
                 }
                 DebugSolver::GoalEvaluationStep(evaluation_step) => {
-                    assert_eq!(evaluation_step.result.replace(result), None);
+                    assert_eq!(
+                        evaluation_step.evaluation.kind.replace(ProbeKind::Root { result }),
+                        None
+                    );
                 }
                 _ => unreachable!(),
             }
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 75a99f799a2..c492408bc76 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -233,9 +233,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
 
     #[instrument(level = "debug", skip(self, goals))]
     fn add_goals(&mut self, goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>) {
-        let current_len = self.nested_goals.goals.len();
-        self.nested_goals.goals.extend(goals);
-        debug!("added_goals={:?}", &self.nested_goals.goals[current_len..]);
+        for goal in goals {
+            self.add_goal(goal);
+        }
     }
 
     /// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`.
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
index 60c348d892b..c816b51f67a 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
@@ -1,6 +1,7 @@
 mod cache;
 
 use self::cache::ProvisionalEntry;
+use super::inspect;
 use super::inspect::ProofTreeBuilder;
 use super::SolverMode;
 use cache::ProvisionalCache;
@@ -185,6 +186,8 @@ impl<'tcx> SearchGraph<'tcx> {
             if let Some(last) = self.stack.raw.last_mut() {
                 last.encountered_overflow = true;
             }
+
+            inspect.goal_evaluation_kind(inspect::WipGoalEvaluationKind::Overflow);
             return Self::response_no_constraints(tcx, input, Certainty::OVERFLOW);
         };
 
@@ -200,7 +203,9 @@ impl<'tcx> SearchGraph<'tcx> {
                     available_depth,
                 )
             {
-                inspect.cache_hit(CacheHit::Global);
+                inspect.goal_evaluation_kind(inspect::WipGoalEvaluationKind::CacheHit(
+                    CacheHit::Global,
+                ));
                 self.on_cache_hit(reached_depth, encountered_overflow);
                 return result;
             }
@@ -235,7 +240,9 @@ impl<'tcx> SearchGraph<'tcx> {
             // Finally we can return either the provisional response for that goal if we have a
             // coinductive cycle or an ambiguous result if the cycle is inductive.
             Entry::Occupied(entry_index) => {
-                inspect.cache_hit(CacheHit::Provisional);
+                inspect.goal_evaluation_kind(inspect::WipGoalEvaluationKind::CacheHit(
+                    CacheHit::Provisional,
+                ));
 
                 let entry_index = *entry_index.get();
                 let stack_depth = cache.depth(entry_index);