diff options
| -rw-r--r-- | compiler/rustc_trait_selection/src/solve/eval_ctxt.rs | 39 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/solve/fulfill.rs | 122 |
2 files changed, 89 insertions, 72 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 9ac37de71d3..a8c569cd38b 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -9,7 +9,7 @@ use rustc_infer::infer::{ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; 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::{ CanonicalInput, CanonicalResponse, Certainty, MaybeCause, PredefinedOpaques, 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> { /// Evaluates a goal from **outside** of the trait solver. /// @@ -116,7 +122,11 @@ pub trait InferCtxtEvalExt<'tcx> { fn evaluate_root_goal( &self, 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> { @@ -124,7 +134,11 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { fn evaluate_root_goal( &self, 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 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(), nested_goals: NestedGoals::new(), tainted: Ok(()), - inspect: self - .tcx - .sess - .opts - .unstable_opts - .dump_solver_proof_tree - .then(ProofTreeBuilder::new_root) - .unwrap_or_else(ProofTreeBuilder::new_noop), + inspect: (self.tcx.sess.opts.unstable_opts.dump_solver_proof_tree + || matches!(generate_proof_tree, GenerateProofTree::Yes)) + .then(ProofTreeBuilder::new_root) + .unwrap_or_else(ProofTreeBuilder::new_noop), }; let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal); - if let Some(tree) = ecx.inspect.finalize() { - println!("{:?}", tree); + let tree = ecx.inspect.finalize(); + if let Some(tree) = &tree { + debug!(?tree); } assert!( @@ -162,7 +173,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { ); assert!(search_graph.is_empty()); - result + (result, tree) } } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 65c8d9c8f69..0e671144a29 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -10,6 +10,7 @@ use rustc_infer::traits::{ use rustc_middle::ty; use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use super::eval_ctxt::GenerateProofTree; use super::{Certainty, InferCtxtEvalExt}; /// A trait engine using the new trait solver. @@ -46,8 +47,11 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { self.obligations .drain(..) .map(|obligation| { - let code = - infcx.probe(|_| match infcx.evaluate_root_goal(obligation.clone().into()) { + let code = infcx.probe(|_| { + match infcx + .evaluate_root_goal(obligation.clone().into(), GenerateProofTree::No) + .0 + { Ok((_, Certainty::Maybe(MaybeCause::Ambiguity), _)) => { FulfillmentErrorCode::CodeAmbiguity { overflow: false } } @@ -60,7 +64,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { Err(_) => { bug!("did not expect selection error when collecting ambiguity errors") } - }); + } + }); FulfillmentError { obligation: obligation.clone(), @@ -81,61 +86,62 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let mut has_changed = false; for obligation in mem::take(&mut self.obligations) { let goal = obligation.clone().into(); - let (changed, certainty, nested_goals) = match infcx.evaluate_root_goal(goal) { - Ok(result) => result, - Err(NoSolution) => { - errors.push(FulfillmentError { - obligation: obligation.clone(), - code: match goal.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(_)) => { - FulfillmentErrorCode::CodeProjectionError( - // FIXME: This could be a `Sorts` if the term is a type - MismatchedProjectionTypes { err: TypeError::Mismatch }, - ) - } - ty::PredicateKind::AliasRelate(_, _, _) => { - FulfillmentErrorCode::CodeProjectionError( - MismatchedProjectionTypes { err: TypeError::Mismatch }, - ) - } - ty::PredicateKind::Subtype(pred) => { - let (a, b) = infcx.instantiate_binder_with_placeholders( - goal.predicate.kind().rebind((pred.a, pred.b)), - ); - let expected_found = ExpectedFound::new(true, a, b); - FulfillmentErrorCode::CodeSubtypeError( - expected_found, - TypeError::Sorts(expected_found), - ) - } - ty::PredicateKind::Coerce(pred) => { - let (a, b) = infcx.instantiate_binder_with_placeholders( - goal.predicate.kind().rebind((pred.a, pred.b)), - ); - let expected_found = ExpectedFound::new(false, a, b); - FulfillmentErrorCode::CodeSubtypeError( - expected_found, - TypeError::Sorts(expected_found), - ) - } - ty::PredicateKind::Clause(_) - | ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::ClosureKind(_, _, _) - | ty::PredicateKind::Ambiguous => { - FulfillmentErrorCode::CodeSelectionError( - SelectionError::Unimplemented, - ) - } - ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::TypeWellFormedFromEnv(_) => { - bug!("unexpected goal: {goal:?}") - } - }, - root_obligation: obligation, - }); - continue; - } - }; + let (changed, certainty, nested_goals) = + match infcx.evaluate_root_goal(goal, GenerateProofTree::No).0 { + Ok(result) => result, + Err(NoSolution) => { + errors.push(FulfillmentError { + obligation: obligation.clone(), + code: match goal.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::Clause::Projection(_)) => { + FulfillmentErrorCode::CodeProjectionError( + // FIXME: This could be a `Sorts` if the term is a type + MismatchedProjectionTypes { err: TypeError::Mismatch }, + ) + } + ty::PredicateKind::AliasRelate(_, _, _) => { + FulfillmentErrorCode::CodeProjectionError( + MismatchedProjectionTypes { err: TypeError::Mismatch }, + ) + } + ty::PredicateKind::Subtype(pred) => { + let (a, b) = infcx.instantiate_binder_with_placeholders( + goal.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(true, a, b); + FulfillmentErrorCode::CodeSubtypeError( + expected_found, + TypeError::Sorts(expected_found), + ) + } + ty::PredicateKind::Coerce(pred) => { + let (a, b) = infcx.instantiate_binder_with_placeholders( + goal.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(false, a, b); + FulfillmentErrorCode::CodeSubtypeError( + expected_found, + TypeError::Sorts(expected_found), + ) + } + ty::PredicateKind::Clause(_) + | ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::ClosureKind(_, _, _) + | ty::PredicateKind::Ambiguous => { + FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + ) + } + ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::TypeWellFormedFromEnv(_) => { + bug!("unexpected goal: {goal:?}") + } + }, + root_obligation: obligation, + }); + continue; + } + }; // Push any nested goals that we get from unifying our canonical response // with our obligation onto the fulfillment context. self.obligations.extend(nested_goals.into_iter().map(|goal| { |
