1
Fork 0

show normalizes-to hack and response instantiation goals

This commit is contained in:
Boxy 2023-06-08 23:58:34 +01:00
parent e367c04dc6
commit 51090b962f
4 changed files with 71 additions and 18 deletions

View file

@ -991,3 +991,9 @@ pub enum DefiningAnchor {
/// Used to catch type mismatch errors when handling opaque types. /// Used to catch type mismatch errors when handling opaque types.
Error, Error,
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
pub enum IsNormalizesToHack {
Yes,
No,
}

View file

@ -1,5 +1,5 @@
use super::{CanonicalInput, Certainty, Goal, NoSolution, QueryInput, QueryResult}; use super::{CanonicalInput, Certainty, Goal, NoSolution, QueryInput, QueryResult};
use crate::ty; use crate::{traits::IsNormalizesToHack, ty};
use std::fmt::{Debug, Write}; use std::fmt::{Debug, Write};
#[derive(Eq, PartialEq, Debug, Hash, HashStable)] #[derive(Eq, PartialEq, Debug, Hash, HashStable)]
@ -14,6 +14,8 @@ pub struct GoalEvaluation<'tcx> {
pub canonicalized_goal: CanonicalInput<'tcx>, pub canonicalized_goal: CanonicalInput<'tcx>,
pub kind: GoalEvaluationKind<'tcx>, pub kind: GoalEvaluationKind<'tcx>,
pub is_normalizes_to_hack: IsNormalizesToHack,
pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
pub result: QueryResult<'tcx>, pub result: QueryResult<'tcx>,
} }
@ -99,7 +101,13 @@ impl ProofTreeFormatter<'_, '_> {
fn format_goal_evaluation(&mut self, goal: &GoalEvaluation<'_>) -> std::fmt::Result { fn format_goal_evaluation(&mut self, goal: &GoalEvaluation<'_>) -> std::fmt::Result {
let f = &mut *self.f; let f = &mut *self.f;
writeln!(f, "GOAL: {:?}", goal.uncanonicalized_goal)?;
let goal_text = match goal.is_normalizes_to_hack {
IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL",
IsNormalizesToHack::No => "GOAL",
};
writeln!(f, "{}: {:?}", goal_text, goal.uncanonicalized_goal,)?;
writeln!(f, "CANONICALIZED: {:?}", goal.canonicalized_goal)?; writeln!(f, "CANONICALIZED: {:?}", goal.canonicalized_goal)?;
match &goal.kind { match &goal.kind {
@ -120,7 +128,19 @@ impl ProofTreeFormatter<'_, '_> {
let f = &mut *self.f; let f = &mut *self.f;
writeln!(f, "RESULT: {:?}", goal.result) writeln!(f, "RESULT: {:?}", goal.result)
} }
}?;
if goal.returned_goals.len() > 0 {
let f = &mut *self.f;
writeln!(f, "NESTED GOALS ADDED TO CALLER: [")?;
let mut f = self.nested();
for goal in goal.returned_goals.iter() {
writeln!(f, "ADDED GOAL: {:?},", goal)?;
} }
writeln!(self.f, "]")?;
}
Ok(())
} }
fn format_evaluation_step( fn format_evaluation_step(

View file

@ -14,7 +14,7 @@ use rustc_middle::traits::solve::{
CanonicalInput, CanonicalResponse, Certainty, MaybeCause, PredefinedOpaques, CanonicalInput, CanonicalResponse, Certainty, MaybeCause, PredefinedOpaques,
PredefinedOpaquesData, QueryResult, PredefinedOpaquesData, QueryResult,
}; };
use rustc_middle::traits::DefiningAnchor; use rustc_middle::traits::{DefiningAnchor, IsNormalizesToHack};
use rustc_middle::ty::{ use rustc_middle::ty::{
self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
TypeVisitableExt, TypeVisitor, TypeVisitableExt, TypeVisitor,
@ -79,12 +79,6 @@ pub struct EvalCtxt<'a, 'tcx> {
inspect: ProofTreeBuilder<'tcx>, inspect: ProofTreeBuilder<'tcx>,
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
pub(super) enum IsNormalizesToHack {
Yes,
No,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(super) struct NestedGoals<'tcx> { pub(super) struct NestedGoals<'tcx> {
/// This normalizes-to goal that is treated specially during the evaluation /// This normalizes-to goal that is treated specially during the evaluation
@ -262,7 +256,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
goal: Goal<'tcx, ty::Predicate<'tcx>>, goal: Goal<'tcx, ty::Predicate<'tcx>>,
) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> { ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
let mut goal_evaluation = self.inspect.new_goal_evaluation(goal); let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, is_normalizes_to_hack);
let canonical_response = EvalCtxt::evaluate_canonical_goal( let canonical_response = EvalCtxt::evaluate_canonical_goal(
self.tcx(), self.tcx(),
self.search_graph, self.search_graph,
@ -270,16 +264,29 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
&mut goal_evaluation, &mut goal_evaluation,
); );
goal_evaluation.query_result(canonical_response); goal_evaluation.query_result(canonical_response);
let canonical_response = match canonical_response {
Err(e) => {
self.inspect.goal_evaluation(goal_evaluation); self.inspect.goal_evaluation(goal_evaluation);
let canonical_response = canonical_response?; return Err(e);
}
Ok(response) => response,
};
let has_changed = !canonical_response.value.var_values.is_identity() let has_changed = !canonical_response.value.var_values.is_identity()
|| !canonical_response.value.external_constraints.opaque_types.is_empty(); || !canonical_response.value.external_constraints.opaque_types.is_empty();
let (certainty, nested_goals) = self.instantiate_and_apply_query_response( let (certainty, nested_goals) = match self.instantiate_and_apply_query_response(
goal.param_env, goal.param_env,
orig_values, orig_values,
canonical_response, canonical_response,
)?; ) {
Err(e) => {
self.inspect.goal_evaluation(goal_evaluation);
return Err(e);
}
Ok(response) => response,
};
goal_evaluation.returned_goals(&nested_goals);
self.inspect.goal_evaluation(goal_evaluation);
if !has_changed && !nested_goals.is_empty() { if !has_changed && !nested_goals.is_empty() {
bug!("an unchanged goal shouldn't have any side-effects on instantiation"); bug!("an unchanged goal shouldn't have any side-effects on instantiation");

View file

@ -5,6 +5,7 @@ use rustc_middle::{
inspect::{self, CacheHit, CandidateKind}, inspect::{self, CacheHit, CandidateKind},
CanonicalInput, Certainty, Goal, QueryInput, QueryResult, CanonicalInput, Certainty, Goal, QueryInput, QueryResult,
}, },
IsNormalizesToHack,
}, },
ty, ty,
}; };
@ -17,6 +18,8 @@ pub struct WipGoalEvaluation<'tcx> {
pub evaluation_steps: Vec<WipGoalEvaluationStep<'tcx>>, pub evaluation_steps: Vec<WipGoalEvaluationStep<'tcx>>,
pub cache_hit: Option<CacheHit>, pub cache_hit: Option<CacheHit>,
pub is_normalizes_to_hack: IsNormalizesToHack,
pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
pub result: Option<QueryResult<'tcx>>, pub result: Option<QueryResult<'tcx>>,
} }
@ -35,6 +38,8 @@ impl<'tcx> WipGoalEvaluation<'tcx> {
.collect(), .collect(),
}, },
}, },
is_normalizes_to_hack: self.is_normalizes_to_hack,
returned_goals: self.returned_goals,
result: self.result.unwrap(), result: self.result.unwrap(),
} }
} }
@ -116,13 +121,11 @@ pub enum DebugSolver<'tcx> {
pub struct ProofTreeBuilder<'tcx>(Option<Box<DebugSolver<'tcx>>>); pub struct ProofTreeBuilder<'tcx>(Option<Box<DebugSolver<'tcx>>>);
impl<'tcx> ProofTreeBuilder<'tcx> { impl<'tcx> ProofTreeBuilder<'tcx> {
pub fn finalize(self) -> Option<inspect::GoalEvaluation<'tcx>> { pub fn finalize(self) -> Option<inspect::GoalEvaluation<'tcx>> {
let wip_tree = *(self.0?); match *(self.0?) {
match wip_tree {
DebugSolver::GoalEvaluation(wip_goal_evaluation) => { DebugSolver::GoalEvaluation(wip_goal_evaluation) => {
Some(wip_goal_evaluation.finalize()) Some(wip_goal_evaluation.finalize())
} }
_ => unreachable!(), root => unreachable!("unexpected proof tree builder root node: {:?}", root),
} }
} }
@ -141,6 +144,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
pub fn new_goal_evaluation( pub fn new_goal_evaluation(
&mut self, &mut self,
goal: Goal<'tcx, ty::Predicate<'tcx>>, goal: Goal<'tcx, ty::Predicate<'tcx>>,
is_normalizes_to_hack: IsNormalizesToHack,
) -> ProofTreeBuilder<'tcx> { ) -> ProofTreeBuilder<'tcx> {
if self.0.is_none() { if self.0.is_none() {
return ProofTreeBuilder(None); return ProofTreeBuilder(None);
@ -150,7 +154,9 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
uncanonicalized_goal: goal, uncanonicalized_goal: goal,
canonicalized_goal: None, canonicalized_goal: None,
evaluation_steps: vec![], evaluation_steps: vec![],
is_normalizes_to_hack,
cache_hit: None, cache_hit: None,
returned_goals: vec![],
result: None, result: None,
})))) }))))
} }
@ -181,6 +187,20 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
_ => unreachable!(), _ => unreachable!(),
}; };
} }
pub fn returned_goals(&mut self, goals: &[Goal<'tcx, ty::Predicate<'tcx>>]) {
let this = match self.0.as_mut() {
None => return,
Some(this) => &mut **this,
};
match this {
DebugSolver::GoalEvaluation(evaluation) => {
assert!(evaluation.returned_goals.is_empty());
evaluation.returned_goals.extend(goals);
}
_ => unreachable!(),
}
}
pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<'tcx>) { pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<'tcx>) {
let this = match self.0.as_mut() { let this = match self.0.as_mut() {
None => return, None => return,