From f21a12aaa22ad7b3d00cd84c9ba1884ffa798ec5 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Mon, 7 Sep 2026 16:07:10 +0200 Subject: [PATCH] In the `BestObligation` prooftree visitor, we now only skip any candidates who have a failed `Normalization` nested goal. The previous condition on `ImplWhereBound` and co is now removed as it is unessecary. + add test of issue --- .../src/solve/fulfill/derive_errors.rs | 16 ++--- ...agnostic-due-to-best-obligation-visitor.rs | 27 ++++++++ ...stic-due-to-best-obligation-visitor.stderr | 64 +++++++++++++++++++ 3 files changed, 97 insertions(+), 10 deletions(-) create mode 100644 tests/ui/traits/next-solver/confusing-diagnostic-due-to-best-obligation-visitor.rs create mode 100644 tests/ui/traits/next-solver/confusing-diagnostic-due-to-best-obligation-visitor.stderr diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 7df3fa41a1df2..992c521261b5c 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -214,20 +214,16 @@ impl<'tcx> BestObligation<'tcx> { // We always handle rigid alias candidates separately as we may not add them for // aliases whose trait bound doesn't hold. candidates.retain(|c| !matches!(c.kind(), inspect::ProbeKind::RigidAlias { .. })); - // 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 there are multiple candidates, we can still recurse into a single one if all + // others fail due to boring reasons. Currently that's if we fail to normalize + // while considering the candidate. if candidates.len() > 1 { candidates.retain(|candidate| { goal.infcx().probe(|_| { - candidate.instantiate_nested_goals(self.span()).iter().any( + !candidate.instantiate_nested_goals(self.span()).iter().any( |nested_goal| { - matches!( - nested_goal.source(), - GoalSource::ImplWhereBound - | GoalSource::AliasBoundConstCondition - | GoalSource::AliasWellFormed - ) && nested_goal.result().is_err() + nested_goal.source() == GoalSource::Normalization + && nested_goal.result().is_err() }, ) }) diff --git a/tests/ui/traits/next-solver/confusing-diagnostic-due-to-best-obligation-visitor.rs b/tests/ui/traits/next-solver/confusing-diagnostic-due-to-best-obligation-visitor.rs new file mode 100644 index 0000000000000..b925e6a7745e6 --- /dev/null +++ b/tests/ui/traits/next-solver/confusing-diagnostic-due-to-best-obligation-visitor.rs @@ -0,0 +1,27 @@ +//@compile-flags: -Znext-solver=globally +//@check-fail + +// See issue https://github.com/rust-lang/rust/issues/161882, test makes sure we don't report +// irrelevant and not implemented bounds when we can't proof an obligation. + +struct MyError; + +trait MaybeFallible { + type Error: MaybeError; //~ ERROR: the trait bound `MyError: From<::Error>` is not satisfied +} + +trait MaybeError: Sized +where + MyError: From, +{ + type ComposeWithOther: MaybeError; //~ ERROR: the trait bound `MyError: From<::ComposeWithOther>` is not satisfied +} + +fn compose() -> Result<(), ()> +where + ::ComposeWithOther: From, //~ ERROR: the trait bound `MyError: From<::Error>` is not satisfied +{ + todo!() +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/confusing-diagnostic-due-to-best-obligation-visitor.stderr b/tests/ui/traits/next-solver/confusing-diagnostic-due-to-best-obligation-visitor.stderr new file mode 100644 index 0000000000000..2dd3f4f9a945f --- /dev/null +++ b/tests/ui/traits/next-solver/confusing-diagnostic-due-to-best-obligation-visitor.stderr @@ -0,0 +1,64 @@ +error[E0277]: the trait bound `MyError: From<::Error>` is not satisfied + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:22:49 + | +LL | ::ComposeWithOther: From, + | ^^^^^^^ unsatisfied trait bound + | +help: the trait `From<::Error>` is not implemented for `MyError` + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:7:1 + | +LL | struct MyError; + | ^^^^^^^^^^^^^^ +note: required by a bound in `MaybeError` + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:15:14 + | +LL | trait MaybeError: Sized +LL | where +LL | MyError: From, + | ^^^^^^^^^^ required by this bound in `MaybeError` +help: consider extending the `where` clause, but there might be an alternative better way to express this requirement + | +LL | ::ComposeWithOther: From, MyError: From<::Error> + | ++++++++++++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `MyError: From<::Error>` is not satisfied + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:10:17 + | +LL | type Error: MaybeError; + | ^^^^^^^^^^ unsatisfied trait bound + | +help: the trait `From<::Error>` is not implemented for `MyError` + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:7:1 + | +LL | struct MyError; + | ^^^^^^^^^^^^^^ +note: required by a bound in `MaybeError` + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:15:14 + | +LL | trait MaybeError: Sized +LL | where +LL | MyError: From, + | ^^^^^^^^^^ required by this bound in `MaybeError` + +error[E0277]: the trait bound `MyError: From<::ComposeWithOther>` is not satisfied + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:17:28 + | +LL | type ComposeWithOther: MaybeError; + | ^^^^^^^^^^ unsatisfied trait bound + | +help: the trait `From<::ComposeWithOther>` is not implemented for `MyError` + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:7:1 + | +LL | struct MyError; + | ^^^^^^^^^^^^^^ +note: required by a bound in `MaybeError` + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:15:14 + | +LL | trait MaybeError: Sized +LL | where +LL | MyError: From, + | ^^^^^^^^^^ required by this bound in `MaybeError` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`.