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 b3d622d0c9bf5..088fa668914a7 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 @@ -1723,7 +1723,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } else { None }; - let spans: Vec<_> = [trait_def_id, other_trait_def_id] + 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() .filter_map(|def_id| self.tcx.extern_crate(def_id.krate)) .map(|data| { @@ -1740,25 +1747,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ), ) }) - .collect(); - let mut span: MultiSpan = spans.iter().map(|(sp, _)| *sp).collect::>().into(); - for (sp, label) in spans.into_iter() { + { span.push_span_label(sp, label); } - err.highlighted_span_help(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()), - ]); - 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"); if let Some(found_type) = found_type { span.push_span_label( self.tcx.def_span(found_type), @@ -1786,6 +1777,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } 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\n".to_string()), + ]); + err.highlighted_note(vec![ StringPart::normal( "two types coming from two different versions of the same crate are \ different types " @@ -1793,7 +1791,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ), StringPart::highlighted("even if they look the same".to_string()), ]); - err.help("you can use `cargo tree` to explore your dependency tree"); + 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; } diff --git a/tests/run-make/crate-loading/rmake.rs b/tests/run-make/crate-loading/rmake.rs index ea8802f6e2a20..544bf9ab957a4 100644 --- a/tests/run-make/crate-loading/rmake.rs +++ b/tests/run-make/crate-loading/rmake.rs @@ -18,8 +18,7 @@ fn main() { .extern_("dependency", rust_lib_name("dependency")) .extern_("dep_2_reexport", rust_lib_name("foo")) .run_fail() - .assert_stderr_contains( - r#"error[E0277]: the trait bound `dep_2_reexport::Type: Trait` is not satisfied + .assert_stderr_contains(r#"error[E0277]: the trait bound `dep_2_reexport::Type: Trait` is not satisfied --> multiple-dep-versions.rs:7:18 | 7 | do_something(Type); @@ -27,41 +26,37 @@ fn main() { | | | required by a bound introduced by this call | -help: there are multiple different versions of crate `dependency` in the dependency graph - --> multiple-dep-versions.rs:1:1 - | -1 | extern crate dep_2_reexport; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one version of crate `dependency` is used here, as a dependency of crate `foo` -2 | extern crate dependency; - | ^^^^^^^^^^^^^^^^^^^^^^^^ one version of crate `dependency` is used here, as a direct dependency of the current crate"#, - ) - .assert_stderr_contains( - r#" +note: there are multiple different versions of crate `dependency` in the dependency graph"#) + .assert_stderr_contains(r#" 3 | pub struct Type(pub i32); | --------------- this type implements the required trait 4 | pub trait Trait { - | ^^^^^^^^^^^^^^^ this is the required trait"#, - ) - .assert_stderr_contains( - r#" + | ^^^^^^^^^^^^^^^ this is the required trait +"#) + .assert_stderr_contains(r#" +1 | extern crate dep_2_reexport; + | ---------------------------- one version of crate `dependency` is used here, as a dependency of crate `foo` +2 | extern crate dependency; + | ------------------------ one version of crate `dependency` is used here, as a direct dependency of the current crate"#) + .assert_stderr_contains(r#" 3 | pub struct Type; | --------------- this type doesn't implement the required trait 4 | pub trait Trait { | --------------- this is the found trait - = help: you can use `cargo tree` to explore your dependency tree"#, - ) - .assert_stderr_contains( - r#" -error[E0599]: no method named `foo` found for struct `dep_2_reexport::Type` in the current scope + = 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"#) + .assert_stderr_contains(r#"note: required by a bound in `do_something`"#) + .assert_stderr_contains(r#" +12 | pub fn do_something(_: X) {} + | ^^^^^ required by this bound in `do_something`"#) + .assert_stderr_contains(r#"error[E0599]: no method named `foo` found for struct `dep_2_reexport::Type` in the current scope --> multiple-dep-versions.rs:8:10 | 8 | Type.foo(); | ^^^ method not found in `Type` | -note: there are multiple different versions of crate `dependency` in the dependency graph"#, - ) - .assert_stderr_contains( - r#" +note: there are multiple different versions of crate `dependency` in the dependency graph"#) + .assert_stderr_contains(r#" 4 | pub trait Trait { | ^^^^^^^^^^^^^^^ this is the trait that is needed 5 | fn foo(&self); @@ -70,25 +65,19 @@ note: there are multiple different versions of crate `dependency` in the depende ::: multiple-dep-versions.rs:4:18 | 4 | use dependency::{Trait, do_something}; - | ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`"#, - ) - .assert_stderr_contains( - r#" + | ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`"#) + .assert_stderr_contains(r#" 4 | pub trait Trait { - | --------------- this is the trait that was imported"#, - ) - .assert_stderr_contains( - r#" + | --------------- this is the trait that was imported"#) + .assert_stderr_contains(r#" error[E0599]: no function or associated item named `bar` found for struct `dep_2_reexport::Type` in the current scope --> multiple-dep-versions.rs:9:11 | 9 | Type::bar(); | ^^^ function or associated item not found in `Type` | -note: there are multiple different versions of crate `dependency` in the dependency graph"#, - ) - .assert_stderr_contains( - r#" +note: there are multiple different versions of crate `dependency` in the dependency graph"#) + .assert_stderr_contains(r#" 4 | pub trait Trait { | ^^^^^^^^^^^^^^^ this is the trait that is needed 5 | fn foo(&self); @@ -98,8 +87,7 @@ note: there are multiple different versions of crate `dependency` in the depende ::: multiple-dep-versions.rs:4:18 | 4 | use dependency::{Trait, do_something}; - | ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`"#, - ) + | ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`"#) .assert_stderr_contains( r#" 6 | pub struct OtherType;