about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src/solve
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-05-06 18:50:35 +0200
committerGitHub <noreply@github.com>2024-05-06 18:50:35 +0200
commit43de8225dc2bdf2ad9a58f42192a32bf2b2eae98 (patch)
treeb474324b8c1b76a6ed480ba7f6460263e0e2cc95 /compiler/rustc_trait_selection/src/solve
parent2d557ba9f4cbc1cdc01a515864867c12e3b85ad1 (diff)
parent4e3350d43b2546281784d2ce4cf6803473a81645 (diff)
downloadrust-43de8225dc2bdf2ad9a58f42192a32bf2b2eae98.tar.gz
rust-43de8225dc2bdf2ad9a58f42192a32bf2b2eae98.zip
Rollup merge of #124771 - compiler-errors:cand-has-failing-wc, r=lcnr
Don't consider candidates with no failing where clauses when refining obligation causes in new solver

Improves error messages when we have param-env candidates that don't deeply unify (i.e. after alias-bounds).

r? lcnr
Diffstat (limited to 'compiler/rustc_trait_selection/src/solve')
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs48
1 files changed, 42 insertions, 6 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index fd4b5805f02..39d2ec4417c 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -14,7 +14,7 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::symbol::sym;
 
 use super::eval_ctxt::GenerateProofTree;
-use super::inspect::{ProofTreeInferCtxtExt, ProofTreeVisitor};
+use super::inspect::{InspectCandidate, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
 use super::{Certainty, InferCtxtEvalExt};
 
 /// A trait engine using the new trait solver.
@@ -304,6 +304,46 @@ impl<'tcx> BestObligation<'tcx> {
         self.obligation = old_obligation;
         res
     }
+
+    /// Filter out the candidates that aren't either error or ambiguous (depending
+    /// on what we are looking for), and also throw out candidates that have no
+    /// failing WC (or higher-ranked obligations, for which there should only be
+    /// one candidate anyways -- but I digress). This most likely means that the
+    /// goal just didn't unify at all, e.g. a param candidate with an alias in it.
+    fn non_trivial_candidates<'a>(
+        &self,
+        goal: &'a InspectGoal<'a, 'tcx>,
+    ) -> Vec<InspectCandidate<'a, 'tcx>> {
+        let mut candidates = goal
+            .candidates()
+            .into_iter()
+            .filter(|candidate| match self.consider_ambiguities {
+                true => matches!(candidate.result(), Ok(Certainty::Maybe(_))),
+                false => matches!(candidate.result(), Err(_)),
+            })
+            .collect::<Vec<_>>();
+
+        // If we have >1 candidate, one may still be due to "boring" reasons, like
+        // an alias-relate that failed to hold when deeply evaluated. We really
+        // don't care about reasons like this.
+        if candidates.len() > 1 {
+            candidates.retain(|candidate| {
+                goal.infcx().probe(|_| {
+                    candidate.instantiate_nested_goals(self.span()).iter().any(|nested_goal| {
+                        matches!(
+                            nested_goal.source(),
+                            GoalSource::ImplWhereBound | GoalSource::InstantiateHigherRanked
+                        ) && match self.consider_ambiguities {
+                            true => matches!(nested_goal.result(), Ok(Certainty::Maybe(_))),
+                            false => matches!(nested_goal.result(), Err(_)),
+                        }
+                    })
+                })
+            });
+        }
+
+        candidates
+    }
 }
 
 impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
@@ -314,11 +354,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
     }
 
     fn visit_goal(&mut self, goal: &super::inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
-        // FIXME: Throw out candidates that have no failing WC and >0 failing misc goal.
-        // This most likely means that the goal just didn't unify at all, e.g. a param
-        // candidate with an alias in it.
-        let candidates = goal.candidates();
-
+        let candidates = self.non_trivial_candidates(goal);
         let [candidate] = candidates.as_slice() else {
             return ControlFlow::Break(self.obligation.clone());
         };