about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-12-02 20:21:09 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-12-07 18:18:08 +0000
commit16bf7223eabd5cde19fab869ea964c14d59a4734 (patch)
treeec28407f05eafbe4d7a80ab63ddadc1622fb8a48
parent8dc83770f748c6cd16b342889ca2240397c19534 (diff)
downloadrust-16bf7223eabd5cde19fab869ea964c14d59a4734.tar.gz
rust-16bf7223eabd5cde19fab869ea964c14d59a4734.zip
Add more info on type/trait mismatches for different crate versions
When encountering a type or trait mismatch for two types coming from two different crates with the same name, detect if it is either mixing two types/traits from the same crate on different versions:

```
error[E0308]: mismatched types
  --> replaced
   |
LL |     do_something_type(Type);
   |     ----------------- ^^^^ expected `dependency::Type`, found `dep_2_reexport::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
  --> replaced
   |
LL | pub struct Type(pub i32);
   | ^^^^^^^^^^^^^^^ this is the expected type `dependency::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` is used here, as a dependency of crate `foo`
LL | extern crate dependency;
   | ------------------------ one version of crate `dependency` is used here, as a direct dependency of the current crate
   = help: you can use `cargo tree` to explore your dependency tree
note: function defined here
  --> replaced
   |
LL | pub fn do_something_type(_: Type) {}
   |        ^^^^^^^^^^^^^^^^^

error[E0308]: mismatched types
  --> replaced
   |
LL |     do_something_trait(Box::new(Type) as Box<dyn Trait2>);
   |     ------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait `dependency::Trait2`, found trait `dep_2_reexport::Trait2`
   |     |
   |     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
  --> replaced
   |
LL | pub trait Trait2 {}
   | ^^^^^^^^^^^^^^^^ this is the expected trait `dependency::Trait2`
   |
  ::: 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` is used here, as a dependency of crate `foo`
LL | extern crate dependency;
   | ------------------------ one version of crate `dependency` is used here, as a direct dependency of the current crate
   = help: you can use `cargo tree` to explore your dependency tree
note: function defined here
  --> replaced
   |
LL | pub fn do_something_trait(_: Box<dyn Trait2>) {}
   |        ^^^^^^^^^^^^^^^^^^
```

or if it is different crates that were renamed to the same name:

```
error[E0308]: mismatched types
  --> $DIR/type-mismatch-same-crate-name.rs:21: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
   |
LL | pub struct Foo;
   | ^^^^^^^^^^^^^^ this is the found type `crate_a2::Foo`
   |
  ::: $DIR/auxiliary/crate_a1.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` is used here, which is renamed locally to `a`
...
LL |         extern crate crate_a1 as a;
   |         --------------------------- one type comes from crate `crate_a1` is used here, which is renamed locally to `a`
note: function defined here
  --> $DIR/auxiliary/crate_a1.rs:10:8
   |
LL | pub fn try_foo(x: Foo){}
   |        ^^^^^^^

error[E0308]: mismatched types
  --> $DIR/type-mismatch-same-crate-name.rs:27: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
   |
LL | pub trait Bar {}
   | ^^^^^^^^^^^^^ this is the found trait `crate_a2::Bar`
   |
  ::: $DIR/auxiliary/crate_a1.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` is used here, which is renamed locally to `a`
...
LL |         extern crate crate_a1 as a;
   |         --------------------------- one trait comes from crate `crate_a1` is used here, which is renamed locally to `a`
note: function defined here
  --> $DIR/auxiliary/crate_a1.rs:11:8
   |
LL | pub fn try_bar(x: Box<Bar>){}
   |        ^^^^^^^
```

This new output unifies the E0308 errors detail with the pre-existing E0277 errors, and better differentiates the "`extern crate` renamed" and "same crate, different versions" cases.
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs134
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs4
-rw-r--r--tests/incremental/circular-dependencies.rs16
-rw-r--r--tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr2
-rw-r--r--tests/run-make/crate-loading/multiple-dep-versions-1.rs3
-rw-r--r--tests/run-make/crate-loading/multiple-dep-versions-2.rs4
-rw-r--r--tests/run-make/crate-loading/multiple-dep-versions-3.rs2
-rw-r--r--tests/run-make/crate-loading/multiple-dep-versions.rs6
-rw-r--r--tests/run-make/crate-loading/multiple-dep-versions.stderr80
-rw-r--r--tests/ui/mismatched_types/similar_paths_primitive.rs16
-rw-r--r--tests/ui/mismatched_types/similar_paths_primitive.stderr14
-rw-r--r--tests/ui/type/auxiliary/crate_a1.rs2
-rw-r--r--tests/ui/type/auxiliary/crate_a2.rs2
-rw-r--r--tests/ui/type/type-mismatch-same-crate-name.rs27
-rw-r--r--tests/ui/type/type-mismatch-same-crate-name.stderr45
15 files changed, 281 insertions, 76 deletions
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 8ba7969207e..f856a8d7abb 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -52,7 +52,9 @@ use std::{cmp, fmt, iter};
 
 use rustc_abi::ExternAbi;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
