Skip to content

Commit 9e4d019

Browse files
committed
suggest replacing field when using the same type
1 parent 185a3f0 commit 9e4d019

File tree

4 files changed

+161
-26
lines changed

4 files changed

+161
-26
lines changed

compiler/rustc_typeck/src/check/pat.rs

+38-22
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
1010
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
1111
use rustc_hir::{HirId, Pat, PatKind};
1212
use rustc_infer::infer;
13+
use rustc_infer::infer::error_reporting::same_type_modulo_infer;
1314
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
1415
use rustc_middle::middle::stability::EvalResult;
1516
use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeFoldable};
@@ -1258,7 +1259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12581259
self.field_ty(span, f, substs)
12591260
})
12601261
.unwrap_or_else(|| {
1261-
inexistent_fields.push(field.ident);
1262+
inexistent_fields.push(field);
12621263
no_field_errors = false;
12631264
tcx.ty_error()
12641265
})
@@ -1276,13 +1277,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12761277
.collect::<Vec<_>>();
12771278

12781279
let inexistent_fields_err = if !(inexistent_fields.is_empty() || variant.is_recovered())
1279-
&& !inexistent_fields.iter().any(|field| field.name == kw::Underscore)
1280+
&& !inexistent_fields.iter().any(|field| field.ident.name == kw::Underscore)
12801281
{
12811282
Some(self.error_inexistent_fields(
12821283
adt.variant_descr(),
12831284
&inexistent_fields,
12841285
&mut unmentioned_fields,
12851286
variant,
1287+
substs,
12861288
))
12871289
} else {
12881290
None
@@ -1448,28 +1450,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14481450
fn error_inexistent_fields(
14491451
&self,
14501452
kind_name: &str,
1451-
inexistent_fields: &[Ident],
1452-
unmentioned_fields: &mut Vec<(&ty::FieldDef, Ident)>,
1453+
inexistent_fields: &[&hir::PatField<'tcx>],
1454+
unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>,
14531455
variant: &ty::VariantDef,
1456+
substs: &'tcx ty::List<ty::subst::GenericArg<'tcx>>,
14541457
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
14551458
let tcx = self.tcx;
14561459
let (field_names, t, plural) = if inexistent_fields.len() == 1 {
1457-
(format!("a field named `{}`", inexistent_fields[0]), "this", "")
1460+
(format!("a field named `{}`", inexistent_fields[0].ident), "this", "")
14581461
} else {
14591462
(
14601463
format!(
14611464
"fields named {}",
14621465
inexistent_fields
14631466
.iter()
1464-
.map(|ident| format!("`{}`", ident))
1467+
.map(|field| format!("`{}`", field.ident))
14651468
.collect::<Vec<String>>()
14661469
.join(", ")
14671470
),
14681471
"these",
14691472
"s",
14701473
)
14711474
};
1472-
let spans = inexistent_fields.iter().map(|ident| ident.span).collect::<Vec<_>>();
1475+
let spans = inexistent_fields.iter().map(|field| field.ident.span).collect::<Vec<_>>();
14731476
let mut err = struct_span_err!(
14741477
tcx.sess,
14751478
spans,
@@ -1479,9 +1482,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14791482
tcx.def_path_str(variant.def_id),
14801483
field_names
14811484
);
1482-
if let Some(ident) = inexistent_fields.last() {
1485+
if let Some(pat_field) = inexistent_fields.last() {
14831486
err.span_label(
1484-
ident.span,
1487+
pat_field.ident.span,
14851488
format!(
14861489
"{} `{}` does not have {} field{}",
14871490
kind_name,
@@ -1494,10 +1497,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14941497
if unmentioned_fields.len() == 1 {
14951498
let input =
14961499
unmentioned_fields.iter().map(|(_, field)| field.name).collect::<Vec<_>>();
1497-
let suggested_name = find_best_match_for_name(&input, ident.name, None);
1500+
let suggested_name = find_best_match_for_name(&input, pat_field.ident.name, None);
14981501
if let Some(suggested_name) = suggested_name {
14991502
err.span_suggestion(
1500-
ident.span,
1503+
pat_field.ident.span,
15011504
"a field with a similar name exists",
15021505
suggested_name.to_string(),
15031506
Applicability::MaybeIncorrect,
@@ -1513,17 +1516,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15131516
unmentioned_fields.retain(|&(_, x)| x.name != suggested_name);
15141517
}
15151518
} else if inexistent_fields.len() == 1 {
1516-
let unmentioned_field = unmentioned_fields[0].1.name;
1517-
err.span_suggestion_short(
1518-
ident.span,
1519-
&format!(
1520-
"`{}` has a field named `{}`",
1521-
tcx.def_path_str(variant.def_id),
1522-
unmentioned_field
1523-
),
1524-
unmentioned_field.to_string(),
1525-
Applicability::MaybeIncorrect,
1526-
);
1519+
match pat_field.pat.kind {
1520+
PatKind::Lit(expr)
1521+
if !same_type_modulo_infer(
1522+
self.typeck_results.borrow().expr_ty(expr),
1523+
self.field_ty(
1524+
unmentioned_fields[0].1.span,
1525+
unmentioned_fields[0].0,
1526+
substs,
1527+
),
1528+
) => {}
1529+
_ => {
1530+
let unmentioned_field = unmentioned_fields[0].1.name;
1531+
err.span_suggestion_short(
1532+
pat_field.ident.span,
1533+
&format!(
1534+
"`{}` has a field named `{}`",
1535+
tcx.def_path_str(variant.def_id),
1536+
unmentioned_field
1537+
),
1538+
unmentioned_field.to_string(),
1539+
Applicability::MaybeIncorrect,
1540+
);
1541+
}
1542+
}
15271543
}
15281544
}
15291545
}

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

+1-4
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ error[E0026]: struct `SimpleStruct` does not have a field named `state`
22
--> $DIR/issue-51102.rs:13:17
33
|
44
LL | state: 0,
5-
| ^^^^^
6-
| |
7-
| struct `SimpleStruct` does not have this field
8-
| help: `SimpleStruct` has a field named `no_state_here`
5+
| ^^^^^ struct `SimpleStruct` does not have this field
96

107
error[E0025]: field `no_state_here` bound multiple times in the pattern
118
--> $DIR/issue-51102.rs:24:17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
enum Foo {
2+
Bar { a: u8, b: i8, c: u8 },
3+
Baz { a: f32 },
4+
None,
5+
}
6+
7+
fn main() {
8+
let foo = Foo::None;
9+
match foo {
10+
Foo::Bar { a, aa: 1, c } => (),
11+
//~^ ERROR variant `Foo::Bar` does not have a field named `aa` [E0026]
12+
//~| ERROR pattern does not mention field `b` [E0027]
13+
Foo::Baz { bb: 1.0 } => (),
14+
//~^ ERROR variant `Foo::Baz` does not have a field named `bb` [E0026]
15+
//~| ERROR pattern does not mention field `a` [E0027]
16+
_ => (),
17+
}
18+
19+
match foo {
20+
Foo::Bar { a, aa: "", c } => (),
21+
//~^ ERROR variant `Foo::Bar` does not have a field named `aa` [E0026]
22+
//~| ERROR pattern does not mention field `b` [E0027]
23+
Foo::Baz { bb: "" } => (),
24+
//~^ ERROR variant `Foo::Baz` does not have a field named `bb` [E0026]
25+
//~| pattern does not mention field `a` [E0027]
26+
_ => (),
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
error[E0026]: variant `Foo::Bar` does not have a field named `aa`
2+
--> $DIR/suggest-replacing-field-when-specifying-same-type.rs:10:23
3+
|
4+
LL | Foo::Bar { a, aa: 1, c } => (),
5+
| ^^
6+
| |
7+
| variant `Foo::Bar` does not have this field
8+
| help: `Foo::Bar` has a field named `b`
9+
10+
error[E0027]: pattern does not mention field `b`
11+
--> $DIR/suggest-replacing-field-when-specifying-same-type.rs:10:9
12+
|
13+
LL | Foo::Bar { a, aa: 1, c } => (),
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^ missing field `b`
15+
|
16+
help: include the missing field in the pattern
17+
|
18+
LL | Foo::Bar { a, aa: 1, c, b } => (),
19+
| ~~~~~
20+
help: if you don't care about this missing field, you can explicitly ignore it
21+
|
22+
LL | Foo::Bar { a, aa: 1, c, .. } => (),
23+
| ~~~~~~
24+
25+
error[E0026]: variant `Foo::Baz` does not have a field named `bb`
26+
--> $DIR/suggest-replacing-field-when-specifying-same-type.rs:13:20
27+
|
28+
LL | Foo::Baz { bb: 1.0 } => (),
29+
| ^^
30+
| |
31+
| variant `Foo::Baz` does not have this field
32+
| help: `Foo::Baz` has a field named `a`
33+
34+
error[E0027]: pattern does not mention field `a`
35+
--> $DIR/suggest-replacing-field-when-specifying-same-type.rs:13:9
36+
|
37+
LL | Foo::Baz { bb: 1.0 } => (),
38+
| ^^^^^^^^^^^^^^^^^^^^ missing field `a`
39+
|
40+
help: include the missing field in the pattern
41+
|
42+
LL | Foo::Baz { bb: 1.0, a } => (),
43+
| ~~~~~
44+
help: if you don't care about this missing field, you can explicitly ignore it
45+
|
46+
LL | Foo::Baz { bb: 1.0, .. } => (),
47+
| ~~~~~~
48+
49+
error[E0026]: variant `Foo::Bar` does not have a field named `aa`
50+
--> $DIR/suggest-replacing-field-when-specifying-same-type.rs:20:23
51+
|
52+
LL | Foo::Bar { a, aa: "", c } => (),
53+
| ^^ variant `Foo::Bar` does not have this field
54+
55+
error[E0027]: pattern does not mention field `b`
56+
--> $DIR/suggest-replacing-field-when-specifying-same-type.rs:20:9
57+
|
58+
LL | Foo::Bar { a, aa: "", c } => (),
59+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `b`
60+
|
61+
help: include the missing field in the pattern
62+
|
63+
LL | Foo::Bar { a, aa: "", c, b } => (),
64+
| ~~~~~
65+
help: if you don't care about this missing field, you can explicitly ignore it
66+
|
67+
LL | Foo::Bar { a, aa: "", c, .. } => (),
68+
| ~~~~~~
69+
70+
error[E0026]: variant `Foo::Baz` does not have a field named `bb`
71+
--> $DIR/suggest-replacing-field-when-specifying-same-type.rs:23:20
72+
|
73+
LL | Foo::Baz { bb: "" } => (),
74+
| ^^ variant `Foo::Baz` does not have this field
75+
76+
error[E0027]: pattern does not mention field `a`
77+
--> $DIR/suggest-replacing-field-when-specifying-same-type.rs:23:9
78+
|
79+
LL | Foo::Baz { bb: "" } => (),
80+
| ^^^^^^^^^^^^^^^^^^^ missing field `a`
81+
|
82+
help: include the missing field in the pattern
83+
|
84+
LL | Foo::Baz { bb: "", a } => (),
85+
| ~~~~~
86+
help: if you don't care about this missing field, you can explicitly ignore it
87+
|
88+
LL | Foo::Baz { bb: "", .. } => (),
89+
| ~~~~~~
90+
91+
error: aborting due to 8 previous errors
92+
93+
Some errors have detailed explanations: E0026, E0027.
94+
For more information about an error, try `rustc --explain E0026`.

0 commit comments

Comments
 (0)