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 1ac309da101f1..d1fe95fc1a68a 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 @@ -487,6 +487,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } + self.suggest_impl_similarly_named_trait(&mut err, &obligation, leaf_trait_predicate); + self.try_to_add_help_message( &root_obligation, &obligation, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index c182fd99b17bd..60fe835ceea5f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -5108,6 +5108,44 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => {} } } + pub(crate) fn suggest_impl_similarly_named_trait( + &self, + err: &mut Diag<'_>, + obligation: &PredicateObligation<'tcx>, + trait_predicate: ty::PolyTraitPredicate<'tcx>, + ) { + let trait_def_id = trait_predicate.def_id(); + let trait_name = self.tcx.item_name(trait_def_id); + if let Some(other_trait_def_id) = self.tcx.all_traits_including_private().find(|def_id| { + trait_def_id != *def_id + && trait_name == self.tcx.item_name(def_id) + && self + .tcx + .all_impls(*def_id) + .find(|impl_def_id| { + let Some(trait_ref) = self.tcx.impl_trait_ref(impl_def_id) else { + return false; + }; + self.predicate_must_hold_modulo_regions(&Obligation::new( + self.tcx, + obligation.cause.clone(), + obligation.param_env, + trait_ref + .skip_binder() + .with_self_ty(self.tcx, trait_predicate.skip_binder().self_ty()), + )) + }) + .is_some() + }) { + err.note(format!( + "`{}` implements similarly named `{}`, but not `{}`", + trait_predicate.self_ty(), + self.tcx.def_path_str(other_trait_def_id), + trait_predicate.print_modifiers_and_trait_path() + )); + } + () + } } /// Add a hint to add a missing borrow or remove an unnecessary one. diff --git a/tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr b/tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr index 9433a0ba00e80..989a046675aff 100644 --- a/tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr +++ b/tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr @@ -4,6 +4,7 @@ error[E0277]: the trait bound `foo::Struct: Trait` is not satisfied 13 | check_trait::(); | ^^^^^^^^^^^ the trait `Trait` is not implemented for `foo::Struct` | + = note: `foo::Struct` implements similarly named `foo::Trait`, but not `Trait` note: there are multiple different versions of crate `foo` in the dependency graph --> foo-current.rs:7:1 | diff --git a/tests/run-make/crate-loading/multiple-dep-versions.stderr b/tests/run-make/crate-loading/multiple-dep-versions.stderr index dea08bb96c979..ddfbf16a586c0 100644 --- a/tests/run-make/crate-loading/multiple-dep-versions.stderr +++ b/tests/run-make/crate-loading/multiple-dep-versions.stderr @@ -6,6 +6,7 @@ LL | do_something(Type); | | | required by a bound introduced by this call | + = note: `dep_2_reexport::Type` implements similarly named `dependency::Trait`, but not `Trait` note: there are multiple different versions of crate `dependency` in the dependency graph --> replaced | @@ -92,6 +93,7 @@ LL | do_something(OtherType); | | | required by a bound introduced by this call | + = note: `OtherType` implements similarly named `dependency::Trait`, but not `Trait` note: there are multiple different versions of crate `dependency` in the dependency graph --> replaced | diff --git a/tests/ui/traits/bound/same-crate-name.stderr b/tests/ui/traits/bound/same-crate-name.stderr index 71a8159fd8906..db293612ce711 100644 --- a/tests/ui/traits/bound/same-crate-name.stderr +++ b/tests/ui/traits/bound/same-crate-name.stderr @@ -12,6 +12,7 @@ help: trait impl with same name found LL | impl Bar for Foo {} | ^^^^^^^^^^^^^^^^ = note: perhaps two different versions of crate `crate_a2` are being used? + = note: `Foo` implements similarly named `main::a::Bar`, but not `main::a::Bar` = help: the trait `main::a::Bar` is implemented for `ImplementsTraitForUsize` note: required by a bound in `try_foo` --> $DIR/auxiliary/crate_a1.rs:3:24 @@ -48,6 +49,7 @@ help: trait impl with same name found LL | impl Bar for ImplementsWrongTraitConditionally {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: perhaps two different versions of crate `crate_a2` are being used? + = note: `ImplementsWrongTraitConditionally` implements similarly named `main::a::Bar`, but not `main::a::Bar` = help: the trait `main::a::Bar` is implemented for `ImplementsTraitForUsize` note: required by a bound in `try_foo` --> $DIR/auxiliary/crate_a1.rs:3:24 diff --git a/tests/ui/traits/similarly_named_trait.rs b/tests/ui/traits/similarly_named_trait.rs new file mode 100644 index 0000000000000..6d5882740bc71 --- /dev/null +++ b/tests/ui/traits/similarly_named_trait.rs @@ -0,0 +1,17 @@ +trait Trait {} //~ HELP this trait has no implementations, consider adding one + +mod m { + pub trait Trait {} + pub struct St; + impl Trait for St {} +} + +fn func(_: T) {} //~ NOTE required by a bound in `func` +//~^ NOTE required by this bound in `func` + +fn main() { + func(m::St); //~ ERROR the trait bound `St: Trait` is not satisfied + //~^ NOTE the trait `Trait` is not implemented for `St` + //~| NOTE required by a bound introduced by this call + //~| NOTE `St` implements similarly named `m::Trait`, but not `Trait` +} diff --git a/tests/ui/traits/similarly_named_trait.stderr b/tests/ui/traits/similarly_named_trait.stderr new file mode 100644 index 0000000000000..27c55da77dc10 --- /dev/null +++ b/tests/ui/traits/similarly_named_trait.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `St: Trait` is not satisfied + --> $DIR/similarly_named_trait.rs:13:10 + | +LL | func(m::St); + | ---- ^^^^^ the trait `Trait` is not implemented for `St` + | | + | required by a bound introduced by this call + | + = note: `St` implements similarly named `m::Trait`, but not `Trait` +help: this trait has no implementations, consider adding one + --> $DIR/similarly_named_trait.rs:1:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^ +note: required by a bound in `func` + --> $DIR/similarly_named_trait.rs:9:12 + | +LL | fn func(_: T) {} + | ^^^^^ required by this bound in `func` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.