diff options
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); |