-use rustc_errors::{Applicability, Diag, DiagStyledString, IntoDiagArg, StringPart, pluralize};
+use rustc_errors::{
+    Applicability, Diag, DiagStyledString, IntoDiagArg, MultiSpan, StringPart, pluralize,
+};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
@@ -67,6 +69,7 @@ use rustc_middle::ty::{
     self, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
     TypeVisitableExt,
 };
+use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::{BytePos, DesugaringKind, Pos, Span, sym};
 use tracing::{debug, instrument};
 
@@ -211,7 +214,9 @@ 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>) {
+    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;
@@ -285,7 +290,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
         }
 
-        let report_path_match = |err: &mut Diag<'_>, did1: DefId, did2: DefId| {
+        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}];
@@ -297,24 +302,112 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
                 // 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 = || -> Result<_, PrintError> {
-                    Ok(self.tcx.def_path_str(did1) == self.tcx.def_path_str(did2)
-                        || abs_path(did1)? == abs_path(did2)?)
+                    Ok(expected_str == found_str || expected_abs == found_abs)
+                };
+                // 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 {
+                    (expected_abs.join("::"), found_abs.join("::"))
+                } else {
+                    (expected_str.clone(), found_str.clone())
                 };
                 if same_path().unwrap_or(false) {
-                    let crate_name = self.tcx.crate_name(did1.krate);
-                    let msg = if did1.is_local() || did2.is_local() {
+                    // 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!(
-                            "the crate `{crate_name}` is compiled multiple times, possibly with different configurations"
+                            "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!(
-                            "perhaps two different versions of crate `{crate_name}` are being used?"
+                            "two types coming from two different crates are different types even \
+                             if they look the same",
                         )
                     };
-                    err.note(msg);
+                    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) => {
@@ -323,14 +416,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 if let (&ty::Adt(exp_adt, _), &ty::Adt(found_adt, _)) =
                     (exp_found.expected.kind(), exp_found.found.kind())
                 {
-                    report_path_match(err, exp_adt.did(), found_adt.did());
+                    return report_path_match(err, exp_adt.did(), found_adt.did(), "type");
                 }
             }
             TypeError::Traits(ref exp_found) => {
-                report_path_match(err, exp_found.expected, exp_found.found);
+                return report_path_match(err, exp_found.expected, exp_found.found, "trait");
             }
             _ => (), // FIXME(#22750) handle traits and stuff
         }
+        false
     }
 
     fn note_error_origin(
@@ -1409,6 +1503,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             label_or_note(span, terr.to_string(self.tcx));
         }
 
