Skip to content

Add a diagnostic for similarly named traits #144674

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
span,
leaf_trait_predicate,
);
self.note_version_mismatch(&mut err, leaf_trait_predicate);
self.note_version_mismatch(&mut err, &obligation, leaf_trait_predicate);
self.suggest_remove_await(&obligation, &mut err);
self.suggest_derive(&obligation, &mut err, leaf_trait_predicate);

Expand Down Expand Up @@ -2346,6 +2346,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
fn note_version_mismatch(
&self,
err: &mut Diag<'_>,
obligation: &PredicateObligation<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool {
let get_trait_impls = |trait_def_id| {
Expand All @@ -2372,6 +2373,49 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let traits_with_same_path =
traits_with_same_path.into_items().into_sorted_stable_ord_by_key(|(p, _)| p);
let mut suggested = false;
let trait_def_id = trait_pred.def_id();
let trait_has_same_params = |other_trait_def_id: DefId| -> bool {
let trait_generics = self.tcx.generics_of(trait_def_id);
let other_trait_generics = self.tcx.generics_of(other_trait_def_id);

if trait_generics.count() != other_trait_generics.count() {
return false;
}
trait_generics.own_params.iter().zip(other_trait_generics.own_params.iter()).all(
|(a, b)| {
(matches!(a.kind, ty::GenericParamDefKind::Type { .. })
&& matches!(b.kind, ty::GenericParamDefKind::Type { .. }))
|| (matches!(a.kind, ty::GenericParamDefKind::Lifetime,)
&& matches!(b.kind, ty::GenericParamDefKind::Lifetime))
|| (matches!(a.kind, ty::GenericParamDefKind::Const { .. })
&& matches!(b.kind, ty::GenericParamDefKind::Const { .. }))
},
)
};

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)
&& trait_has_same_params(*def_id)
&& self.predicate_must_hold_modulo_regions(&Obligation::new(
self.tcx,
obligation.cause.clone(),
obligation.param_env,
trait_pred.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_pred.self_ty(),
self.tcx.def_path_str(other_trait_def_id),
trait_pred.print_modifiers_and_trait_path()
));
suggested = true;
}
for (_, trait_with_same_path) in traits_with_same_path {
let trait_impls = get_trait_impls(trait_with_same_path);
if trait_impls.is_empty() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ error[E0277]: the trait bound `foo::Struct: Trait` is not satisfied
13 | check_trait::<foo::Struct>();
| ^^^^^^^^^^^ 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
|
Expand Down
2 changes: 2 additions & 0 deletions tests/run-make/crate-loading/multiple-dep-versions.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand Down Expand Up @@ -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`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"there are multiple different versions of crate dependency in the dependency graph" is a simply more specific message than "OtherType implements similarly named dependency::Trait, but not Trait", is it not?

I personally really don#t think we should be emitting the new msg if we already detected that there are two different versions of the same crate

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about it, it might be confusing and the message might not be helpful in such a case, indeed. I am going to fix it.

note: there are multiple different versions of crate `dependency` in the dependency graph
--> replaced
|
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/traits/bound/same-crate-name.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ LL | a::try_foo(foo);
| |
| required by a bound introduced by this call
|
= note: `Foo` implements similarly named `main::a::Bar`, but not `main::a::Bar`
help: trait impl with same name found
--> $DIR/auxiliary/crate_a2.rs:5:1
|
Expand Down Expand Up @@ -42,6 +43,7 @@ LL | a::try_foo(other_variant_implements_mismatched_trait);
| |
| required by a bound introduced by this call
|
= note: `ImplementsWrongTraitConditionally<isize>` implements similarly named `main::a::Bar`, but not `main::a::Bar`
help: trait impl with same name found
--> $DIR/auxiliary/crate_a2.rs:13:1
|
Expand Down
27 changes: 27 additions & 0 deletions tests/ui/traits/similarly_named_trait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
trait Trait {} //~ HELP this trait has no implementations, consider adding one
trait TraitWithParam<T> {} //~ HELP this trait has no implementations, consider adding one

mod m {
pub trait Trait {}
pub trait TraitWithParam<T> {}
pub struct St;
impl Trait for St {}
impl<T> TraitWithParam<T> for St {}
}

fn func<T: Trait>(_: T) {} //~ NOTE required by a bound in `func`
//~^ NOTE required by this bound in `func`

fn func2<T: TraitWithParam<T>> (_: 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<St>` is not satisfied
//~^ NOTE the trait `TraitWithParam<St>` is not implemented for `St`
//~| NOTE required by a bound introduced by this call
//~| NOTE `St` implements similarly named `m::TraitWithParam`, but not `TraitWithParam<St>`
}
43 changes: 43 additions & 0 deletions tests/ui/traits/similarly_named_trait.stderr
Original file line number Diff line number Diff line change
@@ -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: Trait>(_: T) {}
| ^^^^^ required by this bound in `func`

error[E0277]: the trait bound `St: TraitWithParam<St>` is not satisfied
--> $DIR/similarly_named_trait.rs:23:11
|
LL | func2(m::St);
| ----- ^^^^^ the trait `TraitWithParam<St>` is not implemented for `St`
| |
| required by a bound introduced by this call
|
= note: `St` implements similarly named `m::TraitWithParam`, but not `TraitWithParam<St>`
help: this trait has no implementations, consider adding one
--> $DIR/similarly_named_trait.rs:2:1
|
LL | trait TraitWithParam<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `func2`
--> $DIR/similarly_named_trait.rs:15:13
|
LL | fn func2<T: TraitWithParam<T>> (_: T) {}
| ^^^^^^^^^^^^^^^^^ required by this bound in `func2`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0277`.
1 change: 1 addition & 0 deletions tests/ui/union/issue-81199.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ error[E0277]: the trait bound `T: Pointee` is not satisfied
LL | components: PtrComponents<T>,
| ^^^^^^^^^^^^^^^^ 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
|
Expand Down
Loading