From 7c7dc226d56d11d23644b3f1d5fb5be1a6145ec8 Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Wed, 23 Jul 2025 12:44:27 +0200 Subject: [PATCH] Add a note when a type implements a trait with the same name as the required one This is useful when you have two dependencies that use different trait for the same thing and with the same name. The user can accidentally implement the bad one which might be confusing. This commits refactorizes existing diagnostics about multiple different crates with the same version and adds a note when similarly named traits are found. Both diagnostics are merged into a single function. --- .../rustc_hir_typeck/src/method/suggest.rs | 53 +--- .../traits/fulfillment_errors.rs | 249 ++++++++---------- .../src/error_reporting/traits/mod.rs | 2 +- .../foo.stderr | 12 +- .../multiple-dep-versions.stderr | 51 +--- .../run-make/duplicate-dependency/main.stderr | 2 +- tests/ui/traits/bound/same-crate-name.rs | 6 +- tests/ui/traits/bound/same-crate-name.stderr | 52 +++- tests/ui/traits/similarly_named_trait.rs | 28 ++ tests/ui/traits/similarly_named_trait.stderr | 53 ++++ tests/ui/union/issue-81199.stderr | 1 + 11 files changed, 263 insertions(+), 246 deletions(-) create mode 100644 tests/ui/traits/similarly_named_trait.rs create mode 100644 tests/ui/traits/similarly_named_trait.stderr diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 44602e6289940..7f85a2ad839bf 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -4089,7 +4089,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err: &mut Diag<'_>, item_def_id: DefId, hir_id: hir::HirId, - rcvr_ty: Option>, + rcvr_ty: Option>, ) -> bool { let hir_id = self.tcx.parent_hir_id(hir_id); let Some(traits) = self.tcx.in_scope_traits(hir_id) else { return false }; @@ -4100,49 +4100,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !self.tcx.is_trait(trait_def_id) { return false; } - let krate = self.tcx.crate_name(trait_def_id.krate); - let name = self.tcx.item_name(trait_def_id); - let candidates: Vec<_> = traits - .iter() - .filter(|c| { - c.def_id.krate != trait_def_id.krate - && self.tcx.crate_name(c.def_id.krate) == krate - && self.tcx.item_name(c.def_id) == name - }) - .map(|c| (c.def_id, c.import_ids.get(0).cloned())) - .collect(); - if candidates.is_empty() { + let hir::Node::Expr(rcvr) = self.tcx.hir_node(hir_id) else { return false; - } - let item_span = self.tcx.def_span(item_def_id); - let msg = format!( - "there are multiple different versions of crate `{krate}` in the dependency graph", - ); - let trait_span = self.tcx.def_span(trait_def_id); - let mut multi_span: MultiSpan = trait_span.into(); - multi_span.push_span_label(trait_span, "this is the trait that is needed".to_string()); - let descr = self.tcx.associated_item(item_def_id).descr(); - let rcvr_ty = - rcvr_ty.map(|t| format!("`{t}`")).unwrap_or_else(|| "the receiver".to_string()); - multi_span - .push_span_label(item_span, format!("the {descr} is available for {rcvr_ty} here")); - for (def_id, import_def_id) in candidates { - if let Some(import_def_id) = import_def_id { - multi_span.push_span_label( - self.tcx.def_span(import_def_id), - format!( - "`{name}` imported here doesn't correspond to the right version of crate \ - `{krate}`", - ), - ); - } - multi_span.push_span_label( - self.tcx.def_span(def_id), - "this is the trait that was imported".to_string(), - ); - } - err.span_note(multi_span, msg); - true + }; + let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, rcvr_ty.into_iter()); + let trait_pred = ty::Binder::dummy(ty::TraitPredicate { + trait_ref, + polarity: ty::PredicatePolarity::Positive, + }); + let obligation = Obligation::new(self.tcx, self.misc(rcvr.span), self.param_env, trait_ref); + self.err_ctxt().note_different_trait_with_same_name(err, &obligation, trait_pred) } /// issue #102320, for `unwrap_or` with closure as argument, suggest `unwrap_or_else` 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 4305d4160ebf5..a1eace22fcbc8 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 @@ -467,7 +467,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span, leaf_trait_predicate, ); - self.note_trait_version_mismatch(&mut err, leaf_trait_predicate); + self.note_different_trait_with_same_name(&mut err, &obligation, leaf_trait_predicate); self.note_adt_version_mismatch(&mut err, leaf_trait_predicate); self.suggest_remove_await(&obligation, &mut err); self.suggest_derive(&obligation, &mut err, leaf_trait_predicate); @@ -1949,115 +1949,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { impl_candidates }; - // We'll check for the case where the reason for the mismatch is that the trait comes from - // one crate version and the type comes from another crate version, even though they both - // are from the same crate. - let trait_def_id = trait_pred.def_id(); - let trait_name = self.tcx.item_name(trait_def_id); - let crate_name = self.tcx.crate_name(trait_def_id.krate); - if let Some(other_trait_def_id) = self.tcx.all_traits_including_private().find(|def_id| { - trait_name == self.tcx.item_name(trait_def_id) - && trait_def_id.krate != def_id.krate - && crate_name == self.tcx.crate_name(def_id.krate) - }) { - // We've found two different traits with the same name, same crate name, but - // different crate `DefId`. We highlight the traits. - - let found_type = - if let ty::Adt(def, _) = trait_pred.self_ty().skip_binder().peel_refs().kind() { - Some(def.did()) - } else { - None - }; - let candidates = if impl_candidates.is_empty() { - alternative_candidates(trait_def_id) - } else { - impl_candidates.into_iter().map(|cand| cand.trait_ref).collect() - }; - let mut span: MultiSpan = self.tcx.def_span(trait_def_id).into(); - span.push_span_label(self.tcx.def_span(trait_def_id), "this is the required trait"); - for (sp, label) in [trait_def_id, other_trait_def_id] - .iter() - // The current crate-version might depend on another version of the same crate - // (Think "semver-trick"). Do not call `extern_crate` in that case for the local - // crate as that doesn't make sense and ICEs (#133563). - .filter(|def_id| !def_id.is_local()) - .filter_map(|def_id| self.tcx.extern_crate(def_id.krate)) - .map(|data| { - let dependency = if data.dependency_of == LOCAL_CRATE { - "direct dependency of the current crate".to_string() - } else { - let dep = self.tcx.crate_name(data.dependency_of); - format!("dependency of crate `{dep}`") - }; - ( - data.span, - format!("one version of crate `{crate_name}` used here, as a {dependency}"), - ) - }) - { - span.push_span_label(sp, label); - } - let mut points_at_type = false; - if let Some(found_type) = found_type { - span.push_span_label( - self.tcx.def_span(found_type), - "this type doesn't implement the required trait", - ); - for trait_ref in candidates { - if let ty::Adt(def, _) = trait_ref.self_ty().peel_refs().kind() - && let candidate_def_id = def.did() - && let Some(name) = self.tcx.opt_item_name(candidate_def_id) - && let Some(found) = self.tcx.opt_item_name(found_type) - && name == found - && candidate_def_id.krate != found_type.krate - && self.tcx.crate_name(candidate_def_id.krate) - == self.tcx.crate_name(found_type.krate) - { - // A candidate was found of an item with the same name, from two separate - // versions of the same crate, let's clarify. - let candidate_span = self.tcx.def_span(candidate_def_id); - span.push_span_label( - candidate_span, - "this type implements the required trait", - ); - points_at_type = true; - } - } - } - span.push_span_label(self.tcx.def_span(other_trait_def_id), "this is the found trait"); - err.highlighted_span_note( - span, - vec![ - StringPart::normal("there are ".to_string()), - StringPart::highlighted("multiple different versions".to_string()), - StringPart::normal(" of crate `".to_string()), - StringPart::highlighted(format!("{crate_name}")), - StringPart::normal("` in the dependency graph".to_string()), - ], - ); - if points_at_type { - // We only clarify that the same type from different crate versions are not the - // same when we *find* the same type coming from different crate versions, otherwise - // it could be that it was a type provided by a different crate than the one that - // provides the trait, and mentioning this adds verbosity without clarification. - err.highlighted_note(vec![ - StringPart::normal( - "two types coming from two different versions of the same crate are \ - different types " - .to_string(), - ), - StringPart::highlighted("even if they look the same".to_string()), - ]); - } - err.highlighted_help(vec![ - StringPart::normal("you can use `".to_string()), - StringPart::highlighted("cargo tree".to_string()), - StringPart::normal("` to explore your dependency tree".to_string()), - ]); - return true; - } - if let [single] = &impl_candidates { // If we have a single implementation, try to unify it with the trait ref // that failed. This should uncover a better hint for what *is* implemented. @@ -2422,10 +2313,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait - /// with the same path as `trait_ref`, a help message about - /// a probable version mismatch is added to `err` - fn note_trait_version_mismatch( + fn check_same_trait_different_version( &self, err: &mut Diag<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, @@ -2442,40 +2330,69 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_impls }; + let krate = self.tcx.crate_name(trait_pred.def_id().krate); + let name = self.tcx.item_name(trait_pred.def_id()); let required_trait_path = self.tcx.def_path_str(trait_pred.def_id()); let traits_with_same_path: UnordSet<_> = self .tcx .visible_traits() - .filter(|trait_def_id| *trait_def_id != trait_pred.def_id()) + .filter(|trait_def_id| { + trait_def_id.krate != trait_pred.def_id().krate + && (self.tcx.def_path_str(trait_def_id) == required_trait_path + || self.tcx.crate_name(trait_def_id.krate) == krate + && self.tcx.item_name(trait_def_id) == name) + }) .map(|trait_def_id| (self.tcx.def_path_str(trait_def_id), trait_def_id)) - .filter(|(p, _)| *p == required_trait_path) .collect(); let traits_with_same_path = traits_with_same_path.into_items().into_sorted_stable_ord_by_key(|(p, _)| p); let mut suggested = false; - 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() { - continue; - } - let impl_spans: Vec<_> = - trait_impls.iter().map(|impl_def_id| self.tcx.def_span(*impl_def_id)).collect(); - err.span_help( - impl_spans, - format!("trait impl{} with same name found", pluralize!(trait_impls.len())), + let mut trait_is_impl = false; + + if !traits_with_same_path.is_empty() { + let mut span: MultiSpan = self.tcx.def_span(trait_pred.def_id()).into(); + span.push_span_label( + self.tcx.def_span(trait_pred.def_id()), + "this is the required trait", ); - self.note_two_crate_versions(trait_with_same_path, err); 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() { + continue; + } + + for candidate_def_id in trait_impls { + let Some(impl_trait_header) = self.tcx.impl_trait_header(candidate_def_id) + else { + continue; + }; + let candidate_span = + self.tcx.def_span(impl_trait_header.trait_ref.skip_binder().def_id); + span.push_span_label(candidate_span, "this is the implemented trait"); + trait_is_impl = true; + } + } + if !trait_is_impl { + for (_, def_id) in traits_with_same_path { + span.push_span_label( + self.tcx.def_span(def_id), + "this is the trait that was imported", + ); + } + } + self.note_two_crate_versions(trait_pred.def_id(), span, err); } suggested } - fn note_two_crate_versions(&self, did: DefId, err: &mut Diag<'_>) { + fn note_two_crate_versions(&self, did: DefId, sp: impl Into, err: &mut Diag<'_>) { let crate_name = self.tcx.crate_name(did.krate); - let crate_msg = - format!("perhaps two different versions of crate `{crate_name}` are being used?"); - err.note(crate_msg); + let crate_msg = format!( + "there are multiple different versions of crate `{crate_name}` in the dependency graph" + ); + err.span_note(sp, crate_msg); } fn note_adt_version_mismatch( @@ -2536,8 +2453,76 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { for (similar_item, _) in similar_items { err.span_help(self.tcx.def_span(similar_item), "item with same name found"); - self.note_two_crate_versions(similar_item, err); + self.note_two_crate_versions(similar_item, MultiSpan::new(), err); + } + } + + fn check_same_name_different_path( + &self, + err: &mut Diag<'_>, + obligation: &PredicateObligation<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> bool { + 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; + } + suggested + } + + /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait + /// with the same path as `trait_ref`, a help message about a multiple different + /// versions of the same crate is added to `err`. Otherwise if it implements another + /// trait with the same name, a note message about a similarly named trait is added to `err`. + pub fn note_different_trait_with_same_name( + &self, + err: &mut Diag<'_>, + obligation: &PredicateObligation<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> bool { + if self.check_same_trait_different_version(err, trait_pred) { + return true; } + self.check_same_name_different_path(err, obligation, trait_pred) } /// Add a `::` prefix when comparing paths so that paths with just one item 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 9052031ce4fd8..e2b99a0c76f63 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -1,6 +1,6 @@ pub mod ambiguity; pub mod call_kind; -mod fulfillment_errors; +pub mod fulfillment_errors; pub mod on_unimplemented; pub mod on_unimplemented_condition; pub mod on_unimplemented_format; 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..18ab39ecd587b 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 @@ -7,22 +7,14 @@ error[E0277]: the trait bound `foo::Struct: Trait` is not satisfied note: there are multiple different versions of crate `foo` in the dependency graph --> foo-current.rs:7:1 | - 4 | extern crate foo; - | ----------------- one version of crate `foo` used here, as a direct dependency of the current crate - 5 | - 6 | pub struct Struct; - | ----------------- this type implements the required trait 7 | pub trait Trait {} | ^^^^^^^^^^^^^^^ this is the required trait | ::: foo-prev.rs:X:Y | - 4 | pub struct Struct; - | ----------------- this type doesn't implement the required trait 5 | pub trait Trait {} - | --------------- this is the found trait - = note: two types coming from two different versions of the same crate are different types even if they look the same - = help: you can use `cargo tree` to explore your dependency tree + | --------------- this is the implemented trait + = help: the trait `Trait` is implemented for `Struct` note: required by a bound in `check_trait` --> foo-current.rs:10:19 | diff --git a/tests/run-make/crate-loading/multiple-dep-versions.stderr b/tests/run-make/crate-loading/multiple-dep-versions.stderr index dea08bb96c979..b631ec6016511 100644 --- a/tests/run-make/crate-loading/multiple-dep-versions.stderr +++ b/tests/run-make/crate-loading/multiple-dep-versions.stderr @@ -9,26 +9,14 @@ LL | do_something(Type); note: there are multiple different versions of crate `dependency` in the dependency graph --> replaced | -LL | pub struct Type(pub i32); - | --------------- this type implements the required trait LL | pub trait Trait { | ^^^^^^^^^^^^^^^ this is the required trait | ::: replaced | -LL | extern crate dep_2_reexport; - | ---------------------------- one version of crate `dependency` used here, as a dependency of crate `foo` -LL | extern crate dependency; - | ------------------------ one version of crate `dependency` used here, as a direct dependency of the current crate - | - ::: replaced - | -LL | pub struct Type; - | --------------- this type doesn't implement the required trait LL | pub trait Trait { - | --------------- this is the found trait - = note: two types coming from two different versions of the same crate are different types even if they look the same - = help: you can use `cargo tree` to explore your dependency tree + | --------------- this is the implemented trait + = help: the trait `Trait` is implemented for `dependency::Type` note: required by a bound in `do_something` --> replaced | @@ -45,14 +33,7 @@ note: there are multiple different versions of crate `dependency` in the depende --> replaced | LL | pub trait Trait { - | ^^^^^^^^^^^^^^^ this is the trait that is needed -LL | fn foo(&self); - | -------------- the method is available for `dep_2_reexport::Type` here - | - ::: replaced - | -LL | use dependency::{Trait, do_something, do_something_trait, do_something_type}; - | ----- `Trait` imported here doesn't correspond to the right version of crate `dependency` + | ^^^^^^^^^^^^^^^ this is the required trait | ::: replaced | @@ -69,15 +50,7 @@ note: there are multiple different versions of crate `dependency` in the depende --> replaced | LL | pub trait Trait { - | ^^^^^^^^^^^^^^^ this is the trait that is needed -LL | fn foo(&self); -LL | fn bar(); - | --------- the associated function is available for `dep_2_reexport::Type` here - | - ::: replaced - | -LL | use dependency::{Trait, do_something, do_something_trait, do_something_type}; - | ----- `Trait` imported here doesn't correspond to the right version of crate `dependency` + | ^^^^^^^^^^^^^^^ this is the required trait | ::: replaced | @@ -100,21 +73,9 @@ LL | pub trait Trait { | ::: replaced | -LL | extern crate dep_2_reexport; - | ---------------------------- one version of crate `dependency` used here, as a dependency of crate `foo` -LL | extern crate dependency; - | ------------------------ one version of crate `dependency` used here, as a direct dependency of the current crate - | - ::: replaced - | -LL | pub struct OtherType; - | -------------------- this type doesn't implement the required trait - | - ::: replaced - | LL | pub trait Trait { - | --------------- this is the found trait - = help: you can use `cargo tree` to explore your dependency tree + | --------------- this is the implemented trait + = help: the trait `Trait` is implemented for `dependency::Type` note: required by a bound in `do_something` --> replaced | diff --git a/tests/run-make/duplicate-dependency/main.stderr b/tests/run-make/duplicate-dependency/main.stderr index 36d54988788f4..7c43dc261e7b6 100644 --- a/tests/run-make/duplicate-dependency/main.stderr +++ b/tests/run-make/duplicate-dependency/main.stderr @@ -11,7 +11,7 @@ help: item with same name found | LL | pub struct Foo; | ^^^^^^^^^^^^^^ - = note: perhaps two different versions of crate `foo` are being used? + = note: there are multiple different versions of crate `foo` in the dependency graph = note: required for `Bar` to implement `Into` note: required by a bound in `into_foo` --> $DIR/re-export-foo.rs:3:25 diff --git a/tests/ui/traits/bound/same-crate-name.rs b/tests/ui/traits/bound/same-crate-name.rs index 395b963031a55..cdc8610b7eae3 100644 --- a/tests/ui/traits/bound/same-crate-name.rs +++ b/tests/ui/traits/bound/same-crate-name.rs @@ -32,13 +32,13 @@ fn main() { extern crate crate_a1 as a; a::try_foo(foo); //~^ ERROR E0277 - //~| HELP trait impl with same name found - //~| NOTE perhaps two different versions of crate `crate_a2` + //~| NOTE there are multiple different versions of crate `crate_a1` in the dependency graph // We don't want to see the "version mismatch" help message here // because `implements_no_traits` has no impl for `Foo` a::try_foo(implements_no_traits); //~^ ERROR E0277 + //~| NOTE there are multiple different versions of crate `crate_a1` in the dependency graph // We don't want to see the "version mismatch" help message here // because `other_variant_implements_mismatched_trait` @@ -46,6 +46,7 @@ fn main() { // only for its `` variant. a::try_foo(other_variant_implements_mismatched_trait); //~^ ERROR E0277 + //~| NOTE there are multiple different versions of crate `crate_a1` in the dependency graph // We don't want to see the "version mismatch" help message here // because `ImplementsTraitForUsize` only has @@ -53,5 +54,6 @@ fn main() { a::try_foo(other_variant_implements_correct_trait); //~^ ERROR E0277 //~| HELP the trait `main::a::Bar` is implemented for `ImplementsTraitForUsize` + //~| NOTE there are multiple different versions of crate `crate_a1` in the dependency graph } } diff --git a/tests/ui/traits/bound/same-crate-name.stderr b/tests/ui/traits/bound/same-crate-name.stderr index 71a8159fd8906..cafab863e9b02 100644 --- a/tests/ui/traits/bound/same-crate-name.stderr +++ b/tests/ui/traits/bound/same-crate-name.stderr @@ -6,12 +6,16 @@ LL | a::try_foo(foo); | | | required by a bound introduced by this call | -help: trait impl with same name found - --> $DIR/auxiliary/crate_a2.rs:5:1 +note: there are multiple different versions of crate `crate_a1` in the dependency graph + --> $DIR/auxiliary/crate_a1.rs:1:1 | -LL | impl Bar for Foo {} - | ^^^^^^^^^^^^^^^^ - = note: perhaps two different versions of crate `crate_a2` are being used? +LL | pub trait Bar {} + | ^^^^^^^^^^^^^ this is the required trait + | + ::: $DIR/auxiliary/crate_a2.rs:3:1 + | +LL | pub trait Bar {} + | ------------- this is the implemented trait = 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 @@ -20,13 +24,23 @@ LL | pub fn try_foo(x: impl Bar) {} | ^^^ required by this bound in `try_foo` error[E0277]: the trait bound `DoesNotImplementTrait: main::a::Bar` is not satisfied - --> $DIR/same-crate-name.rs:40:20 + --> $DIR/same-crate-name.rs:39:20 | LL | a::try_foo(implements_no_traits); | ---------- ^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `DoesNotImplementTrait` | | | required by a bound introduced by this call | +note: there are multiple different versions of crate `crate_a1` in the dependency graph + --> $DIR/auxiliary/crate_a1.rs:1:1 + | +LL | pub trait Bar {} + | ^^^^^^^^^^^^^ this is the required trait + | + ::: $DIR/auxiliary/crate_a2.rs:3:1 + | +LL | pub trait Bar {} + | ------------- this is the trait that was imported = 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 @@ -42,12 +56,16 @@ LL | a::try_foo(other_variant_implements_mismatched_trait); | | | required by a bound introduced by this call | -help: trait impl with same name found - --> $DIR/auxiliary/crate_a2.rs:13:1 +note: there are multiple different versions of crate `crate_a1` in the dependency graph + --> $DIR/auxiliary/crate_a1.rs:1:1 | -LL | impl Bar for ImplementsWrongTraitConditionally {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: perhaps two different versions of crate `crate_a2` are being used? +LL | pub trait Bar {} + | ^^^^^^^^^^^^^ this is the required trait + | + ::: $DIR/auxiliary/crate_a2.rs:3:1 + | +LL | pub trait Bar {} + | ------------- this is the implemented trait = 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 @@ -56,13 +74,23 @@ LL | pub fn try_foo(x: impl Bar) {} | ^^^ required by this bound in `try_foo` error[E0277]: the trait bound `ImplementsTraitForUsize: main::a::Bar` is not satisfied - --> $DIR/same-crate-name.rs:53:20 + --> $DIR/same-crate-name.rs:54:20 | LL | a::try_foo(other_variant_implements_correct_trait); | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `ImplementsTraitForUsize` | | | required by a bound introduced by this call | +note: there are multiple different versions of crate `crate_a1` in the dependency graph + --> $DIR/auxiliary/crate_a1.rs:1:1 + | +LL | pub trait Bar {} + | ^^^^^^^^^^^^^ this is the required trait + | + ::: $DIR/auxiliary/crate_a2.rs:3:1 + | +LL | pub trait Bar {} + | ------------- this is the trait that was imported = 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..1e46ed88ba022 --- /dev/null +++ b/tests/ui/traits/similarly_named_trait.rs @@ -0,0 +1,28 @@ +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; //~ HELP the trait `Trait` is not implemented for `St` + //~| HELP the trait `TraitWithParam` is not implemented for `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 unsatisfied trait bound + //~| 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 unsatisfied trait bound + //~| 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..e6966283b48a7 --- /dev/null +++ b/tests/ui/traits/similarly_named_trait.stderr @@ -0,0 +1,53 @@ +error[E0277]: the trait bound `St: Trait` is not satisfied + --> $DIR/similarly_named_trait.rs:20:10 + | +LL | func(m::St); + | ---- ^^^^^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | +help: the trait `Trait` is not implemented for `St` + --> $DIR/similarly_named_trait.rs:7:5 + | +LL | pub struct St; + | ^^^^^^^^^^^^^ + = 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:13: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:24:11 + | +LL | func2(m::St); + | ----- ^^^^^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | +help: the trait `TraitWithParam` is not implemented for `St` + --> $DIR/similarly_named_trait.rs:7:5 + | +LL | pub struct St; + | ^^^^^^^^^^^^^ + = 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:16: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 |