diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index c7b3b5415492b..9625b91df9134 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -102,7 +102,7 @@ impl GenericParamDef { } } -#[derive(Default)] +#[derive(Default, PartialEq)] pub struct GenericParamCount { pub lifetimes: usize, pub types: usize, 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 62859329de356..ba442bb725255 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 @@ -498,6 +498,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 bc8c8a444058d..e8633cd98a7fd 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -5127,6 +5127,45 @@ 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); + + // Ensure that the current trait and the other_trait have the same number of args and each arg + // has the same kind + let trait_has_same_params = |other_trait_def_id: DefId| -> bool { + self.tcx.generics_of(trait_def_id).own_counts() + == self.tcx.generics_of(other_trait_def_id).own_counts() + }; + + 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) + && trait_has_same_params(*def_id) + && self.predicate_must_hold_modulo_regions(&Obligation::new( + self.tcx, + obligation.cause.clone(), + obligation.param_env, + trait_predicate.map_bound(|tr| ty::TraitPredicate { + trait_ref: ty::TraitRef::new(self.tcx, *def_id, tr.trait_ref.args), + ..tr + }), + )) + }) { + 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..e49c6df97b505 --- /dev/null +++ b/tests/ui/traits/similarly_named_trait.rs @@ -0,0 +1,27 @@ +trait Trait {} //~ HELP this trait has no implementations, consider adding one +trait TraitWithParam {} //~ HELP this trait has no implementations, consider adding one + +mod m { + pub trait Trait {} + pub trait TraitWithParam {} + pub struct St; + impl Trait for St {} + impl TraitWithParam for St {} +} + +fn func(_: T) {} //~ NOTE required by a bound in `func` +//~^ NOTE required by this bound in `func` + +fn func2> (_: T) {} //~ NOTE required by a bound in `func2` +//~^ NOTE required by this bound in `func2` + +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` + func2(m::St); //~ ERROR the trait bound `St: TraitWithParam` is not satisfied + //~^ NOTE the trait `TraitWithParam` is not implemented for `St` + //~| NOTE required by a bound introduced by this call + //~| NOTE `St` implements similarly named `m::TraitWithParam`, but not `TraitWithParam` +} diff --git a/tests/ui/traits/similarly_named_trait.stderr b/tests/ui/traits/similarly_named_trait.stderr new file mode 100644 index 0000000000000..655ee34bbb981 --- /dev/null +++ b/tests/ui/traits/similarly_named_trait.stderr @@ -0,0 +1,43 @@ +error[E0277]: the trait bound `St: Trait` is not satisfied + --> $DIR/similarly_named_trait.rs:19: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:12:12 + | +LL | fn func(_: T) {} + | ^^^^^ required by this bound in `func` + +error[E0277]: the trait bound `St: TraitWithParam` is not satisfied + --> $DIR/similarly_named_trait.rs:23:11 + | +LL | func2(m::St); + | ----- ^^^^^ the trait `TraitWithParam` is not implemented for `St` + | | + | required by a bound introduced by this call + | + = note: `St` implements similarly named `m::TraitWithParam`, but not `TraitWithParam` +help: this trait has no implementations, consider adding one + --> $DIR/similarly_named_trait.rs:2:1 + | +LL | trait TraitWithParam {} + | ^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `func2` + --> $DIR/similarly_named_trait.rs:15:13 + | +LL | fn func2> (_: T) {} + | ^^^^^^^^^^^^^^^^^ required by this bound in `func2` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/union/issue-81199.stderr b/tests/ui/union/issue-81199.stderr index 7deba88fc803c..dbc4a0ab55346 100644 --- a/tests/ui/union/issue-81199.stderr +++ b/tests/ui/union/issue-81199.stderr @@ -16,6 +16,7 @@ error[E0277]: the trait bound `T: Pointee` is not satisfied LL | components: PtrComponents, | ^^^^^^^^^^^^^^^^ the trait `Pointee` is not implemented for `T` | + = note: `T` implements similarly named `std::ptr::Pointee`, but not `Pointee` note: required by a bound in `PtrComponents` --> $DIR/issue-81199.rs:11:25 |