Skip to content

Commit 43de822

Browse files
authored
Rollup merge of rust-lang#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
2 parents 2d557ba + 4e3350d commit 43de822

File tree

3 files changed

+86
-6
lines changed

3 files changed

+86
-6
lines changed

compiler/rustc_trait_selection/src/solve/fulfill.rs

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_middle::ty::{self, TyCtxt};
1414
use rustc_span::symbol::sym;
1515

1616
use super::eval_ctxt::GenerateProofTree;
17-
use super::inspect::{ProofTreeInferCtxtExt, ProofTreeVisitor};
17+
use super::inspect::{InspectCandidate, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
1818
use super::{Certainty, InferCtxtEvalExt};
1919

2020
/// A trait engine using the new trait solver.
@@ -304,6 +304,46 @@ impl<'tcx> BestObligation<'tcx> {
304304
self.obligation = old_obligation;
305305
res
306306
}
307+
308+
/// Filter out the candidates that aren't either error or ambiguous (depending
309+
/// on what we are looking for), and also throw out candidates that have no
310+
/// failing WC (or higher-ranked obligations, for which there should only be
311+
/// one candidate anyways -- but I digress). This most likely means that the
312+
/// goal just didn't unify at all, e.g. a param candidate with an alias in it.
313+
fn non_trivial_candidates<'a>(
314+
&self,
315+
goal: &'a InspectGoal<'a, 'tcx>,
316+
) -> Vec<InspectCandidate<'a, 'tcx>> {
317+
let mut candidates = goal
318+
.candidates()
319+
.into_iter()
320+
.filter(|candidate| match self.consider_ambiguities {
321+
true => matches!(candidate.result(), Ok(Certainty::Maybe(_))),
322+
false => matches!(candidate.result(), Err(_)),
323+
})
324+
.collect::<Vec<_>>();
325+
326+
// If we have >1 candidate, one may still be due to "boring" reasons, like
327+
// an alias-relate that failed to hold when deeply evaluated. We really
328+
// don't care about reasons like this.
329+
if candidates.len() > 1 {
330+
candidates.retain(|candidate| {
331+
goal.infcx().probe(|_| {
332+
candidate.instantiate_nested_goals(self.span()).iter().any(|nested_goal| {
333+
matches!(
334+
nested_goal.source(),
335+
GoalSource::ImplWhereBound | GoalSource::InstantiateHigherRanked
336+
) && match self.consider_ambiguities {
337+
true => matches!(nested_goal.result(), Ok(Certainty::Maybe(_))),
338+
false => matches!(nested_goal.result(), Err(_)),
339+
}
340+
})
341+
})
342+
});
343+
}
344+
345+
candidates
346+
}
307347
}
308348

309349
impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
@@ -314,11 +354,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
314354
}
315355

316356
fn visit_goal(&mut self, goal: &super::inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
317-
// FIXME: Throw out candidates that have no failing WC and >0 failing misc goal.
318-
// This most likely means that the goal just didn't unify at all, e.g. a param
319-
// candidate with an alias in it.
320-
let candidates = goal.candidates();
321-
357+
let candidates = self.non_trivial_candidates(goal);
322358
let [candidate] = candidates.as_slice() else {
323359
return ControlFlow::Break(self.obligation.clone());
324360
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
trait Foo {}
2+
trait Bar {}
3+
4+
impl<T> Foo for T where T: Bar {}
5+
fn needs_foo(_: impl Foo) {}
6+
7+
trait Mirror {
8+
type Mirror;
9+
}
10+
impl<T> Mirror for T {
11+
type Mirror = T;
12+
}
13+
14+
// Make sure the `Alias: Foo` bound doesn't "shadow" the impl, since the
15+
// impl is really the only candidate we care about here for the purpose
16+
// of error reporting.
17+
fn hello<T>() where <T as Mirror>::Mirror: Foo {
18+
needs_foo(());
19+
//~^ ERROR the trait bound `(): Foo` is not satisfied
20+
}
21+
22+
fn main() {}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0277]: the trait bound `(): Foo` is not satisfied
2+
--> $DIR/where-clause-doesnt-apply.rs:18:15
3+
|
4+
LL | needs_foo(());
5+
| --------- ^^ the trait `Bar` is not implemented for `()`, which is required by `(): Foo`
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
note: required for `()` to implement `Foo`
10+
--> $DIR/where-clause-doesnt-apply.rs:4:9
11+
|
12+
LL | impl<T> Foo for T where T: Bar {}
13+
| ^^^ ^ --- unsatisfied trait bound introduced here
14+
note: required by a bound in `needs_foo`
15+
--> $DIR/where-clause-doesnt-apply.rs:5:22
16+
|
17+
LL | fn needs_foo(_: impl Foo) {}
18+
| ^^^ required by this bound in `needs_foo`
19+
20+
error: aborting due to 1 previous error
21+
22+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)