about summary refs log tree commit diff
diff options
context:
space:
mode:
authormejrs <>2022-09-11 00:46:53 +0200
committermejrs <>2022-09-18 02:43:42 +0200
commit8477b9b707db74aa97a8390ff562f0e20b5d4d86 (patch)
tree9e224546c70b180885590c159f2516cd587322af
parent98ad6a5519651af36e246c0335c964dd52c554ba (diff)
downloadrust-8477b9b707db74aa97a8390ff562f0e20b5d4d86.tar.gz
rust-8477b9b707db74aa97a8390ff562f0e20b5d4d86.zip
Note if mismatched types have a similar name
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs52
-rw-r--r--src/test/ui/fully-qualified-type/fully-qualified-type-name2.stderr12
-rw-r--r--src/test/ui/issues/issue-56943.stderr12
-rw-r--r--src/test/ui/mismatched_types/similar_paths.rs11
-rw-r--r--src/test/ui/mismatched_types/similar_paths.stderr23
-rw-r--r--src/test/ui/type/type-mismatch-same-crate-name.stderr11
6 files changed, 117 insertions, 4 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 67526c22289..ab76b488478 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -51,6 +51,7 @@ use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePa
 
 use crate::infer;
 use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
+use crate::infer::ExpectedFound;
 use crate::traits::error_reporting::report_object_safety_error;
 use crate::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
@@ -1653,8 +1654,51 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 ),
                 Mismatch::Fixed(s) => (s.into(), s.into(), None),
             };
