Skip to content

Commit b3e46a9

Browse files
committed
Auto merge of #95396 - TaKO8Ki:suggest-replacing-field-when-using-the-same-type, r=compiler-errors
Suggest replacing a field when using the same type closes #89166
2 parents 13c9fc3 + c26cfd1 commit b3e46a9

File tree

3 files changed

+159
-22
lines changed

3 files changed

+159
-22
lines changed

compiler/rustc_typeck/src/check/pat.rs

+37-22
Original file line numberDiff line numberDiff line change
@@ -1258,7 +1258,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12581258
self.field_ty(span, f, substs)
12591259
})
12601260
.unwrap_or_else(|| {
1261-
inexistent_fields.push(field.ident);
1261+
inexistent_fields.push(field);
12621262
no_field_errors = false;
12631263
tcx.ty_error()
12641264
})
@@ -1276,13 +1276,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12761276
.collect::<Vec<_>>();
12771277

12781278
let inexistent_fields_err = if !(inexistent_fields.is_empty() || variant.is_recovered())
1279-
&& !inexistent_fields.iter().any(|field| field.name == kw::Underscore)
1279+
&& !inexistent_fields.iter().any(|field| field.ident.name == kw::Underscore)
12801280
{
12811281
Some(self.error_inexistent_fields(
12821282
adt.variant_descr(),
12831283
&inexistent_fields,
12841284
&mut unmentioned_fields,
12851285
variant,
1286+
substs,
12861287
))
12871288
} else {
12881289
None
@@ -1448,28 +1449,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14481449
fn error_inexistent_fields(
14491450
&self,
14501451
kind_name: &str,
1451-
inexistent_fields: &[Ident],
1452-
unmentioned_fields: &mut Vec<(&ty::FieldDef, Ident)>,
1452+
inexistent_fields: &[&hir::PatField<'tcx>],
1453+
unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>,
14531454
variant: &ty::VariantDef,
1455+
substs: &'tcx ty::List<ty::subst::GenericArg<'tcx>>,
14541456
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
14551457
let tcx = self.tcx;
14561458
let (field_names, t, plural) = if inexistent_fields.len() == 1 {
1457-
(format!("a field named `{}`", inexistent_fields[0]), "this", "")
1459+
(format!("a field named `{}`", inexistent_fields[0].ident), "this", "")
14581460
} else {
14591461
(
14601462
format!(
14611463
"fields named {}",
14621464
inexistent_fields
14631465
.iter()
1464-
.map(|ident| format!("`{}`", ident))
1466+
.map(|field| format!("`{}`", field.ident))
14651467
.collect::<Vec<String>>()
14661468
.join(", ")
14671469
),
14681470
"these",
14691471
"s",
14701472
)
14711473
};
1472-
let spans = inexistent_fields.iter().map(|ident| ident.span).collect::<Vec<_>>();
1474+
let spans = inexistent_fields.iter().map(|field| field.ident.span).collect::<Vec<_>>();
14731475
let mut err = struct_span_err!(
14741476
tcx.sess,
14751477
spans,
@@ -1479,9 +1481,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14791481
tcx.def_path_str(variant.def_id),
14801482
field_names
14811483
);
1482-
if let Some(ident) = inexistent_fields.last() {
1484+
if let Some(pat_field) = inexistent_fields.last() {
14831485
err.span_label(
1484-
ident.span,
1486+
pat_field.ident.span,
14851487
format!(
14861488
"{} `{}` does not have {} field{}",
14871489
kind_name,
@@ -1494,10 +1496,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14941496
if unmentioned_fields.len() == 1 {
14951497
let input =
14961498
unmentioned_fields.iter().map(|(_, field)| field.name).collect::<Vec<_>>();
1497-
let suggested_name = find_best_match_for_name(&input, ident.name, None);
1499+
let suggested_name = find_best_match_for_name(&input, pat_field.ident.name, None);
14981500
if let Some(suggested_name) = suggested_name {
14991501
err.span_suggestion(
1500-
ident.span,
1502+
pat_field.ident.span,
15011503
"a field with a similar name exists",
15021504
suggested_name.to_string(),
15031505
Applicability::MaybeIncorrect,
@@ -1513,17 +1515,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15131515
unmentioned_fields.retain(|&(_, x)| x.name != suggested_name);
15141516
}
15151517
} 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-
);
1518+
match pat_field.pat.kind {
1519+
PatKind::Lit(expr)
1520+
if !self.can_coerce(
1521+
self.typeck_results.borrow().expr_ty(expr),
1522+
self.field_ty(
1523+
unmentioned_fields[0].1.span,
1524+
unmentioned_fields[0].0,
1525+
substs,
1526+
),
1527+
) => {}
1528+
_ => {
1529+
let unmentioned_field = unmentioned_fields[0].1.name;
1530+
err.span_suggestion_short(
1531+
pat_field.ident.span,
1532+
&format!(
1533+
"`{}` has a field named `{}`",
1534+
tcx.def_path_str(variant.def_id),
1535+
unmentioned_field
1536+
),
1537+
unmentioned_field.to_string(),
1538+
Applicability::MaybeIncorrect,
1539+
);
1540+
}
1541+
}
15271542
}
15281543
}
15291544
}
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)