1
Fork 0

allow caller to force proof tree generation

This commit is contained in:
Boxy 2023-06-09 00:19:54 +01:00
parent 51090b962f
commit bb743f8635
2 changed files with 89 additions and 72 deletions

View file

@ -9,7 +9,7 @@ use rustc_infer::infer::{
use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::ObligationCause; use rustc_infer::traits::ObligationCause;
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::traits::solve::inspect::CandidateKind; use rustc_middle::traits::solve::inspect::{self, CandidateKind};
use rustc_middle::traits::solve::{ use rustc_middle::traits::solve::{
CanonicalInput, CanonicalResponse, Certainty, MaybeCause, PredefinedOpaques, CanonicalInput, CanonicalResponse, Certainty, MaybeCause, PredefinedOpaques,
PredefinedOpaquesData, QueryResult, PredefinedOpaquesData, QueryResult,
@ -108,6 +108,12 @@ impl NestedGoals<'_> {
} }
} }
#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
pub enum GenerateProofTree {
Yes,
No,
}
pub trait InferCtxtEvalExt<'tcx> { pub trait InferCtxtEvalExt<'tcx> {
/// Evaluates a goal from **outside** of the trait solver. /// Evaluates a goal from **outside** of the trait solver.
/// ///
@ -116,7 +122,11 @@ pub trait InferCtxtEvalExt<'tcx> {
fn evaluate_root_goal( fn evaluate_root_goal(
&self, &self,
goal: Goal<'tcx, ty::Predicate<'tcx>>, goal: Goal<'tcx, ty::Predicate<'tcx>>,
) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>; generate_proof_tree: GenerateProofTree,
) -> (
Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>,
Option<inspect::GoalEvaluation<'tcx>>,
);
} }
impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
@ -124,7 +134,11 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
fn evaluate_root_goal( fn evaluate_root_goal(
&self, &self,
goal: Goal<'tcx, ty::Predicate<'tcx>>, goal: Goal<'tcx, ty::Predicate<'tcx>>,
) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> { generate_proof_tree: GenerateProofTree,
) -> (
Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>,
Option<inspect::GoalEvaluation<'tcx>>,
) {
let mode = if self.intercrate { SolverMode::Coherence } else { SolverMode::Normal }; let mode = if self.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
let mut search_graph = search_graph::SearchGraph::new(self.tcx, mode); let mut search_graph = search_graph::SearchGraph::new(self.tcx, mode);
@ -141,19 +155,16 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
var_values: CanonicalVarValues::dummy(), var_values: CanonicalVarValues::dummy(),
nested_goals: NestedGoals::new(), nested_goals: NestedGoals::new(),
tainted: Ok(()), tainted: Ok(()),
inspect: self inspect: (self.tcx.sess.opts.unstable_opts.dump_solver_proof_tree
.tcx || matches!(generate_proof_tree, GenerateProofTree::Yes))
.sess
.opts
.unstable_opts
.dump_solver_proof_tree
.then(ProofTreeBuilder::new_root) .then(ProofTreeBuilder::new_root)
.unwrap_or_else(ProofTreeBuilder::new_noop), .unwrap_or_else(ProofTreeBuilder::new_noop),
}; };
let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal); let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal);
if let Some(tree) = ecx.inspect.finalize() { let tree = ecx.inspect.finalize();
println!("{:?}", tree); if let Some(tree) = &tree {
debug!(?tree);
} }
assert!( assert!(
@ -162,7 +173,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
); );
assert!(search_graph.is_empty()); assert!(search_graph.is_empty());
result (result, tree)
} }
} }

View file

@ -10,6 +10,7 @@ use rustc_infer::traits::{
use rustc_middle::ty; use rustc_middle::ty;
use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::error::{ExpectedFound, TypeError};
use super::eval_ctxt::GenerateProofTree;
use super::{Certainty, InferCtxtEvalExt}; use super::{Certainty, InferCtxtEvalExt};
/// A trait engine using the new trait solver. /// A trait engine using the new trait solver.
@ -46,8 +47,11 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
self.obligations self.obligations
.drain(..) .drain(..)
.map(|obligation| { .map(|obligation| {
let code = let code = infcx.probe(|_| {
infcx.probe(|_| match infcx.evaluate_root_goal(obligation.clone().into()) { match infcx
.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::No)
.0
{
Ok((_, Certainty::Maybe(MaybeCause::Ambiguity), _)) => { Ok((_, Certainty::Maybe(MaybeCause::Ambiguity), _)) => {
FulfillmentErrorCode::CodeAmbiguity { overflow: false } FulfillmentErrorCode::CodeAmbiguity { overflow: false }
} }
@ -60,6 +64,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
Err(_) => { Err(_) => {
bug!("did not expect selection error when collecting ambiguity errors") bug!("did not expect selection error when collecting ambiguity errors")
} }
}
}); });
FulfillmentError { FulfillmentError {
@ -81,7 +86,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
let mut has_changed = false; let mut has_changed = false;
for obligation in mem::take(&mut self.obligations) { for obligation in mem::take(&mut self.obligations) {
let goal = obligation.clone().into(); let goal = obligation.clone().into();
let (changed, certainty, nested_goals) = match infcx.evaluate_root_goal(goal) { let (changed, certainty, nested_goals) =
match infcx.evaluate_root_goal(goal, GenerateProofTree::No).0 {
Ok(result) => result, Ok(result) => result,
Err(NoSolution) => { Err(NoSolution) => {
errors.push(FulfillmentError { errors.push(FulfillmentError {