diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs index 0f3ace2d55d38..70d5a08229150 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -60,14 +60,14 @@ pub struct GoalEvaluation<'tcx> { pub evaluation: CanonicalGoalEvaluation<'tcx>, } -#[derive(Eq, PartialEq)] +#[derive(Eq, PartialEq, Debug)] pub struct CanonicalGoalEvaluation<'tcx> { pub goal: CanonicalInput<'tcx>, pub kind: CanonicalGoalEvaluationKind<'tcx>, pub result: QueryResult<'tcx>, } -#[derive(Eq, PartialEq)] +#[derive(Eq, PartialEq, Debug)] pub enum CanonicalGoalEvaluationKind<'tcx> { Overflow, CycleInStack, @@ -86,7 +86,7 @@ pub struct AddedGoalsEvaluation<'tcx> { pub result: Result, } -#[derive(Eq, PartialEq)] +#[derive(Eq, PartialEq, Debug)] pub struct GoalEvaluationStep<'tcx> { pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 2d58111e80385..cba3262017580 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -34,9 +34,9 @@ pub struct InspectConfig { pub struct InspectGoal<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, depth: usize, - orig_values: &'a [ty::GenericArg<'tcx>], + orig_values: Vec>, goal: Goal<'tcx, ty::Predicate<'tcx>>, - evaluation: &'a inspect::GoalEvaluation<'tcx>, + evaluation: inspect::CanonicalGoalEvaluation<'tcx>, } pub struct InspectCandidate<'a, 'tcx> { @@ -57,6 +57,10 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { self.result.map(|c| c.value.certainty) } + pub fn goal(&self) -> &'a InspectGoal<'a, 'tcx> { + self.goal + } + /// Certainty passed into `evaluate_added_goals_and_make_canonical_response`. /// /// If this certainty is `Yes`, then we must be confident that the candidate @@ -74,46 +78,55 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { /// the state of the `infcx`. pub fn visit_nested_no_probe>(&self, visitor: &mut V) -> V::Result { if self.goal.depth < visitor.config().max_depth { - let infcx = self.goal.infcx; - let param_env = self.goal.goal.param_env; - let mut orig_values = self.goal.orig_values.to_vec(); - let mut instantiated_goals = vec![]; - for goal in &self.nested_goals { - let goal = canonical::instantiate_canonical_state( + for goal in self.instantiate_nested_goals(visitor.span()) { + try_visit!(visitor.visit_goal(&goal)); + } + } + + V::Result::output() + } + + /// Instantiate the nested goals for the candidate without rolling back their + /// inference constraints. This function modifies the state of the `infcx`. + pub fn instantiate_nested_goals(&self, span: Span) -> Vec> { + let infcx = self.goal.infcx; + let param_env = self.goal.goal.param_env; + let mut orig_values = self.goal.orig_values.to_vec(); + let instantiated_goals: Vec<_> = self + .nested_goals + .iter() + .map(|goal| { + canonical::instantiate_canonical_state( infcx, - visitor.span(), + span, param_env, &mut orig_values, *goal, - ); - instantiated_goals.push(goal); - } + ) + }) + .collect(); - let () = canonical::instantiate_canonical_state( - infcx, - visitor.span(), - param_env, - &mut orig_values, - self.final_state, - ); + let () = canonical::instantiate_canonical_state( + infcx, + span, + param_env, + &mut orig_values, + self.final_state, + ); - for &goal in &instantiated_goals { + instantiated_goals + .into_iter() + .map(|goal| { let proof_tree = match goal.predicate.kind().no_bound_vars() { Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => { let unconstrained_term = match term.unpack() { ty::TermKind::Ty(_) => infcx - .next_ty_var(TypeVariableOrigin { - param_def_id: None, - span: visitor.span(), - }) + .next_ty_var(TypeVariableOrigin { param_def_id: None, span }) .into(), ty::TermKind::Const(ct) => infcx .next_const_var( ct.ty(), - ConstVariableOrigin { - param_def_id: None, - span: visitor.span(), - }, + ConstVariableOrigin { param_def_id: None, span }, ) .into(), }; @@ -129,22 +142,16 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { }) .1; let InferOk { value: (), obligations: _ } = infcx - .at(&ObligationCause::dummy(), param_env) + .at(&ObligationCause::dummy_with_span(span), param_env) .eq(DefineOpaqueTypes::Yes, term, unconstrained_term) .unwrap(); proof_tree } _ => infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1, }; - try_visit!(visitor.visit_goal(&InspectGoal::new( - infcx, - self.goal.depth + 1, - &proof_tree.unwrap(), - ))); - } - } - - V::Result::output() + InspectGoal::new(infcx, self.goal.depth + 1, proof_tree.unwrap()) + }) + .collect() } /// Visit all nested goals of this candidate, rolling back @@ -164,7 +171,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { } pub fn result(&self) -> Result { - self.evaluation.evaluation.result.map(|c| c.value.certainty) + self.evaluation.result.map(|c| c.value.certainty) } fn candidates_recur( @@ -221,7 +228,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { pub fn candidates(&'a self) -> Vec> { let mut candidates = vec![]; - let last_eval_step = match self.evaluation.evaluation.kind { + let last_eval_step = match self.evaluation.kind { inspect::CanonicalGoalEvaluationKind::Overflow | inspect::CanonicalGoalEvaluationKind::CycleInStack | inspect::CanonicalGoalEvaluationKind::ProvisionalCacheHit => { @@ -254,18 +261,15 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { candidates.pop().filter(|_| candidates.is_empty()) } - fn new( - infcx: &'a InferCtxt<'tcx>, - depth: usize, - root: &'a inspect::GoalEvaluation<'tcx>, - ) -> Self { - match root.kind { - inspect::GoalEvaluationKind::Root { ref orig_values } => InspectGoal { + fn new(infcx: &'a InferCtxt<'tcx>, depth: usize, root: inspect::GoalEvaluation<'tcx>) -> Self { + let inspect::GoalEvaluation { uncanonicalized_goal, kind, evaluation } = root; + match kind { + inspect::GoalEvaluationKind::Root { orig_values } => InspectGoal { infcx, depth, orig_values, - goal: root.uncanonicalized_goal.fold_with(&mut EagerResolver::new(infcx)), - evaluation: root, + goal: uncanonicalized_goal.fold_with(&mut EagerResolver::new(infcx)), + evaluation, }, inspect::GoalEvaluationKind::Nested { .. } => unreachable!(), } @@ -294,6 +298,6 @@ impl<'tcx> InferCtxt<'tcx> { ) -> V::Result { let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes); let proof_tree = proof_tree.unwrap(); - visitor.visit_goal(&InspectGoal::new(self, 0, &proof_tree)) + visitor.visit_goal(&InspectGoal::new(self, 0, proof_tree)) } }