diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 1897ed8fc84eb..6293c85f595d8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1593,6 +1593,45 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } + /// Whether `error`, a projection goal, only failed because the trait goal it rests on + /// did: `::Assoc == U` cannot hold when `T: Trait` doesn't, so an error on + /// the latter says everything the former would. + pub(super) fn trait_error_implies_projection_error( + &self, + cond: Goal<'tcx, ty::Predicate<'tcx>>, + error: Goal<'tcx, ty::Predicate<'tcx>>, + ) -> bool { + if cond.param_env != error.param_env { + return false; + } + let Some(error) = error.predicate.as_projection_clause() else { + return false; + }; + + self.enter_forall(error, |error| { + if !error.projection_term.kind.is_trait_projection() { + return false; + } + let trait_pred = ty::TraitPredicate { + trait_ref: error.projection_term.trait_ref(self.tcx), + polarity: ty::PredicatePolarity::Positive, + }; + // Elaborating is what pairs a failing `C: FnMut(..)` with the + // `>::Output` projection resting on it. A supertrait can hold + // while `cond` fails though, so the projection is only covered if its own trait + // goal is unproven too, otherwise it failed for its own reasons. + elaborate(self.tcx, std::iter::once(cond.predicate)) + .filter_map(|implied| implied.as_trait_clause()) + .any(|implied| self.can_match_trait(cond.param_env, trait_pred, implied)) + && !self.predicate_must_hold_modulo_regions(&Obligation::new( + self.tcx, + ObligationCause::dummy(), + cond.param_env, + trait_pred, + )) + }) + } + #[instrument(level = "debug", skip_all)] pub(super) fn report_projection_error( &self, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 8bf5814b9fe13..bd272dee3b3ab 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -224,6 +224,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // We do this in 2 passes because we want to display errors in order, though // maybe it *is* better to sort errors by span or something. let mut is_suppressed = vec![false; errors.len()]; + // A failing trait goal also fails every projection goal resting on it. Ambiguity + // errors are exempt: they get merged into a single diagnostic whose notes list all + // the constraints the annotation has to satisfy, so their projections still say + // something the trait error doesn't. + let covered_by_trait_error = + |cond: &ErrorDescriptor<'tcx>, error: &ErrorDescriptor<'tcx>| { + let is_definite = |error: &ErrorDescriptor<'tcx>| { + error.index.is_some_and(|index| { + !matches!(errors[index].code, FulfillmentErrorCode::Ambiguity { .. }) + }) + }; + is_definite(cond) + && is_definite(error) + && self.trait_error_implies_projection_error(cond.goal, error.goal) + }; for (_, error_set) in error_map.iter() { // We want to suppress "duplicate" errors with the same span. for error in error_set { @@ -239,9 +254,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { continue; } - if self.error_implies(error2.goal, error.goal) + if (self.error_implies(error2.goal, error.goal) && !(error2.index >= error.index - && self.error_implies(error.goal, error2.goal)) + && self.error_implies(error.goal, error2.goal))) + || covered_by_trait_error(error2, error) { info!("skipping {:?} (implied by {:?})", error, error2); is_suppressed[index] = true; diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed index b1158e1cbffa7..1ff52c9e5a38a 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed @@ -6,9 +6,7 @@ fn main() { let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //[current]~^ ERROR type mismatch in closure arguments //[next]~^^ ERROR: expected an `FnMut(&{integer})` closure, found - //[next]~| ERROR: type mismatch resolving `<{closure@closure-arg-type-mismatch-issue-45727.rs:6:29} as FnOnce<(&{integer},)>>::Output == bool` let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //[current]~^ ERROR type mismatch in closure arguments //[next]~^^ ERROR: expected an `FnMut(&{integer})` closure, found - //[next]~| ERROR: type mismatch resolving `<{closure@closure-arg-type-mismatch-issue-45727.rs:10:29} as FnOnce<(&{integer},)>>::Output == bool` } diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.stderr index a6ba644f3a44a..c35d70a635cbd 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.stderr +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.stderr @@ -16,7 +16,7 @@ LL | let _ = (-10..=10).find(|x: &i32| x.signum() == 0); | + error[E0631]: type mismatch in closure arguments - --> $DIR/closure-arg-type-mismatch-issue-45727.rs:10:24 + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:24 | LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); | ^^^^ ----------- found signature defined here diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr index 2c51d1e9aec4d..baeff76e1ffe2 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr @@ -12,45 +12,20 @@ LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0); note: required by a bound in `find` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL -error[E0271]: type mismatch resolving `<{closure@closure-arg-type-mismatch-issue-45727.rs:6:29} as FnOnce<(&{integer},)>>::Output == bool` - --> $DIR/closure-arg-type-mismatch-issue-45727.rs:6:38 - | -LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0); - | ---- -------- ^^^^^^^^^^^^^^^ types differ - | | | - | | this closure - | required by a bound introduced by this call - | -note: required by a bound in `find` - --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL - -error[E0277]: expected an `FnMut(&{integer})` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:10:29: 10:40}` - --> $DIR/closure-arg-type-mismatch-issue-45727.rs:10:29 +error[E0277]: expected an `FnMut(&{integer})` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}` + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:29 | LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); - | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnMut(&{integer})` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:10:29: 10:40}` + | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnMut(&{integer})` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}` | | | required by a bound introduced by this call | - = help: the trait `for<'a> FnMut(&'a {integer})` is not implemented for closure `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:10:29: 10:40}` + = help: the trait `for<'a> FnMut(&'a {integer})` is not implemented for closure `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}` = note: expected a closure with signature `for<'a> fn(&'a {integer})` found a closure with signature `fn(&&&i32)` note: required by a bound in `find` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL -error[E0271]: type mismatch resolving `<{closure@closure-arg-type-mismatch-issue-45727.rs:10:29} as FnOnce<(&{integer},)>>::Output == bool` - --> $DIR/closure-arg-type-mismatch-issue-45727.rs:10:41 - | -LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); - | ---- ----------- ^^^^^^^^^^^^^^^ types differ - | | | - | | this closure - | required by a bound introduced by this call - | -note: required by a bound in `find` - --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs index 09f7af7c0253e..0a0abfafc45a2 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs @@ -6,9 +6,7 @@ fn main() { let _ = (-10..=10).find(|x: i32| x.signum() == 0); //[current]~^ ERROR type mismatch in closure arguments //[next]~^^ ERROR: expected an `FnMut(&{integer})` closure, found - //[next]~| ERROR: type mismatch resolving `<{closure@closure-arg-type-mismatch-issue-45727.rs:6:29} as FnOnce<(&{integer},)>>::Output == bool` let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); //[current]~^ ERROR type mismatch in closure arguments //[next]~^^ ERROR: expected an `FnMut(&{integer})` closure, found - //[next]~| ERROR: type mismatch resolving `<{closure@closure-arg-type-mismatch-issue-45727.rs:10:29} as FnOnce<(&{integer},)>>::Output == bool` } diff --git a/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.rs b/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.rs index a0d1db3ff02b3..b53d30e5f5c9c 100644 --- a/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.rs +++ b/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.rs @@ -8,7 +8,6 @@ const fn with_positive [const] Fn(&'a ())>() {} const _: () = { with_positive::<()>(); //~^ ERROR expected an `Fn(&'a ())` closure, found `()` - //~| ERROR type mismatch resolving `<() as FnOnce<(&(),)>>::Output == ()` }; fn main() {} diff --git a/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.stderr b/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.stderr index 7b98ba618a727..3b1126e253abd 100644 --- a/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.stderr +++ b/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.stderr @@ -11,19 +11,6 @@ note: required by a bound in `with_positive` LL | const fn with_positive [const] Fn(&'a ())>() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `with_positive` -error[E0271]: type mismatch resolving `<() as FnOnce<(&(),)>>::Output == ()` - --> $DIR/const-host-effect-hrtb-no-ice.rs:9:21 - | -LL | with_positive::<()>(); - | ^^ types differ - | -note: required by a bound in `with_positive` - --> $DIR/const-host-effect-hrtb-no-ice.rs:6:43 - | -LL | const fn with_positive [const] Fn(&'a ())>() {} - | ^^^^^^^^^^ required by this bound in `with_positive` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/diagnostics/dont-suppress-independent-projection-error.current.stderr b/tests/ui/traits/next-solver/diagnostics/dont-suppress-independent-projection-error.current.stderr new file mode 100644 index 0000000000000..546a069bb93ab --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/dont-suppress-independent-projection-error.current.stderr @@ -0,0 +1,53 @@ +error[E0277]: the trait bound `S: Sub` is not satisfied + --> $DIR/dont-suppress-independent-projection-error.rs:28:7 + | +LL | f(S); + | - ^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | +help: the trait `Sub` is not implemented for `S` + --> $DIR/dont-suppress-independent-projection-error.rs:14:1 + | +LL | struct S; + | ^^^^^^^^ +help: this trait has no implementations, consider adding one + --> $DIR/dont-suppress-independent-projection-error.rs:12:1 + | +LL | trait Sub: Super {} + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `f` + --> $DIR/dont-suppress-independent-projection-error.rs:22:8 + | +LL | fn f(_: T) + | - required by a bound in this function +LL | where +LL | T: Sub, + | ^^^ required by this bound in `f` + +error[E0271]: type mismatch resolving `::Assoc == u32` + --> $DIR/dont-suppress-independent-projection-error.rs:28:7 + | +LL | f(S); + | - ^ type mismatch resolving `::Assoc == u32` + | | + | required by a bound introduced by this call + | +note: expected this to be `u32` + --> $DIR/dont-suppress-independent-projection-error.rs:17:18 + | +LL | type Assoc = u8; + | ^^ +note: required by a bound in `f` + --> $DIR/dont-suppress-independent-projection-error.rs:23:14 + | +LL | fn f(_: T) + | - required by a bound in this function +... +LL | T: Super, + | ^^^^^^^^^^^ required by this bound in `f` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/diagnostics/dont-suppress-independent-projection-error.next.stderr b/tests/ui/traits/next-solver/diagnostics/dont-suppress-independent-projection-error.next.stderr new file mode 100644 index 0000000000000..546a069bb93ab --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/dont-suppress-independent-projection-error.next.stderr @@ -0,0 +1,53 @@ +error[E0277]: the trait bound `S: Sub` is not satisfied + --> $DIR/dont-suppress-independent-projection-error.rs:28:7 + | +LL | f(S); + | - ^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | +help: the trait `Sub` is not implemented for `S` + --> $DIR/dont-suppress-independent-projection-error.rs:14:1 + | +LL | struct S; + | ^^^^^^^^ +help: this trait has no implementations, consider adding one + --> $DIR/dont-suppress-independent-projection-error.rs:12:1 + | +LL | trait Sub: Super {} + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `f` + --> $DIR/dont-suppress-independent-projection-error.rs:22:8 + | +LL | fn f(_: T) + | - required by a bound in this function +LL | where +LL | T: Sub, + | ^^^ required by this bound in `f` + +error[E0271]: type mismatch resolving `::Assoc == u32` + --> $DIR/dont-suppress-independent-projection-error.rs:28:7 + | +LL | f(S); + | - ^ type mismatch resolving `::Assoc == u32` + | | + | required by a bound introduced by this call + | +note: expected this to be `u32` + --> $DIR/dont-suppress-independent-projection-error.rs:17:18 + | +LL | type Assoc = u8; + | ^^ +note: required by a bound in `f` + --> $DIR/dont-suppress-independent-projection-error.rs:23:14 + | +LL | fn f(_: T) + | - required by a bound in this function +... +LL | T: Super, + | ^^^^^^^^^^^ required by this bound in `f` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/diagnostics/dont-suppress-independent-projection-error.rs b/tests/ui/traits/next-solver/diagnostics/dont-suppress-independent-projection-error.rs new file mode 100644 index 0000000000000..2209597254da4 --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/dont-suppress-independent-projection-error.rs @@ -0,0 +1,31 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + +// A projection error is only redundant when the trait goal it rests on failed too. +// Here `S: Super` holds, so `::Assoc == u32` failed on its own and has to +// be reported even though the `S: Sub` error at the same span elaborates to `S: Super`. + +trait Super { + type Assoc; +} +trait Sub: Super {} + +struct S; + +impl Super for S { + type Assoc = u8; +} + +fn f(_: T) +where + T: Sub, + T: Super, +{ +} + +fn main() { + f(S); + //~^ ERROR the trait bound `S: Sub` is not satisfied + //~| ERROR type mismatch resolving `::Assoc == u32` +} diff --git a/tests/ui/traits/next-solver/diagnostics/iterator-item-suggest-no-ice.rs b/tests/ui/traits/next-solver/diagnostics/iterator-item-suggest-no-ice.rs index 89a37d8c75a31..1d17909e26a92 100644 --- a/tests/ui/traits/next-solver/diagnostics/iterator-item-suggest-no-ice.rs +++ b/tests/ui/traits/next-solver/diagnostics/iterator-item-suggest-no-ice.rs @@ -15,7 +15,6 @@ trait FooMut { //~^ ERROR: cannot find value `_I` in this scope self.bar(collection); //~^ ERROR: `&'b _` is not an iterator - //~| ERROR: type mismatch resolving `<&_ as Iterator>::Item == &()` } } diff --git a/tests/ui/traits/next-solver/diagnostics/iterator-item-suggest-no-ice.stderr b/tests/ui/traits/next-solver/diagnostics/iterator-item-suggest-no-ice.stderr index 0bd604d03fdf2..7f160b1b7e951 100644 --- a/tests/ui/traits/next-solver/diagnostics/iterator-item-suggest-no-ice.stderr +++ b/tests/ui/traits/next-solver/diagnostics/iterator-item-suggest-no-ice.stderr @@ -40,32 +40,7 @@ LL | where LL | for<'b> &'b I: Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `FooMut::bar` -error[E0271]: type mismatch resolving `<&_ as Iterator>::Item == &()` - --> $DIR/iterator-item-suggest-no-ice.rs:16:18 - | -LL | self.bar(collection); - | --- ^^^^^^^^^^ types differ - | | - | required by a bound introduced by this call - | -note: the method call chain might not have had the expected associated types - --> $DIR/iterator-item-suggest-no-ice.rs:14:35 - | -LL | let collection = vec![_I].iter().map(|x| ()); - | -------- ^^^^^^ ----------- `Iterator::Item` remains `<{type error} as Iterator>::Item` here - | | | - | | `Iterator::Item` is `<{type error} as Iterator>::Item` here - | this expression has type `Vec<{type error}>` -note: required by a bound in `FooMut::bar` - --> $DIR/iterator-item-suggest-no-ice.rs:7:33 - | -LL | fn bar(&self, _: I) - | --- required by a bound in this associated function -LL | where -LL | for<'b> &'b I: Iterator; - | ^^^^^^^^^^^^^ required by this bound in `FooMut::bar` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0271, E0277, E0425, E0428. -For more information about an error, try `rustc --explain E0271`. +Some errors have detailed explanations: E0277, E0425, E0428. +For more information about an error, try `rustc --explain E0277`.