about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs18
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs48
3 files changed, 56 insertions, 12 deletions
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index 6600b92fb31..c437dedbbbc 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -455,7 +455,7 @@ impl<I: Interner> TypeFolder<I> for RegionsToStatic<I> {
         I::Binder<T>: TypeSuperFoldable<I>,
     {
         self.binder.shift_in(1);
-        let t = t.fold_with(self);
+        let t = t.super_fold_with(self);
         self.binder.shift_out(1);
         t
     }
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
index 16fe045b82d..4d474b8e707 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
@@ -58,6 +58,12 @@ impl<'tcx> inspect::ProofTreeVisitor<'tcx> for Select {
             )));
         }
 
+        // Don't winnow until `Certainty::Yes` -- we don't need to winnow until
+        // codegen, and only on the good path.
+        if matches!(goal.result().unwrap(), Certainty::Maybe(..)) {
+            return ControlFlow::Break(Ok(None));
+        }
+
         // We need to winnow. See comments on `candidate_should_be_dropped_in_favor_of`.
         let mut i = 0;
         while i < candidates.len() {
@@ -86,7 +92,7 @@ fn candidate_should_be_dropped_in_favor_of<'tcx>(
     other: &inspect::InspectCandidate<'_, 'tcx>,
 ) -> bool {
     // Don't winnow until `Certainty::Yes` -- we don't need to winnow until
-    // codegen, technically.
+    // codegen, and only on the good path.
     if matches!(other.result().unwrap(), Certainty::Maybe(..)) {
         return false;
     }
@@ -105,13 +111,15 @@ fn candidate_should_be_dropped_in_favor_of<'tcx>(
             bug!("should not have assembled a CoherenceUnknowable candidate")
         }
 
+        // In the old trait solver, we arbitrarily choose lower vtable candidates
+        // over higher ones.
+        (
+            CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base: a }),
+            CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base: b }),
+        ) => a >= b,
         // Prefer dyn candidates over non-dyn candidates. This is necessary to
         // handle the unsoundness between `impl<T: ?Sized> Any for T` and `dyn Any: Any`.
         (
-            CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
-            CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
-        ) => false,
-        (
             CandidateSource::Impl(_) | CandidateSource::ParamEnv(_) | CandidateSource::AliasBound,
             CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
         ) => true,
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());
         };