Skip to content

Commit 8477b9b

Browse files
author
mejrs
committed
Note if mismatched types have a similar name
1 parent 98ad6a5 commit 8477b9b

File tree

6 files changed

+117
-4
lines changed

6 files changed

+117
-4
lines changed

compiler/rustc_infer/src/infer/error_reporting/mod.rs

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePa
5151

5252
use crate::infer;
5353
use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
54+
use crate::infer::ExpectedFound;
5455
use crate::traits::error_reporting::report_object_safety_error;
5556
use crate::traits::{
5657
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
@@ -1653,8 +1654,51 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16531654
),
16541655
Mismatch::Fixed(s) => (s.into(), s.into(), None),
16551656
};
1656-
match (&terr, expected == found) {
1657-
(TypeError::Sorts(values), extra) => {
1657+
let looks_similar = |e: ExpectedFound<Ty<'_>>| {
1658+
// We're only interested in adts
1659+
if let (Some(e), Some(f)) = (e.expected.ty_adt_def(), e.found.ty_adt_def()) {
1660+
// Only compare the last parts of the path.
1661+
// `whatever::Foo` is pretty similar to `blah::Foo`
1662+
let e_path = self.tcx.def_path(e.did()).data;
1663+
let f_path = self.tcx.def_path(f.did()).data;
1664+
if let (Some(e), Some(f)) = (e_path.last(), f_path.last()) {
1665+
return e.data == f.data;
1666+
}
1667+
}
1668+
false
1669+
};
1670+
1671+
match terr {
1672+
// If two types mismatch but have similar names, mention that specifically.
1673+
TypeError::Sorts(values) if looks_similar(values) => {
1674+
let found_adt = values.found.ty_adt_def().unwrap();
1675+
let expected_adt = values.expected.ty_adt_def().unwrap();
1676+
1677+
let found_name = values.found.sort_string(self.tcx);
1678+
let expected_name = values.expected.sort_string(self.tcx);
1679+
1680+
diag.note(format!("{found_name} and {expected_name} have similar names, but are actually distinct types"));
1681+
1682+
for (adt, name) in [(found_adt, found_name), (expected_adt, expected_name)] {
1683+
let defid = adt.did();
1684+
let def_span = self.tcx.def_span(defid);
1685+
1686+
let msg = if defid.is_local() {
1687+
format!("{name} is defined in the current crate.")
1688+
} else if self.tcx.all_diagnostic_items(()).id_to_name.get(&defid).is_some()
1689+
{
1690+
// if it's a diagnostic item, it's definitely defined in std/core/alloc
1691+
// otherwise might be, might not be.
1692+
format!("{name} is defined in the standard library.")
1693+
} else {
1694+
let crate_name = self.tcx.crate_name(defid.krate);
1695+
format!("{name} is defined in crate `{crate_name}`.")
1696+
};
1697+
diag.span_note(def_span, msg);
1698+
}
1699+
}
1700+
TypeError::Sorts(values) => {
1701+
let extra = expected == found;
16581702
let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
16591703
(true, ty::Opaque(def_id, _)) => {
16601704
let sm = self.tcx.sess.source_map();
@@ -1707,10 +1751,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
17071751
);
17081752
}
17091753
}
1710-
(TypeError::ObjectUnsafeCoercion(_), _) => {
1754+
TypeError::ObjectUnsafeCoercion(_) => {
17111755
diag.note_unsuccessful_coercion(found, expected);
17121756
}
1713-
(_, _) => {
1757+
_ => {
17141758
debug!(
17151759
"note_type_err: exp_found={:?}, expected={:?} found={:?}",
17161760
exp_found, expected, found

src/test/ui/fully-qualified-type/fully-qualified-type-name2.stderr

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ LL | fn bar(x: x::Foo) -> y::Foo {
55
| ------ expected `y::Foo` because of return type
66
LL | return x;
77
| ^ expected enum `y::Foo`, found enum `x::Foo`
8+
|
9+
= note: enum `x::Foo` and enum `y::Foo` have similar names, but are actually distinct types
10+
note: enum `x::Foo` is defined in the current crate.
11+
--> $DIR/fully-qualified-type-name2.rs:4:5
12+
|
13+
LL | pub enum Foo { }
14+
| ^^^^^^^^^^^^
15+
note: enum `y::Foo` is defined in the current crate.
16+
--> $DIR/fully-qualified-type-name2.rs:8:5
17+
|
18+
LL | pub enum Foo { }
19+
| ^^^^^^^^^^^^
820

921
error: aborting due to previous error
1022

src/test/ui/issues/issue-56943.stderr

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ LL | let _: issue_56943::S = issue_56943::S2;
55
| -------------- ^^^^^^^^^^^^^^^ expected struct `S`, found struct `S2`
66
| |
77
| expected due to this
8+
|
9+
= note: struct `S2` and struct `S` have similar names, but are actually distinct types
10+
note: struct `S2` is defined in crate `issue_56943`.
11+
--> $DIR/auxiliary/issue-56943.rs:2:9
12+
|
13+
LL | mod m { pub struct S; }
14+
| ^^^^^^^^^^^^
15+
note: struct `S` is defined in crate `issue_56943`.
16+
--> $DIR/auxiliary/issue-56943.rs:1:1
17+
|
18+
LL | pub struct S;
19+
| ^^^^^^^^^^^^
820

921
error: aborting due to previous error
1022

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
enum Option<T>{
2+
Some(T),
3+
None,
4+
}
5+
6+
pub fn foo() -> Option<u8>{
7+
Some(42_u8)
8+
//~^ ERROR mismatched types [E0308]
9+
}
10+
11+
fn main(){}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/similar_paths.rs:7:5
3+
|
4+
LL | pub fn foo() -> Option<u8>{
5+
| ---------- expected `Option<u8>` because of return type
6+
LL | Some(42_u8)
7+
| ^^^^^^^^^^^ expected enum `Option`, found enum `std::option::Option`
8+
|
9+
= note: enum `std::option::Option` and enum `Option` have similar names, but are actually distinct types
10+
note: enum `std::option::Option` is defined in the standard library.
11+
--> $SRC_DIR/core/src/option.rs:LL:COL
12+
|
13+
LL | pub enum Option<T> {
14+
| ^^^^^^^^^^^^^^^^^^
15+
note: enum `Option` is defined in the current crate.
16+
--> $DIR/similar_paths.rs:1:1
17+
|
18+
LL | enum Option<T>{
19+
| ^^^^^^^^^^^^^^
20+
21+
error: aborting due to previous error
22+
23+
For more information about this error, try `rustc --explain E0308`.

src/test/ui/type/type-mismatch-same-crate-name.stderr

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@ LL | a::try_foo(foo2);
66
| |
77
| arguments to this function are incorrect
88
|
9+
= note: struct `main::a::Foo` and struct `main::a::Foo` have similar names, but are actually distinct types
10+
note: struct `main::a::Foo` is defined in crate `crate_a2`.
11+
--> $DIR/auxiliary/crate_a2.rs:1:1
12+
|
13+
LL | pub struct Foo;
14+
| ^^^^^^^^^^^^^^
15+
note: struct `main::a::Foo` is defined in crate `crate_a1`.
16+
--> $DIR/auxiliary/crate_a1.rs:1:1
17+
|
18+
LL | pub struct Foo;
19+
| ^^^^^^^^^^^^^^
920
= note: perhaps two different versions of crate `crate_a1` are being used?
1021
note: function defined here
1122
--> $DIR/auxiliary/crate_a1.rs:10:8

0 commit comments

Comments
 (0)