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 088fa668914a7..cb074261cdeed 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 @@ -1796,6 +1796,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { StringPart::highlighted("cargo tree".to_string()), StringPart::normal("` to explore your dependency tree".to_string()), ]); + + // FIXME: this is a giant hack for the benefit of this specific diagnostic. Because + // we're so nested in method calls before the error gets emitted, bubbling a single bit + // flag informing the top level caller to stop adding extra detail to the diagnostic, + // would actually be harder to follow. So we do something naughty here: we consume the + // diagnostic, emit it and leave in its place a "delayed bug" that will continue being + // modified but won't actually be printed to end users. This *is not ideal*, but allows + // us to reduce the verbosity of an error that is already quite verbose and increase its + // specificity. Below we modify the main message as well, in a way that *could* break if + // the implementation of Diagnostics change significantly, but that would be caught with + // a make test failure when this diagnostic is tested. + err.primary_message(format!( + "{} because the trait comes from a different crate version", + err.messages[0].0.as_str().unwrap(), + )); + let diag = err.clone(); + err.downgrade_to_delayed_bug(); + self.tcx.dcx().emit_diagnostic(diag); return true; } diff --git a/tests/run-make/crate-loading/rmake.rs b/tests/run-make/crate-loading/rmake.rs index 544bf9ab957a4..2d5913c4bcb09 100644 --- a/tests/run-make/crate-loading/rmake.rs +++ b/tests/run-make/crate-loading/rmake.rs @@ -18,37 +18,31 @@ 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 - --> multiple-dep-versions.rs:7:18 - | -7 | do_something(Type); - | ------------ ^^^^ the trait `Trait` is not implemented for `dep_2_reexport::Type` - | | - | required by a bound introduced by this call - | + .assert_stderr_contains(r#"error[E0277]: the trait bound `dep_2_reexport::Type: Trait` is not satisfied because the trait comes from a different crate version + --> multiple-dep-versions.rs:7:18 + | +7 | do_something(Type); + | ^^^^ the trait `Trait` is not implemented for `dep_2_reexport::Type` + | 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 +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#" -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"#) +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 - = 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`"#) +3 | pub struct Type; + | --------------- this type doesn't implement the required trait +4 | 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"#) .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 |