+        if self.check_and_note_conflicting_crates(diag, terr) {
+            return;
+        }
+
         if let Some((expected, found, path)) = expected_found {
             let (expected_label, found_label, exp_found) = match exp_found {
                 Mismatch::Variable(ef) => (
@@ -1470,15 +1568,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         |prim: Ty<'tcx>, shadow: Ty<'tcx>, defid: DefId, diag: &mut Diag<'_>| {
                             let name = shadow.sort_string(self.tcx);
                             diag.note(format!(
-                                "{prim} and {name} have similar names, but are actually distinct types"
+                                "`{prim}` and {name} have similar names, but are actually distinct types"
+                            ));
+                            diag.note(format!(
+                                "one `{prim}` is a primitive defined by the language",
                             ));
-                            diag.note(format!("{prim} is a primitive defined by the language"));
                             let def_span = self.tcx.def_span(defid);
                             let msg = if defid.is_local() {
-                                format!("{name} is defined in the current crate")
+                                format!("the other {name} is defined in the current crate")
                             } else {
                                 let crate_name = self.tcx.crate_name(defid.krate);
-                                format!("{name} is defined in crate `{crate_name}`")
+                                format!("the other {name} is defined in crate `{crate_name}`")
                             };
                             diag.span_note(def_span, msg);
                         };
@@ -1666,8 +1766,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
         }
 
-        self.check_and_note_conflicting_crates(diag, terr);
-
         self.note_and_explain_type_err(diag, terr, cause, span, cause.body_id.to_def_id());
         if let Some(exp_found) = exp_found
             && let exp_found = TypeError::Sorts(exp_found)
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 90b18253629..4fb02f60943 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
@@ -1745,9 +1745,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     };
                     (
                         data.span,
-                        format!(
-                            "one version of crate `{crate_name}` is used here, as a {dependency}"
-                        ),
+                        format!("one version of crate `{crate_name}` used here, as a {dependency}"),
                     )
                 })
             {
diff --git a/tests/incremental/circular-dependencies.rs b/tests/incremental/circular-dependencies.rs
index 320edad3fde..c7b5b931fbb 100644
--- a/tests/incremental/circular-dependencies.rs
+++ b/tests/incremental/circular-dependencies.rs
@@ -6,10 +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 `Foo` is defined in the current crate
-//[cfail2]~| NOTE `Foo` is defined in the current crate
-//[cfail2]~| NOTE `circular_dependencies::Foo` is defined in crate `circular_dependencies`
-//[cfail2]~| NOTE `circular_dependencies::Foo` is defined in crate `circular_dependencies`
+//[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`
 
 pub fn consume_foo(_: Foo) {}
 //[cfail2]~^ NOTE function defined here
@@ -24,14 +26,12 @@ fn test() {
     //[cfail2]~^ ERROR mismatched types [E0308]
     //[cfail2]~| NOTE expected `circular_dependencies::Foo`, found `Foo`
     //[cfail2]~| NOTE arguments to this function are incorrect
-    //[cfail2]~| NOTE `Foo` and `circular_dependencies::Foo` have similar names, but are actually distinct types
-    //[cfail2]~| NOTE the crate `circular_dependencies` is compiled multiple times, possibly with different configurations
     //[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]
     //[cfail2]~| NOTE expected `Foo`, found `circular_dependencies::Foo`
     //[cfail2]~| NOTE arguments to this function are incorrect
-    //[cfail2]~| NOTE `circular_dependencies::Foo` and `Foo` have similar names, but are actually distinct types
-    //[cfail2]~| NOTE the crate `circular_dependencies` is compiled multiple times, possibly with different configurations
 }
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 36379429530..7f131153540 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
@@ -8,7 +8,7 @@ note: there are multiple different versions of crate `foo` in the dependency gra
   --> foo-current.rs:7:1
    |
 4  | extern crate foo;
-   | ----------------- one version of crate `foo` is used here, as a direct dependency of the current crate
+   | ----------------- 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
diff --git a/tests/run-make/crate-loading/multiple-dep-versions-1.rs b/tests/run-make/crate-loading/multiple-dep-versions-1.rs
index d81462504dd..bfeabccf5c1 100644
--- a/tests/run-make/crate-loading/multiple-dep-versions-1.rs
+++ b/tests/run-make/crate-loading/multiple-dep-versions-1.rs
@@ -5,8 +5,11 @@ pub trait Trait {
     fn foo(&self);
     fn bar();
 }
+pub trait Trait2 {}
 impl Trait for Type {
     fn foo(&self) {}
     fn bar() {}
 }
 pub fn do_something<X: Trait>(_: X) {}
+pub fn do_something_type(_: Type) {}
+pub fn do_something_trait(_: Box<dyn Trait2>) {}
diff --git a/tests/run-make/crate-loading/multiple-dep-versions-2.rs b/tests/run-make/crate-loading/multiple-dep-versions-2.rs
index 0a566fe2c60..682d1ff64b8 100644
--- a/tests/run-make/crate-loading/multiple-dep-versions-2.rs
+++ b/tests/run-make/crate-loading/multiple-dep-versions-2.rs
@@ -5,8 +5,12 @@ pub trait Trait {
     fn foo(&self);
     fn bar();
 }
+pub trait Trait2 {}
+impl Trait2 for Type {}
 impl Trait for Type {
     fn foo(&self) {}
     fn bar() {}
 }
 pub fn do_something<X: Trait>(_: X) {}
+pub fn do_something_type(_: Type) {}
+pub fn do_something_trait(_: Box<dyn Trait2>) {}
diff --git a/tests/run-make/crate-loading/multiple-dep-versions-3.rs b/tests/run-make/crate-loading/multiple-dep-versions-3.rs
index f5c4d1baa81..07444511472 100644
--- a/tests/run-make/crate-loading/multiple-dep-versions-3.rs
+++ b/tests/run-make/crate-loading/multiple-dep-versions-3.rs
@@ -2,7 +2,7 @@
 #![crate_type = "rlib"]
 
 extern crate dependency;
-pub use dependency::Type;
+pub use dependency::{Trait2, Type, do_something_trait, do_something_type};
 pub struct OtherType;
 impl dependency::Trait for OtherType {
     fn foo(&self) {}
diff --git a/tests/run-make/crate-loading/multiple-dep-versions.rs b/tests/run-make/crate-loading/multiple-dep-versions.rs
index c68a9e6489f..3a4a20d38fc 100644
--- a/tests/run-make/crate-loading/multiple-dep-versions.rs
+++ b/tests/run-make/crate-loading/multiple-dep-versions.rs
@@ -1,11 +1,13 @@
 extern crate dep_2_reexport;
 extern crate dependency;
-use dep_2_reexport::{OtherType, Type};
-use dependency::{Trait, do_something};
+use dep_2_reexport::{OtherType, Trait2, Type};
+use dependency::{Trait, do_something, do_something_trait, do_something_type};
 
 fn main() {
     do_something(Type);
     Type.foo();
     Type::bar();
     do_something(OtherType);
+    do_something_type(Type);
+    do_something_trait(Box::new(Type) as Box<dyn Trait2>);
 }
diff --git a/tests/run-make/crate-loading/multiple-dep-versions.stderr b/tests/run-make/crate-loading/multiple-dep-versions.stderr
index 5888aad8f37..6e1d6111b58 100644
--- a/tests/run-make/crate-loading/multiple-dep-versions.stderr
+++ b/tests/run-make/crate-loading/multiple-dep-versions.stderr
@@ -17,9 +17,9 @@ LL | pub trait Trait {
   ::: replaced
    |
 LL | extern crate dep_2_reexport;
-   | ---------------------------- one version of crate `dependency` is used here, as a dependency of crate `foo`
+   | ---------------------------- one version of crate `dependency` used here, as a dependency of crate `foo`
 LL | extern crate dependency;
-   | ------------------------ one version of crate `dependency` is used here, as a direct dependency of the current crate
+   | ------------------------ one version of crate `dependency` used here, as a direct dependency of the current crate
    |
   ::: replaced
    |
@@ -51,7 +51,7 @@ LL |     fn foo(&self);
    |
   ::: replaced
    |
-LL | use dependency::{Trait, do_something};
+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`
    |
   ::: replaced
@@ -76,7 +76,7 @@ LL |     fn bar();
    |
   ::: replaced
    |
-LL | use dependency::{Trait, do_something};
+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`
    |
   ::: replaced
@@ -101,9 +101,9 @@ LL | pub trait Trait {
   ::: replaced
    |
 LL | extern crate dep_2_reexport;
-   | ---------------------------- one version of crate `dependency` is used here, as a dependency of crate `foo`
+   | ---------------------------- one version of crate `dependency` used here, as a dependency of crate `foo`
 LL | extern crate dependency;
-   | ------------------------ one version of crate `dependency` is used here, as a direct dependency of the current crate
+   | ------------------------ one version of crate `dependency` used here, as a direct dependency of the current crate
    |
   ::: replaced
    |
@@ -121,7 +121,71 @@ note: required by a bound in `do_something`
 LL | pub fn do_something<X: Trait>(_: X) {}
    |                        ^^^^^ required by this bound in `do_something`
 
-error: aborting due to 4 previous errors
+error[E0308]: mismatched types
+  --> replaced
+   |
+LL |     do_something_type(Type);
+   |     ----------------- ^^^^ expected `dependency::Type`, found `dep_2_reexport::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
+  --> replaced
+   |
+LL | pub struct Type(pub i32);
+   | ^^^^^^^^^^^^^^^ this is the expected type `dependency::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
+   = help: you can use `cargo tree` to explore your dependency tree
+note: function defined here
+  --> replaced
+   |
+LL | pub fn do_something_type(_: Type) {}
+   |        ^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> replaced
+   |
+LL |     do_something_trait(Box::new(Type) as Box<dyn Trait2>);
+   |     ------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait `dependency::Trait2`, found trait `dep_2_reexport::Trait2`
+   |     |
+   |     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
+  --> replaced
+   |
+LL | pub trait Trait2 {}
+   | ^^^^^^^^^^^^^^^^ this is the expected trait `dependency::Trait2`
+   |
+  ::: 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
+   = help: you can use `cargo tree` to explore your dependency tree
+note: function defined here
+  --> replaced
+   |
+LL | pub fn do_something_trait(_: Box<dyn Trait2>) {}
+   |        ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0277, E0599.
+Some errors have detailed explanations: E0277, E0308, E0599.
 For more information about an error, try `rustc --explain E0277`.
\ No newline at end of file
diff --git a/tests/ui/mismatched_types/similar_paths_primitive.rs b/tests/ui/mismatched_types/similar_paths_primitive.rs
index 98890a15d98..a58fe68b863 100644
--- a/tests/ui/mismatched_types/similar_paths_primitive.rs
+++ b/tests/ui/mismatched_types/similar_paths_primitive.rs
@@ -1,14 +1,22 @@
 #![allow(non_camel_case_types)]
 
-struct bool;
-struct str;
+struct bool; //~ NOTE the other `bool` is defined in the current crate
+struct str; //~ NOTE the other `str` is defined in the current crate
 
-fn foo(_: bool) {}
-fn bar(_: &str) {}
+fn foo(_: bool) {} //~ NOTE function defined here
+fn bar(_: &str) {} //~ NOTE function defined here
 
 fn main() {
     foo(true);
     //~^ ERROR mismatched types [E0308]
+    //~| NOTE expected `bool`, found a different `bool`
+    //~| NOTE arguments to this function are incorrect
+    //~| NOTE `bool` and `bool` have similar names, but are actually distinct types
+    //~| NOTE one `bool` is a primitive defined by the language
     bar("hello");
     //~^ ERROR mismatched types [E0308]
+    //~| NOTE expected `str`, found a different `str`
+    //~| NOTE arguments to this function are incorrect
+    //~| NOTE `str` and `str` have similar names, but are actually distinct types
+    //~| NOTE one `str` is a primitive defined by the language
 }
diff --git a/tests/ui/mismatched_types/similar_paths_primitive.stderr b/tests/ui/mismatched_types/similar_paths_primitive.stderr
index 0530bf5863e..cf26234dba8 100644
--- a/tests/ui/mismatched_types/similar_paths_primitive.stderr
+++ b/tests/ui/mismatched_types/similar_paths_primitive.stderr
@@ -6,9 +6,9 @@ LL |     foo(true);
    |     |
    |     arguments to this function are incorrect
    |
-   = note: bool and `bool` have similar names, but are actually distinct types
-   = note: bool is a primitive defined by the language
-note: `bool` is defined in the current crate
+   = note: `bool` and `bool` have similar names, but are actually distinct types
+   = note: one `bool` is a primitive defined by the language
+note: the other `bool` is defined in the current crate
   --> $DIR/similar_paths_primitive.rs:3:1
    |
 LL | struct bool;
@@ -20,16 +20,16 @@ LL | fn foo(_: bool) {}
    |    ^^^ -------
 
 error[E0308]: mismatched types
-  --> $DIR/similar_paths_primitive.rs:12:9
+  --> $DIR/similar_paths_primitive.rs:16:9
    |
 LL |     bar("hello");
    |     --- ^^^^^^^ expected `str`, found a different `str`
    |     |
    |     arguments to this function are incorrect
    |
-   = note: str and `str` have similar names, but are actually distinct types
-   = note: str is a primitive defined by the language
-note: `str` is defined in the current crate
+   = note: `str` and `str` have similar names, but are actually distinct types
+   = note: one `str` is a primitive defined by the language
+note: the other `str` is defined in the current crate
   --> $DIR/similar_paths_primitive.rs:4:1
    |
 LL | struct str;
diff --git a/tests/ui/type/auxiliary/crate_a1.rs b/tests/ui/type/auxiliary/crate_a1.rs
index e2e18500541..616493193fd 100644
--- a/tests/ui/type/auxiliary/crate_a1.rs
+++ b/tests/ui/type/auxiliary/crate_a1.rs
@@ -1,6 +1,6 @@
 pub struct Foo;
 
-pub trait Bar{}
+pub trait Bar {}
 
 pub fn bar() -> Box<Bar> {
     unimplemented!()
diff --git a/tests/ui/type/auxiliary/crate_a2.rs b/tests/ui/type/auxiliary/crate_a2.rs
index d16a4ac10e0..57a7685b77c 100644
--- a/tests/ui/type/auxiliary/crate_a2.rs
+++ b/tests/ui/type/auxiliary/crate_a2.rs
@@ -1,6 +1,6 @@
 pub struct Foo;
 
-pub trait Bar{}
+pub trait Bar {}
 
 pub fn bar() -> Box<Bar> {
     unimplemented!()
diff --git a/tests/ui/type/type-mismatch-same-crate-name.rs b/tests/ui/type/type-mismatch-same-crate-name.rs
index da766165238..e88960364a2 100644
--- a/tests/ui/type/type-mismatch-same-crate-name.rs
+++ b/tests/ui/type/type-mismatch-same-crate-name.rs
@@ -3,25 +3,32 @@
 
 // This tests the extra note reported when a type error deals with
 // seemingly identical types.
-// The main use case of this error is when there are two crates
-// (generally different versions of the same crate) with the same name
-// causing a type mismatch. Here, we simulate that error using block-scoped
-// aliased `extern crate` declarations.
+// The main use case of this error is when there are two crates imported
+// with the same name, causing a type mismatch. Here, we simulate that error
+// using block-scoped aliased `extern crate` declarations.
+// This is *not* the same case as two different crate versions in the
+// dependency tree. That is tested in `tests/run-make/crate-loading/`.
 
 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
-        //~| perhaps two different versions of crate `crate_a1`
-        //~| expected `main::a::Foo`, found a different `main::a::Foo`
+        //~| 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 function defined here
         a::try_bar(bar2);
         //~^ ERROR mismatched types
-        //~| perhaps two different versions of crate `crate_a1`
-        //~| expected trait `main::a::Bar`
-        //~| expected struct `Box<(dyn main::a::Bar + 'static)>`
-        //~| found struct `Box<dyn main::a::Bar>`
+        //~| 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 function defined here
     }
 }
diff --git a/tests/ui/type/type-mismatch-same-crate-name.stderr b/tests/ui/type/type-mismatch-same-crate-name.stderr
index 504812f5867..7b791549f56 100644
--- a/tests/ui/type/type-mismatch-same-crate-name.stderr
+++ b/tests/ui/type/type-mismatch-same-crate-name.stderr
@@ -1,23 +1,29 @@
 error[E0308]: mismatched types
-  --> $DIR/type-mismatch-same-crate-name.rs:16:20
+  --> $DIR/type-mismatch-same-crate-name.rs:21:20
    |
 LL |         a::try_foo(foo2);
    |         ---------- ^^^^ expected `main::a::Foo`, found a different `main::a::Foo`
    |         |
    |         arguments to this function are incorrect
    |
-   = note: `main::a::Foo` and `main::a::Foo` have similar names, but are actually distinct types
-note: `main::a::Foo` is defined in crate `crate_a2`
+note: two types coming from two different crates are different types even if they look the same
   --> $DIR/auxiliary/crate_a2.rs:1:1
    |
 LL | pub struct Foo;
-   | ^^^^^^^^^^^^^^
-note: `main::a::Foo` is defined in crate `crate_a1`
-  --> $DIR/auxiliary/crate_a1.rs:1:1
+   | ^^^^^^^^^^^^^^ this is the found type `crate_a2::Foo`
+   |
+  ::: $DIR/auxiliary/crate_a1.rs:1:1
    |
 LL | pub struct Foo;
-   | ^^^^^^^^^^^^^^
-   = note: perhaps two different versions of crate `crate_a1` are being used?
+   | ^^^^^^^^^^^^^^ 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`
 note: function defined here
   --> $DIR/auxiliary/crate_a1.rs:10:8
    |
@@ -25,16 +31,31 @@ LL | pub fn try_foo(x: Foo){}
    |        ^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/type-mismatch-same-crate-name.rs:20:20
+  --> $DIR/type-mismatch-same-crate-name.rs:27: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: expected struct `Box<(dyn main::a::Bar + 'static)>`
-              found struct `Box<dyn main::a::Bar>`
-   = note: perhaps two different versions of crate `crate_a1` are being used?
+note: two types coming from two different crates are different types even if they look the same
+  --> $DIR/auxiliary/crate_a2.rs:3:1
+   |
+LL | pub trait Bar {}
+   | ^^^^^^^^^^^^^ this is the found trait `crate_a2::Bar`
+   |
+  ::: $DIR/auxiliary/crate_a1.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`
 note: function defined here
   --> $DIR/auxiliary/crate_a1.rs:11:8
    |