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 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 @@ enum Mismatch<'a> { ), Mismatch::Fixed(s) => (s.into(), s.into(), None), }; - match (&terr, expected == found) { - (TypeError::Sorts(values), extra) => { + let looks_similar = |e: ExpectedFound>| { + // 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 @@ enum Mismatch<'a> { ); } } - (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{ + Some(T), + None, +} + +pub fn foo() -> Option{ + 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{ + | ---------- expected `Option` 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 { + | ^^^^^^^^^^^^^^^^^^ +note: enum `Option` is defined in the current crate. + --> $DIR/similar_paths.rs:1:1 + | +LL | enum Option{ + | ^^^^^^^^^^^^^^ + +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