diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 36fe7f380069c..7bd3f7db55f99 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -559,6 +559,15 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { .filter_map(|(cnum, data)| data.used().then_some(cnum)), ) }, + duplicate_crate_names: |tcx, c: CrateNum| { + let name = tcx.crate_name(c); + tcx.arena.alloc_from_iter( + tcx.crates(()) + .into_iter() + .filter(|k| tcx.crate_name(**k) == name && **k != c) + .map(|c| *c), + ) + }, ..providers.queries }; provide_extern(&mut providers.extern_queries); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 676f0d82e4fbe..88917ad8db0d1 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2339,6 +2339,7 @@ rustc_queries! { eval_always desc { "fetching all foreign CrateNum instances" } } + // Crates that are loaded non-speculatively (not for diagnostics or doc links). // FIXME: This is currently only used for collecting lang items, but should be used instead of // `crates` in most other cases too. @@ -2347,6 +2348,14 @@ rustc_queries! { desc { "fetching `CrateNum`s for all crates loaded non-speculatively" } } + /// All crates that share the same name as crate `c`. + /// + /// This normally occurs when multiple versions of the same dependency are present in the + /// dependency tree. + query duplicate_crate_names(c: CrateNum) -> &'tcx [CrateNum] { + desc { "fetching `CrateNum`s with same name as `{c:?}`" } + } + /// A list of all traits in a crate, used by rustdoc and error reporting. query traits(_: CrateNum) -> &'tcx [DefId] { desc { "fetching all traits in a crate" } 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 d96a1b0a8c0eb..8d779f40a13a1 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 @@ -33,6 +33,7 @@ use rustc_middle::ty::{ TypeVisitableExt, Upcast, }; use rustc_middle::{bug, span_bug}; +use rustc_span::def_id::CrateNum; use rustc_span::{BytePos, DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym}; use tracing::{debug, instrument}; @@ -2172,6 +2173,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.suggest_function_pointers_impl(None, &exp_found, err); } + if let ty::Adt(def, _) = trait_pred.self_ty().skip_binder().peel_refs().kind() + && let crates = self.tcx.duplicate_crate_names(def.did().krate) + && !crates.is_empty() + { + self.note_two_crate_versions(def.did().krate, MultiSpan::new(), err); + err.help("you can use `cargo tree` to explore your dependency tree"); + } true }) }) { @@ -2282,6 +2290,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } )); } + + if let ty::Adt(def, _) = trait_pred.self_ty().skip_binder().peel_refs().kind() + && let crates = self.tcx.duplicate_crate_names(def.did().krate) + && !crates.is_empty() + { + self.note_two_crate_versions(def.did().krate, MultiSpan::new(), err); + err.help("you can use `cargo tree` to explore your dependency tree"); + } true }; @@ -2445,11 +2461,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub fn note_two_crate_versions( &self, - did: DefId, + krate: CrateNum, sp: impl Into, err: &mut Diag<'_>, ) { - let crate_name = self.tcx.crate_name(did.krate); + let crate_name = self.tcx.crate_name(krate); let crate_msg = format!( "there are multiple different versions of crate `{crate_name}` in the dependency graph" ); @@ -2514,7 +2530,7 @@ 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, MultiSpan::new(), err); + self.note_two_crate_versions(similar_item.krate, MultiSpan::new(), err); } } 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 3ba984b90a1d1..a7a685d62b345 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -442,7 +442,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } } - self.note_two_crate_versions(expected_did, span, err); + self.note_two_crate_versions(expected_did.krate, span, err); err.help("you can use `cargo tree` to explore your dependency tree"); } suggested diff --git a/tests/run-make/crate-loading/dep-2-reexport.rs b/tests/run-make/crate-loading/dep-2-reexport.rs index 07444511472fa..8b6ee6749dcc4 100644 --- a/tests/run-make/crate-loading/dep-2-reexport.rs +++ b/tests/run-make/crate-loading/dep-2-reexport.rs @@ -2,9 +2,23 @@ #![crate_type = "rlib"] extern crate dependency; -pub use dependency::{Trait2, Type, do_something_trait, do_something_type}; +pub use dependency::{Error, OtherError, Trait2, Type, do_something_trait, do_something_type}; pub struct OtherType; impl dependency::Trait for OtherType { fn foo(&self) {} fn bar() {} } +#[derive(Debug)] +pub struct Error2; + +impl From for Error2 { + fn from(_: Error) -> Error2 { + Error2 + } +} + +impl From for Error2 { + fn from(_: OtherError) -> Error2 { + Error2 + } +} diff --git a/tests/run-make/crate-loading/dependency-1.rs b/tests/run-make/crate-loading/dependency-1.rs index bfeabccf5c146..0eea7a7fae8bb 100644 --- a/tests/run-make/crate-loading/dependency-1.rs +++ b/tests/run-make/crate-loading/dependency-1.rs @@ -13,3 +13,27 @@ impl Trait for Type { pub fn do_something(_: X) {} pub fn do_something_type(_: Type) {} pub fn do_something_trait(_: Box) {} + +#[derive(Debug)] +pub struct Error; + +impl From<()> for Error { + fn from(t: ()) -> Error { + Error + } +} + +#[derive(Debug)] +pub struct OtherError; + +impl From<()> for OtherError { + fn from(t: ()) -> OtherError { + OtherError + } +} + +impl From for OtherError { + fn from(t: i32) -> OtherError { + OtherError + } +} diff --git a/tests/run-make/crate-loading/dependency-2.rs b/tests/run-make/crate-loading/dependency-2.rs index 682d1ff64b822..a07873297c547 100644 --- a/tests/run-make/crate-loading/dependency-2.rs +++ b/tests/run-make/crate-loading/dependency-2.rs @@ -14,3 +14,27 @@ impl Trait for Type { pub fn do_something(_: X) {} pub fn do_something_type(_: Type) {} pub fn do_something_trait(_: Box) {} + +#[derive(Debug)] +pub struct Error; + +impl From<()> for Error { + fn from(t: ()) -> Error { + Error + } +} + +#[derive(Debug)] +pub struct OtherError; + +impl From<()> for OtherError { + fn from(_: ()) -> OtherError { + OtherError + } +} + +impl From for OtherError { + fn from(_: i32) -> OtherError { + OtherError + } +} diff --git a/tests/run-make/crate-loading/multiple-dep-versions.rs b/tests/run-make/crate-loading/multiple-dep-versions.rs index 3a4a20d38fc87..69b8360a8c926 100644 --- a/tests/run-make/crate-loading/multiple-dep-versions.rs +++ b/tests/run-make/crate-loading/multiple-dep-versions.rs @@ -1,13 +1,20 @@ extern crate dep_2_reexport; extern crate dependency; -use dep_2_reexport::{OtherType, Trait2, Type}; -use dependency::{Trait, do_something, do_something_trait, do_something_type}; +use dep_2_reexport::{Error2, OtherType, Trait2, Type}; +use dependency::{Error, OtherError, Trait, do_something, do_something_trait, do_something_type}; -fn main() { +fn main() -> Result<(), Error> { do_something(Type); Type.foo(); Type::bar(); do_something(OtherType); do_something_type(Type); do_something_trait(Box::new(Type) as Box); + Err(Error2)?; + Ok(()) +} + +fn foo() -> Result<(), OtherError> { + Err(Error2)?; + Ok(()) } diff --git a/tests/run-make/crate-loading/multiple-dep-versions.stderr b/tests/run-make/crate-loading/multiple-dep-versions.stderr index 235a44a8ce895..f8f8bfaaff6f5 100644 --- a/tests/run-make/crate-loading/multiple-dep-versions.stderr +++ b/tests/run-make/crate-loading/multiple-dep-versions.stderr @@ -144,7 +144,51 @@ note: function defined here LL | pub fn do_something_trait(_: Box) {} | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error[E0277]: `?` couldn't convert the error to `dependency::Error` + --> replaced + | +LL | fn main() -> Result<(), Error> { + | ----------------- expected `dependency::Error` because of this +... +LL | Err(Error2)?; + | -----------^ the trait `From` is not implemented for `dependency::Error` + | | + | this can't be annotated with `?` because it has type `Result<_, Error2>` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait +help: the trait `From` is not implemented for `dependency::Error` + but trait `From<()>` is implemented for it + --> replaced + | +LL | impl From<()> for Error { + | ^^^^^^^^^^^^^^^^^^^^^^^ + = help: for that trait implementation, expected `()`, found `Error2` + = note: there are multiple different versions of crate `dependency` in the dependency graph + = help: you can use `cargo tree` to explore your dependency tree + +error[E0277]: `?` couldn't convert the error to `dependency::OtherError` + --> replaced + | +LL | fn foo() -> Result<(), OtherError> { + | ---------------------- expected `dependency::OtherError` because of this +LL | Err(Error2)?; + | -----------^ the trait `From` is not implemented for `dependency::OtherError` + | | + | this can't be annotated with `?` because it has type `Result<_, Error2>` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait +help: the following other types implement trait `From` + --> replaced + | +LL | impl From<()> for OtherError { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dependency::OtherError` implements `From<()>` +... +LL | impl From for OtherError { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dependency::OtherError` implements `From` + = note: there are multiple different versions of crate `dependency` in the dependency graph + = help: you can use `cargo tree` to explore your dependency tree + +error: aborting due to 8 previous errors Some errors have detailed explanations: E0277, E0308, E0599. For more information about an error, try `rustc --explain E0277`. \ No newline at end of file