diff options
Diffstat (limited to 'compiler')
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()); }; |
