From c8c04663c56fa99ac973f103ade5660650875bbd 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. All diagnostics are merged into a single one. --- .../rustc_hir_typeck/src/method/suggest.rs | 53 +--- .../src/error_reporting/infer/mod.rs | 223 ++-------------- .../traits/fulfillment_errors.rs | 243 +++++++----------- .../src/error_reporting/traits/mod.rs | 79 +++++- tests/incremental/circular-dependencies.rs | 14 +- .../foo.stderr | 15 +- .../multiple-dep-versions.stderr | 85 ++---- .../run-make/duplicate-dependency/main.stderr | 2 +- tests/ui/traits/bound/same-crate-name.rs | 10 +- tests/ui/traits/bound/same-crate-name.stderr | 56 +++- tests/ui/traits/similarly_named_trait.rs | 28 ++ tests/ui/traits/similarly_named_trait.stderr | 53 ++++ .../ui/type/type-mismatch-same-crate-name.rs | 10 +- .../type/type-mismatch-same-crate-name.stderr | 42 +-- tests/ui/union/issue-81199.stderr | 1 + 15 files changed, 386 insertions(+), 528 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 1b8ecdbee579d..2e35e67a6e738 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -4212,7 +4212,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 }; @@ -4223,49 +4223,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/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index e18e294635b52..b280a6ec55af7 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -51,11 +51,8 @@ use std::path::PathBuf; use std::{cmp, fmt, iter}; use rustc_abi::ExternAbi; -use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_errors::{ - Applicability, Diag, DiagStyledString, IntoDiagArg, MultiSpan, StringPart, pluralize, -}; +use rustc_errors::{Applicability, Diag, DiagStyledString, IntoDiagArg, StringPart, pluralize}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; @@ -66,15 +63,12 @@ use rustc_middle::bug; use rustc_middle::dep_graph::DepContext; use rustc_middle::traits::PatternOriginExpr; use rustc_middle::ty::error::{ExpectedFound, TypeError, TypeErrorToStringExt}; -use rustc_middle::ty::print::{ - PrintError, PrintTraitRefExt as _, WrapBinderMode, with_forced_trimmed_paths, -}; +use rustc_middle::ty::print::{PrintTraitRefExt as _, WrapBinderMode, with_forced_trimmed_paths}; use rustc_middle::ty::{ self, List, ParamEnv, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; -use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, Symbol, sym}; +use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, sym}; use tracing::{debug, instrument}; use crate::error_reporting::TypeErrCtxt; @@ -216,201 +210,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Adds a note if the types come from similarly named crates fn check_and_note_conflicting_crates(&self, err: &mut Diag<'_>, terr: TypeError<'tcx>) -> bool { - // FIXME(estebank): unify with `report_similar_impl_candidates`. The message is similar, - // even if the logic needed to detect the case is very different. - use hir::def_id::CrateNum; - use rustc_hir::definitions::DisambiguatedDefPathData; - use ty::GenericArg; - use ty::print::Printer; - - struct ConflictingPathPrinter<'tcx> { - tcx: TyCtxt<'tcx>, - segments: Vec, - } - - impl<'tcx> Printer<'tcx> for ConflictingPathPrinter<'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { - self.tcx - } - - fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> { - unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs` - } - - fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> { - unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs` - } - - fn print_dyn_existential( - &mut self, - _predicates: &'tcx ty::List>, - ) -> Result<(), PrintError> { - unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs` - } - - fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> { - unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs` - } - - fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> { - self.segments = vec![self.tcx.crate_name(cnum)]; - Ok(()) - } - - fn print_path_with_qualified( - &mut self, - _self_ty: Ty<'tcx>, - _trait_ref: Option>, - ) -> Result<(), PrintError> { - Err(fmt::Error) - } - - fn print_path_with_impl( - &mut self, - _print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, - _self_ty: Ty<'tcx>, - _trait_ref: Option>, - ) -> Result<(), PrintError> { - Err(fmt::Error) - } - - fn print_path_with_simple( - &mut self, - print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, - disambiguated_data: &DisambiguatedDefPathData, - ) -> Result<(), PrintError> { - print_prefix(self)?; - self.segments.push(disambiguated_data.as_sym(true)); - Ok(()) - } - - fn print_path_with_generic_args( - &mut self, - print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, - _args: &[GenericArg<'tcx>], - ) -> Result<(), PrintError> { - print_prefix(self) - } - } - - let report_path_match = |err: &mut Diag<'_>, did1: DefId, did2: DefId, ty: &str| -> bool { - // Only report definitions from different crates. If both definitions - // are from a local module we could have false positives, e.g. - // let _ = [{struct Foo; Foo}, {struct Foo; Foo}]; - if did1.krate != did2.krate { - let abs_path = |def_id| { - let mut p = ConflictingPathPrinter { tcx: self.tcx, segments: vec![] }; - p.print_def_path(def_id, &[]).map(|_| p.segments) - }; - - // We compare strings because DefPath can be different for imported and - // non-imported crates. - let expected_str = self.tcx.def_path_str(did1); - let found_str = self.tcx.def_path_str(did2); - let Ok(expected_abs) = abs_path(did1) else { return false }; - let Ok(found_abs) = abs_path(did2) else { return false }; - let same_path = expected_str == found_str || expected_abs == found_abs; - if same_path { - // We want to use as unique a type path as possible. If both types are "locally - // known" by the same name, we use the "absolute path" which uses the original - // crate name instead. - let (expected, found) = if expected_str == found_str { - (join_path_syms(&expected_abs), join_path_syms(&found_abs)) - } else { - (expected_str, found_str) - }; - - // We've displayed "expected `a::b`, found `a::b`". We add context to - // differentiate the different cases where that might happen. - let expected_crate_name = self.tcx.crate_name(did1.krate); - let found_crate_name = self.tcx.crate_name(did2.krate); - let same_crate = expected_crate_name == found_crate_name; - let expected_sp = self.tcx.def_span(did1); - let found_sp = self.tcx.def_span(did2); - - let both_direct_dependencies = if !did1.is_local() - && !did2.is_local() - && let Some(data1) = self.tcx.extern_crate(did1.krate) - && let Some(data2) = self.tcx.extern_crate(did2.krate) - && data1.dependency_of == LOCAL_CRATE - && data2.dependency_of == LOCAL_CRATE - { - // If both crates are directly depended on, we don't want to mention that - // in the final message, as it is redundant wording. - // We skip the case of semver trick, where one version of the local crate - // depends on another version of itself by checking that both crates at play - // are not the current one. - true - } else { - false - }; - - let mut span: MultiSpan = vec![expected_sp, found_sp].into(); - span.push_span_label( - self.tcx.def_span(did1), - format!("this is the expected {ty} `{expected}`"), - ); - span.push_span_label( - self.tcx.def_span(did2), - format!("this is the found {ty} `{found}`"), - ); - for def_id in [did1, did2] { - let crate_name = self.tcx.crate_name(def_id.krate); - if !def_id.is_local() - && let Some(data) = self.tcx.extern_crate(def_id.krate) - { - let descr = if same_crate { - "one version of".to_string() - } else { - format!("one {ty} comes from") - }; - let dependency = if both_direct_dependencies { - if let rustc_session::cstore::ExternCrateSource::Extern(def_id) = - data.src - && let Some(name) = self.tcx.opt_item_name(def_id) - { - format!(", which is renamed locally to `{name}`") - } else { - String::new() - } - } else if data.dependency_of == LOCAL_CRATE { - ", as a direct dependency of the current crate".to_string() - } else { - let dep = self.tcx.crate_name(data.dependency_of); - format!(", as a dependency of crate `{dep}`") - }; - span.push_span_label( - data.span, - format!("{descr} crate `{crate_name}` used here{dependency}"), - ); - } - } - let msg = if (did1.is_local() || did2.is_local()) && same_crate { - format!( - "the crate `{expected_crate_name}` is compiled multiple times, \ - possibly with different configurations", - ) - } else if same_crate { - format!( - "two different versions of crate `{expected_crate_name}` are being \ - used; two types coming from two different versions of the same crate \ - are different types even if they look the same", - ) - } else { - format!( - "two types coming from two different crates are different types even \ - if they look the same", - ) - }; - err.span_note(span, msg); - if same_crate { - err.help("you can use `cargo tree` to explore your dependency tree"); - } - return true; - } - } - false - }; match terr { TypeError::Sorts(ref exp_found) => { // if they are both "path types", there's a chance of ambiguity @@ -418,11 +217,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let (&ty::Adt(exp_adt, _), &ty::Adt(found_adt, _)) = (exp_found.expected.kind(), exp_found.found.kind()) { - return report_path_match(err, exp_adt.did(), found_adt.did(), "type"); + return self.check_same_definition_different_crate( + err, + exp_adt.did(), + [found_adt.did()].into_iter(), + |did| vec![self.tcx.def_span(did)], + "type", + ); } } TypeError::Traits(ref exp_found) => { - return report_path_match(err, exp_found.expected, exp_found.found, "trait"); + return self.check_same_definition_different_crate( + err, + exp_found.expected, + [exp_found.found].into_iter(), + |did| vec![self.tcx.def_span(did)], + "trait", + ); } _ => (), // FIXME(#22750) handle traits and stuff } 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 c282f42042600..27eb614bae138 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 @@ -468,7 +468,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); @@ -1974,115 +1974,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, cand.impl_def_id)).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. @@ -2478,10 +2369,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>, @@ -2492,46 +2380,33 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_def_id, trait_pred.skip_binder().self_ty(), |impl_def_id| { - trait_impls.push(impl_def_id); + let impl_trait_header = self.tcx.impl_trait_header(impl_def_id); + trait_impls + .push(self.tcx.def_span(impl_trait_header.trait_ref.skip_binder().def_id)); }, ); trait_impls }; - - 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()) - .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())), - ); - self.note_two_crate_versions(trait_with_same_path, err); - suggested = true; - } - suggested + self.check_same_definition_different_crate( + err, + trait_pred.def_id(), + self.tcx.visible_traits(), + get_trait_impls, + "trait", + ) } - fn note_two_crate_versions(&self, did: DefId, err: &mut Diag<'_>) { + pub 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( @@ -2592,8 +2467,80 @@ 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)| match (&a.kind, &b.kind) { + (ty::GenericParamDefKind::Lifetime, ty::GenericParamDefKind::Lifetime) + | ( + ty::GenericParamDefKind::Type { .. }, + ty::GenericParamDefKind::Type { .. }, + ) + | ( + ty::GenericParamDefKind::Const { .. }, + ty::GenericParamDefKind::Const { .. }, + ) => true, + _ => false, + }, + ) + }; + 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 trait `{}`, 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 1825719a30774..befc83a592c0f 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; @@ -10,6 +10,7 @@ pub mod suggestions; use std::{fmt, iter}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::unord::UnordSet; use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; @@ -21,7 +22,7 @@ use rustc_infer::traits::{ }; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _}; -use rustc_span::{DesugaringKind, ErrorGuaranteed, ExpnKind, Span}; +use rustc_span::{DesugaringKind, ErrorGuaranteed, ExpnKind, Span, Symbol}; use tracing::{info, instrument}; pub use self::overflow::*; @@ -351,6 +352,80 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle), } } + + fn get_extern_crate_renamed_symbol(&self, trait_def_id: DefId) -> Option { + if !trait_def_id.is_local() + && let Some(data) = self.tcx.extern_crate(trait_def_id.krate) + && let rustc_session::cstore::ExternCrateSource::Extern(def_id) = data.src + { + self.tcx.opt_item_name(def_id) + } else { + None + } + } + + pub fn check_same_definition_different_crate( + &self, + err: &mut Diag<'_>, + expected_did: DefId, + found_dids: impl Iterator, + get_impls: F, + ty: &str, + ) -> bool + where + F: Fn(DefId) -> Vec, + { + let krate = self.tcx.crate_name(expected_did.krate); + let name = self.tcx.item_name(expected_did); + let locally_renamed_krate = self + .get_extern_crate_renamed_symbol(expected_did) + .map_or(None, |s| if s != krate { Some(s) } else { None }); + let definitions_with_same_path: UnordSet<_> = found_dids + .filter(|def_id| { + def_id.krate != expected_did.krate + && (locally_renamed_krate == self.get_extern_crate_renamed_symbol(*def_id) + || self.tcx.crate_name(def_id.krate) == krate) + && self.tcx.item_name(def_id) == name + }) + .map(|def_id| (self.tcx.def_path_str(def_id), def_id)) + .collect(); + + let definitions_with_same_path = + definitions_with_same_path.into_items().into_sorted_stable_ord_by_key(|(p, _)| p); + let mut suggested = false; + let mut trait_is_impl = false; + + if !definitions_with_same_path.is_empty() { + let mut span: MultiSpan = self.tcx.def_span(expected_did).into(); + span.push_span_label( + self.tcx.def_span(expected_did), + format!("this is the expected {ty}"), + ); + suggested = true; + for (_, definition_with_same_path) in &definitions_with_same_path { + let definitions_impls = get_impls(*definition_with_same_path); + if definitions_impls.is_empty() { + continue; + } + + for candidate_span in definitions_impls { + span.push_span_label(candidate_span, format!("this is the found {ty}")); + trait_is_impl = true; + } + } + if !trait_is_impl { + for (_, def_id) in definitions_with_same_path { + span.push_span_label( + self.tcx.def_span(def_id), + format!("this is the {ty} that was imported"), + ); + } + } + self.note_two_crate_versions(expected_did, span, err); + err.help("you can use `cargo tree` to explore your dependency tree"); + } + suggested + } } /// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a diff --git a/tests/incremental/circular-dependencies.rs b/tests/incremental/circular-dependencies.rs index c7b5b931fbbec..15e21089c9042 100644 --- a/tests/incremental/circular-dependencies.rs +++ b/tests/incremental/circular-dependencies.rs @@ -6,12 +6,12 @@ //@ [cfail2] compile-flags: --test --extern aux={{build-base}}/circular-dependencies/auxiliary/libcircular_dependencies_aux.rmeta -L dependency={{build-base}}/circular-dependencies pub struct Foo; -//[cfail2]~^ NOTE the crate `circular_dependencies` is compiled multiple times, possibly with different configurations -//[cfail2]~| NOTE the crate `circular_dependencies` is compiled multiple times, possibly with different configurations -//[cfail2]~| NOTE this is the expected type `Foo` -//[cfail2]~| NOTE this is the expected type `circular_dependencies::Foo` -//[cfail2]~| NOTE this is the found type `Foo` -//[cfail2]~| NOTE this is the found type `circular_dependencies::Foo` +//[cfail2]~^ NOTE there are multiple different versions of crate `circular_dependencies` in the dependency graph +//[cfail2]~| NOTE there are multiple different versions of crate `circular_dependencies` in the dependency graph +//[cfail2]~| NOTE this is the expected type +//[cfail2]~| NOTE this is the expected type +//[cfail2]~| NOTE this is the found type +//[cfail2]~| NOTE this is the found type pub fn consume_foo(_: Foo) {} //[cfail2]~^ NOTE function defined here @@ -27,8 +27,6 @@ fn test() { //[cfail2]~| NOTE expected `circular_dependencies::Foo`, found `Foo` //[cfail2]~| NOTE arguments to this function are incorrect //[cfail2]~| NOTE function defined here - //[cfail2]~| NOTE one version of crate `circular_dependencies` used here, as a dependency of crate `circular_dependencies_aux` - //[cfail2]~| NOTE one version of crate `circular_dependencies` used here, as a dependency of crate `circular_dependencies_aux` consume_foo(aux::produce_foo()); //[cfail2]~^ ERROR mismatched types [E0308] 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..fa71a3142b05e 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,19 @@ 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 + | ^^^^^^^^^^^^^^^ this is the expected 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 +help: the trait `Trait` is implemented for `Struct` + --> foo-current.rs:8:1 + | + 8 | impl Trait 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..235a44a8ce895 100644 --- a/tests/run-make/crate-loading/multiple-dep-versions.stderr +++ b/tests/run-make/crate-loading/multiple-dep-versions.stderr @@ -9,26 +9,19 @@ 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 + | ^^^^^^^^^^^^^^^ this is the expected trait | ::: 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 +help: the trait `Trait` is implemented for `dependency::Type` + --> replaced + | +LL | impl Trait for Type { + | ^^^^^^^^^^^^^^^^^^^ note: required by a bound in `do_something` --> replaced | @@ -45,19 +38,13 @@ 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 expected trait | ::: replaced | LL | pub trait Trait { | --------------- this is the trait that was imported + = help: you can use `cargo tree` to explore your dependency tree error[E0599]: no function or associated item named `bar` found for struct `dep_2_reexport::Type` in the current scope --> replaced @@ -69,20 +56,13 @@ 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 expected trait | ::: replaced | LL | pub trait Trait { | --------------- this is the trait that was imported + = help: you can use `cargo tree` to explore your dependency tree error[E0277]: the trait bound `OtherType: Trait` is not satisfied --> replaced @@ -96,25 +76,18 @@ note: there are multiple different versions of crate `dependency` in the depende --> replaced | 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 OtherType; - | -------------------- this type doesn't implement the required trait + | ^^^^^^^^^^^^^^^ this is the expected trait | ::: replaced | LL | pub trait Trait { | --------------- this is the found trait = help: you can use `cargo tree` to explore your dependency tree +help: the trait `Trait` is implemented for `dependency::Type` + --> replaced + | +LL | impl Trait for Type { + | ^^^^^^^^^^^^^^^^^^^ note: required by a bound in `do_something` --> replaced | @@ -129,23 +102,16 @@ LL | do_something_type(Type); | | | arguments to this function are incorrect | -note: two different versions of crate `dependency` are being used; two types coming from two different versions of the same crate are different types even if they look the same +note: there are multiple different versions of crate `dependency` in the dependency graph --> replaced | LL | pub struct Type(pub i32); - | ^^^^^^^^^^^^^^^ this is the expected type `dependency::Type` + | ^^^^^^^^^^^^^^^ this is the expected type | ::: replaced | LL | pub struct Type; - | ^^^^^^^^^^^^^^^ this is the found type `dep_2_reexport::Type` - | - ::: 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 + | --------------- this is the found type = help: you can use `cargo tree` to explore your dependency tree note: function defined here --> replaced @@ -161,23 +127,16 @@ LL | do_something_trait(Box::new(Type) as Box); | | | arguments to this function are incorrect | -note: two different versions of crate `dependency` are being used; two types coming from two different versions of the same crate are different types even if they look the same +note: there are multiple different versions of crate `dependency` in the dependency graph --> replaced | LL | pub trait Trait2 {} - | ^^^^^^^^^^^^^^^^ this is the expected trait `dependency::Trait2` + | ^^^^^^^^^^^^^^^^ this is the expected trait | ::: replaced | LL | pub trait Trait2 {} - | ^^^^^^^^^^^^^^^^ this is the found trait `dep_2_reexport::Trait2` - | - ::: 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 + | ---------------- this is the found trait = help: you can use `cargo tree` to explore your dependency tree note: function defined here --> 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..acd4894612872 100644 --- a/tests/ui/traits/bound/same-crate-name.rs +++ b/tests/ui/traits/bound/same-crate-name.rs @@ -32,13 +32,15 @@ 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 + //~| HELP you can use `cargo tree` to explore your dependency tree // 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 + //~| HELP you can use `cargo tree` to explore your dependency tree // We don't want to see the "version mismatch" help message here // because `other_variant_implements_mismatched_trait` @@ -46,6 +48,8 @@ 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 + //~| HELP you can use `cargo tree` to explore your dependency tree // We don't want to see the "version mismatch" help message here // because `ImplementsTraitForUsize` only has @@ -53,5 +57,7 @@ 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 + //~| HELP you can use `cargo tree` to explore your dependency tree } } diff --git a/tests/ui/traits/bound/same-crate-name.stderr b/tests/ui/traits/bound/same-crate-name.stderr index 5266f934f3ac8..9e5e110f8624e 100644 --- a/tests/ui/traits/bound/same-crate-name.stderr +++ b/tests/ui/traits/bound/same-crate-name.stderr @@ -6,12 +6,17 @@ 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 expected trait + | + ::: $DIR/auxiliary/crate_a2.rs:3:1 + | +LL | pub trait Bar {} + | ------------- this is the found trait + = help: you can use `cargo tree` to explore your dependency tree help: the trait `main::a::Bar` is implemented for `ImplementsTraitForUsize` --> $DIR/auxiliary/crate_a1.rs:9:1 | @@ -31,6 +36,17 @@ LL | a::try_foo(implements_no_traits); | | | 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 expected trait + | + ::: $DIR/auxiliary/crate_a2.rs:3:1 + | +LL | pub trait Bar {} + | ------------- this is the trait that was imported + = help: you can use `cargo tree` to explore your dependency tree help: the trait `main::a::Bar` is implemented for `ImplementsTraitForUsize` --> $DIR/auxiliary/crate_a1.rs:9:1 | @@ -43,19 +59,24 @@ LL | pub fn try_foo(x: impl Bar) {} | ^^^ required by this bound in `try_foo` error[E0277]: the trait bound `ImplementsWrongTraitConditionally: main::a::Bar` is not satisfied - --> $DIR/same-crate-name.rs:47:20 + --> $DIR/same-crate-name.rs:49:20 | LL | a::try_foo(other_variant_implements_mismatched_trait); | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `ImplementsWrongTraitConditionally` | | | 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 expected trait + | + ::: $DIR/auxiliary/crate_a2.rs:3:1 + | +LL | pub trait Bar {} + | ------------- this is the found trait + = help: you can use `cargo tree` to explore your dependency tree help: the trait `main::a::Bar` is implemented for `ImplementsTraitForUsize` --> $DIR/auxiliary/crate_a1.rs:9:1 | @@ -68,13 +89,24 @@ 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:57: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 expected trait + | + ::: $DIR/auxiliary/crate_a2.rs:3:1 + | +LL | pub trait Bar {} + | ------------- this is the trait that was imported + = help: you can use `cargo tree` to explore your dependency tree help: the trait `main::a::Bar` is implemented for `ImplementsTraitForUsize` --> $DIR/auxiliary/crate_a1.rs:9:1 | diff --git a/tests/ui/traits/similarly_named_trait.rs b/tests/ui/traits/similarly_named_trait.rs new file mode 100644 index 0000000000000..2545b9c7ed303 --- /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 trait `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 trait `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..2432e1ffbbe50 --- /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 trait `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 trait `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/type/type-mismatch-same-crate-name.rs b/tests/ui/type/type-mismatch-same-crate-name.rs index e88960364a251..df6d7aba8fd69 100644 --- a/tests/ui/type/type-mismatch-same-crate-name.rs +++ b/tests/ui/type/type-mismatch-same-crate-name.rs @@ -11,24 +11,22 @@ fn main() { let foo2 = {extern crate crate_a2 as a; a::Foo}; - //~^ NOTE one type comes from crate `crate_a2` used here, which is renamed locally to `a` - //~| NOTE one trait comes from crate `crate_a2` used here, which is renamed locally to `a` let bar2 = {extern crate crate_a2 as a; a::bar()}; { extern crate crate_a1 as a; - //~^ NOTE one type comes from crate `crate_a1` used here, which is renamed locally to `a` - //~| NOTE one trait comes from crate `crate_a1` used here, which is renamed locally to `a` a::try_foo(foo2); //~^ ERROR mismatched types //~| NOTE expected `main::a::Foo`, found a different `main::a::Foo` //~| NOTE arguments to this function are incorrect - //~| NOTE two types coming from two different crates are different types even if they look the same + //~| NOTE there are multiple different versions of crate `crate_a1` in the dependency graph //~| NOTE function defined here + //~| HELP you can use `cargo tree` to explore your dependency tree a::try_bar(bar2); //~^ ERROR mismatched types //~| NOTE expected trait `main::a::Bar`, found a different trait `main::a::Bar` //~| NOTE arguments to this function are incorrect - //~| NOTE two types coming from two different crates are different types even if they look the same + //~| NOTE there are multiple different versions of crate `crate_a1` in the dependency graph //~| NOTE function defined here + //~| HELP you can use `cargo tree` to explore your dependency tree } } diff --git a/tests/ui/type/type-mismatch-same-crate-name.stderr b/tests/ui/type/type-mismatch-same-crate-name.stderr index 8fafbfaa93425..2913b994e9529 100644 --- a/tests/ui/type/type-mismatch-same-crate-name.stderr +++ b/tests/ui/type/type-mismatch-same-crate-name.stderr @@ -1,29 +1,22 @@ error[E0308]: mismatched types - --> $DIR/type-mismatch-same-crate-name.rs:21:20 + --> $DIR/type-mismatch-same-crate-name.rs:17:20 | LL | a::try_foo(foo2); | ---------- ^^^^ expected `main::a::Foo`, found a different `main::a::Foo` | | | arguments to this function are incorrect | -note: two types coming from two different crates are different types even if they look the same - --> $DIR/auxiliary/crate_a2.rs:1:1 +note: there are multiple different versions of crate `crate_a1` in the dependency graph + --> $DIR/auxiliary/crate_a1.rs:1:1 | LL | pub struct Foo; - | ^^^^^^^^^^^^^^ this is the found type `crate_a2::Foo` + | ^^^^^^^^^^^^^^ this is the expected type | - ::: $DIR/auxiliary/crate_a1.rs:1:1 + ::: $DIR/auxiliary/crate_a2.rs:1:1 | LL | pub struct Foo; - | ^^^^^^^^^^^^^^ this is the expected type `crate_a1::Foo` - | - ::: $DIR/type-mismatch-same-crate-name.rs:13:17 - | -LL | let foo2 = {extern crate crate_a2 as a; a::Foo}; - | --------------------------- one type comes from crate `crate_a2` used here, which is renamed locally to `a` -... -LL | extern crate crate_a1 as a; - | --------------------------- one type comes from crate `crate_a1` used here, which is renamed locally to `a` + | -------------- this is the found type + = help: you can use `cargo tree` to explore your dependency tree note: function defined here --> $DIR/auxiliary/crate_a1.rs:10:8 | @@ -31,31 +24,24 @@ LL | pub fn try_foo(x: Foo){} | ^^^^^^^ error[E0308]: mismatched types - --> $DIR/type-mismatch-same-crate-name.rs:27:20 + --> $DIR/type-mismatch-same-crate-name.rs:24:20 | LL | a::try_bar(bar2); | ---------- ^^^^ expected trait `main::a::Bar`, found a different trait `main::a::Bar` | | | arguments to this function are incorrect | -note: two types coming from two different crates are different types even if they look the same - --> $DIR/auxiliary/crate_a2.rs:3:1 +note: there are multiple different versions of crate `crate_a1` in the dependency graph + --> $DIR/auxiliary/crate_a1.rs:3:1 | LL | pub trait Bar {} - | ^^^^^^^^^^^^^ this is the found trait `crate_a2::Bar` + | ^^^^^^^^^^^^^ this is the expected trait | - ::: $DIR/auxiliary/crate_a1.rs:3:1 + ::: $DIR/auxiliary/crate_a2.rs:3:1 | LL | pub trait Bar {} - | ^^^^^^^^^^^^^ this is the expected trait `crate_a1::Bar` - | - ::: $DIR/type-mismatch-same-crate-name.rs:13:17 - | -LL | let foo2 = {extern crate crate_a2 as a; a::Foo}; - | --------------------------- one trait comes from crate `crate_a2` used here, which is renamed locally to `a` -... -LL | extern crate crate_a1 as a; - | --------------------------- one trait comes from crate `crate_a1` used here, which is renamed locally to `a` + | ------------- this is the found trait + = help: you can use `cargo tree` to explore your dependency tree note: function defined here --> $DIR/auxiliary/crate_a1.rs:11:8 | diff --git a/tests/ui/union/issue-81199.stderr b/tests/ui/union/issue-81199.stderr index 7deba88fc803c..46f5de8d4fd8a 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 trait `std::ptr::Pointee`, but not `Pointee` note: required by a bound in `PtrComponents` --> $DIR/issue-81199.rs:11:25 |