about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
authorlcnr <rust@lcnr.de>2024-05-09 17:11:51 +0000
committerlcnr <rust@lcnr.de>2024-05-09 17:29:53 +0000
commit83e6da0be5e0e7cec8326ad5c4ba463299d32eea (patch)
tree964cf7496871933227693d45a005c28c7b014439 /compiler/rustc_trait_selection/src
parent8c7c151a7a03d92cc5c75c49aa82a658ec1fe4ff (diff)
analyse visitor: build proof tree in probe
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs44
2 files changed, 34 insertions, 11 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index 5f73432750d..41b304ec538 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -409,6 +409,7 @@ pub(in crate::solve) fn make_canonical_state<'tcx, T: TypeFoldable<TyCtxt<'tcx>>
 /// This currently assumes that unifying the var values trivially succeeds.
 /// Adding any inference constraints which weren't present when originally
 /// computing the canonical query can result in bugs.
+#[instrument(level = "debug", skip(infcx, span, param_env))]
 pub(in crate::solve) fn instantiate_canonical_state<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
     infcx: &InferCtxt<'tcx>,
     span: Span,
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index fa4323a3a94..71ae410a03f 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -146,6 +146,11 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
     /// inference constraints, and optionally the args of an impl if this candidate
     /// came from a `CandidateSource::Impl`. This function modifies the state of the
     /// `infcx`.
+    #[instrument(
+        level = "debug",
+        skip_all,
+        fields(goal = ?self.goal.goal, nested_goals = ?self.nested_goals)
+    )]
     pub fn instantiate_nested_goals_and_opt_impl_args(
         &self,
         span: Span,
@@ -213,10 +218,23 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
                     };
                     let goal =
                         goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term });
-                    let proof_tree = EvalCtxt::enter_root(infcx, GenerateProofTree::Yes, |ecx| {
-                        ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal)
-                    })
-                    .1;
+                    // We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the
+                    // expected term. This means that candidates which only fail due to nested goals
+                    // and which normalize to a different term then the final result could ICE: when
+                    // building their proof tree, the expected term was unconstrained, but when
+                    // instantiating the candidate it is already constrained to the result of another
+                    // candidate.
+                    let proof_tree = infcx
+                        .probe(|_| {
+                            EvalCtxt::enter_root(infcx, GenerateProofTree::Yes, |ecx| {
+                                ecx.evaluate_goal_raw(
+                                    GoalEvaluationKind::Root,
+                                    GoalSource::Misc,
+                                    goal,
+                                )
+                            })
+                        })
+                        .1;
                     InspectGoal::new(
                         infcx,
                         self.goal.depth + 1,
@@ -225,13 +243,17 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
                         source,
                     )
                 }
-                _ => InspectGoal::new(
-                    infcx,
-                    self.goal.depth + 1,
-                    infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1.unwrap(),
-                    None,
-                    source,
-                ),
+                _ => {
+                    // We're using a probe here as evaluating a goal could constrain
+                    // inference variables by choosing one candidate. If we then recurse
+                    // into another candidate who ends up with different inference
+                    // constraints, we get an ICE if we already applied the constraints
+                    // from the chosen candidate.
+                    let proof_tree = infcx
+                        .probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1)
+                        .unwrap();
+                    InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source)
+                }
             })
             .collect();