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
This commit is contained in:
Matthias Krüger 2024-05-06 18:50:35 +02:00 committed by GitHub
commit 43de8225dc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 86 additions and 6 deletions

View file

@ -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());
};

View file

@ -0,0 +1,22 @@
trait Foo {}
trait Bar {}
impl<T> Foo for T where T: Bar {}
fn needs_foo(_: impl Foo) {}
trait Mirror {
type Mirror;
}
impl<T> Mirror for T {
type Mirror = T;
}
// Make sure the `Alias: Foo` bound doesn't "shadow" the impl, since the
// impl is really the only candidate we care about here for the purpose
// of error reporting.
fn hello<T>() where <T as Mirror>::Mirror: Foo {
needs_foo(());
//~^ ERROR the trait bound `(): Foo` is not satisfied
}
fn main() {}

View file

@ -0,0 +1,22 @@
error[E0277]: the trait bound `(): Foo` is not satisfied
--> $DIR/where-clause-doesnt-apply.rs:18:15
|
LL | needs_foo(());
| --------- ^^ the trait `Bar` is not implemented for `()`, which is required by `(): Foo`
| |
| required by a bound introduced by this call
|
note: required for `()` to implement `Foo`
--> $DIR/where-clause-doesnt-apply.rs:4:9
|
LL | impl<T> Foo for T where T: Bar {}
| ^^^ ^ --- unsatisfied trait bound introduced here
note: required by a bound in `needs_foo`
--> $DIR/where-clause-doesnt-apply.rs:5:22
|
LL | fn needs_foo(_: impl Foo) {}
| ^^^ required by this bound in `needs_foo`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.