-            match (&terr, expected == found) {
-                (TypeError::Sorts(values), extra) => {
+            let looks_similar = |e: ExpectedFound<Ty<'_>>| {
+                // We're only interested in adts
+                if let (Some(e), Some(f)) = (e.expected.ty_adt_def(), e.found.ty_adt_def()) {
+                    // Only compare the last parts of the path.
+                    // `whatever::Foo` is pretty similar to `blah::Foo`
+                    let e_path = self.tcx.def_path(e.did()).data;
+                    let f_path = self.tcx.def_path(f.did()).data;
+                    if let (Some(e), Some(f)) = (e_path.last(), f_path.last()) {
+                        return e.data == f.data;
+                    }
+                }
+                false
+            };
+
+            match terr {
+                // If two types mismatch but have similar names, mention that specifically.
+                TypeError::Sorts(values) if looks_similar(values) => {
+                    let found_adt = values.found.ty_adt_def().unwrap();
+                    let expected_adt = values.expected.ty_adt_def().unwrap();
+
+                    let found_name = values.found.sort_string(self.tcx);
+                    let expected_name = values.expected.sort_string(self.tcx);
+
+                    diag.note(format!("{found_name} and {expected_name} have similar names, but are actually distinct types"));
+
+                    for (adt, name) in [(found_adt, found_name), (expected_adt, expected_name)] {
+                        let defid = adt.did();
+                        let def_span = self.tcx.def_span(defid);
+
+                        let msg = if defid.is_local() {
+                            format!("{name} is defined in the current crate.")
+                        } else if self.tcx.all_diagnostic_items(()).id_to_name.get(&defid).is_some()
+                        {
+                            // if it's a diagnostic item, it's definitely defined in std/core/alloc
+                            // otherwise might be, might not be.
+                            format!("{name} is defined in the standard library.")
+                        } else {
+                            let crate_name = self.tcx.crate_name(defid.krate);
+                            format!("{name} is defined in crate `{crate_name}`.")
+                        };
+                        diag.span_note(def_span, msg);
+                    }
+                }
+                TypeError::Sorts(values) => {
+                    let extra = expected == found;
                     let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
                         (true, ty::Opaque(def_id, _)) => {
                             let sm = self.tcx.sess.source_map();
@@ -1707,10 +1751,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                         );
                     }
                 }
-                (TypeError::ObjectUnsafeCoercion(_), _) => {
+                TypeError::ObjectUnsafeCoercion(_) => {
                     diag.note_unsuccessful_coercion(found, expected);
                 }
-                (_, _) => {
+                _ => {
                     debug!(
                         "note_type_err: exp_found={:?}, expected={:?} found={:?}",
                         exp_found, expected, found
diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name2.stderr b/src/test/ui/fully-qualified-type/fully-qualified-type-name2.stderr
index aed7f72c660..8729ea1740c 100644
--- a/src/test/ui/fully-qualified-type/fully-qualified-type-name2.stderr
+++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name2.stderr
@@ -5,6 +5,18 @@ LL | fn bar(x: x::Foo) -> y::Foo {
    |                      ------ expected `y::Foo` because of return type
 LL |     return x;
    |            ^ expected enum `y::Foo`, found enum `x::Foo`
+   |
+   = note: enum `x::Foo` and enum `y::Foo` have similar names, but are actually distinct types
+note: enum `x::Foo` is defined in the current crate.
+  --> $DIR/fully-qualified-type-name2.rs:4:5
+   |
+LL |     pub enum Foo { }
+   |     ^^^^^^^^^^^^
+note: enum `y::Foo` is defined in the current crate.
+  --> $DIR/fully-qualified-type-name2.rs:8:5
+   |
+LL |     pub enum Foo { }
+   |     ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-56943.stderr b/src/test/ui/issues/issue-56943.stderr
index 74ed5ec0fb6..3efa5f6d040 100644
--- a/src/test/ui/issues/issue-56943.stderr
+++ b/src/test/ui/issues/issue-56943.stderr
@@ -5,6 +5,18 @@ LL |     let _: issue_56943::S = issue_56943::S2;
    |            --------------   ^^^^^^^^^^^^^^^ expected struct `S`, found struct `S2`
    |            |
    |            expected due to this
+   |
+   = note: struct `S2` and struct `S` have similar names, but are actually distinct types
+note: struct `S2` is defined in crate `issue_56943`.
+  --> $DIR/auxiliary/issue-56943.rs:2:9
+   |
+LL | mod m { pub struct S; }
+   |         ^^^^^^^^^^^^
+note: struct `S` is defined in crate `issue_56943`.
+  --> $DIR/auxiliary/issue-56943.rs:1:1
+   |
+LL | pub struct S;
+   | ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/mismatched_types/similar_paths.rs b/src/test/ui/mismatched_types/similar_paths.rs
new file mode 100644
index 00000000000..4d3a2a1fcc6
--- /dev/null
+++ b/src/test/ui/mismatched_types/similar_paths.rs
@@ -0,0 +1,11 @@
+enum Option<T>{
+    Some(T),
+    None,
+}
+
+pub fn foo() -> Option<u8>{
+    Some(42_u8)
+    //~^ ERROR mismatched types [E0308]
+}
+
+fn main(){}
diff --git a/src/test/ui/mismatched_types/similar_paths.stderr b/src/test/ui/mismatched_types/similar_paths.stderr
new file mode 100644
index 00000000000..c12afd20b9c
--- /dev/null
+++ b/src/test/ui/mismatched_types/similar_paths.stderr
@@ -0,0 +1,23 @@
+error[E0308]: mismatched types
+  --> $DIR/similar_paths.rs:7:5
+   |
+LL | pub fn foo() -> Option<u8>{
+   |                 ---------- expected `Option<u8>` because of return type
+LL |     Some(42_u8)
+   |     ^^^^^^^^^^^ expected enum `Option`, found enum `std::option::Option`
+   |
+   = note: enum `std::option::Option` and enum `Option` have similar names, but are actually distinct types
+note: enum `std::option::Option` is defined in the standard library.
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL | pub enum Option<T> {
+   | ^^^^^^^^^^^^^^^^^^
+note: enum `Option` is defined in the current crate.
+  --> $DIR/similar_paths.rs:1:1
+   |
+LL | enum Option<T>{
+   | ^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type/type-mismatch-same-crate-name.stderr b/src/test/ui/type/type-mismatch-same-crate-name.stderr
index 783f747fa6d..38a36e8940f 100644
--- a/src/test/ui/type/type-mismatch-same-crate-name.stderr
+++ b/src/test/ui/type/type-mismatch-same-crate-name.stderr
@@ -6,6 +6,17 @@ LL |         a::try_foo(foo2);
    |         |
    |         arguments to this function are incorrect
    |
+   = note: struct `main::a::Foo` and struct `main::a::Foo` have similar names, but are actually distinct types
+note: struct `main::a::Foo` is defined in crate `crate_a2`.
+  --> $DIR/auxiliary/crate_a2.rs:1:1
+   |
+LL | pub struct Foo;
+   | ^^^^^^^^^^^^^^
+note: struct `main::a::Foo` is defined in crate `crate_a1`.
+  --> $DIR/auxiliary/crate_a1.rs:1:1
+   |
+LL | pub struct Foo;
+   | ^^^^^^^^^^^^^^
    = note: perhaps two different versions of crate `crate_a1` are being used?
 note: function defined here
   --> $DIR/auxiliary/crate_a1.rs:10:8