Skip to content

Commit 21f8326

Browse files
committed
Provide suggestion for missing fields in patterns
1 parent d778203 commit 21f8326

File tree

7 files changed

+96
-38
lines changed

7 files changed

+96
-38
lines changed

compiler/rustc_typeck/src/check/pat.rs

+49-9
Original file line numberDiff line numberDiff line change
@@ -1121,7 +1121,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11211121
if no_accessible_unmentioned_fields {
11221122
unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields));
11231123
} else {
1124-
unmentioned_err = Some(self.error_unmentioned_fields(pat, &unmentioned_fields));
1124+
unmentioned_err =
1125+
Some(self.error_unmentioned_fields(pat, &unmentioned_fields, &fields));
11251126
}
11261127
}
11271128
match (inexistent_fields_err, unmentioned_err) {
@@ -1376,6 +1377,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13761377
&self,
13771378
pat: &Pat<'_>,
13781379
unmentioned_fields: &[(&ty::FieldDef, Ident)],
1380+
fields: &'tcx [hir::FieldPat<'tcx>],
13791381
) -> DiagnosticBuilder<'tcx> {
13801382
let field_names = if unmentioned_fields.len() == 1 {
13811383
format!("field `{}`", unmentioned_fields[0].1)
@@ -1395,14 +1397,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13951397
field_names
13961398
);
13971399
err.span_label(pat.span, format!("missing {}", field_names));
1398-
if self.tcx.sess.teach(&err.get_code().unwrap()) {
1399-
err.note(
1400-
"This error indicates that a pattern for a struct fails to specify a \
1401-
sub-pattern for every one of the struct's fields. Ensure that each field \
1402-
from the struct's definition is mentioned in the pattern, or use `..` to \
1403-
ignore unwanted fields.",
1404-
);
1405-
}
1400+
let len = unmentioned_fields.len();
1401+
let (prefix, postfix, sp) = match fields {
1402+
[] => match &pat.kind {
1403+
PatKind::Struct(path, [], false) => {
1404+
(" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi()))
1405+
}
1406+
_ => return err,
1407+
},
1408+
[.., field] => (
1409+
match pat.kind {
1410+
PatKind::Struct(_, [_, ..], _) => ", ",
1411+
_ => "",
1412+
},
1413+
"",
1414+
field.span.shrink_to_hi(),
1415+
),
1416+
};
1417+
err.span_suggestion(
1418+
sp,
1419+
&format!(
1420+
"include the missing field{} in the pattern",
1421+
if len == 1 { "" } else { "s" },
1422+
),
1423+
format!(
1424+
"{}{}{}",
1425+
prefix,
1426+
unmentioned_fields
1427+
.iter()
1428+
.map(|(_, name)| name.to_string())
1429+
.collect::<Vec<_>>()
1430+
.join(", "),
1431+
postfix,
1432+
),
1433+
Applicability::MachineApplicable,
1434+
);
1435+
err.span_suggestion(
1436+
sp,
1437+
&format!(
1438+
"if you don't care about {} missing field{}, you can explicitely ignore {}",
1439+
if len == 1 { "this" } else { "these" },
1440+
if len == 1 { "" } else { "s" },
1441+
if len == 1 { "it" } else { "them" },
1442+
),
1443+
format!("{}..{}", prefix, postfix),
1444+
Applicability::MachineApplicable,
1445+
);
14061446
err
14071447
}
14081448

src/test/ui/error-codes/E0027-teach.rs

-15
This file was deleted.

src/test/ui/error-codes/E0027-teach.stderr

-11
This file was deleted.

src/test/ui/error-codes/E0027.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ fn main() {
77
let d = Dog { name: "Rusty".to_string(), age: 8 };
88

99
match d {
10-
Dog { age: x } => {}
11-
//~^ ERROR pattern does not mention field `name`
10+
Dog { age: x } => {} //~ ERROR pattern does not mention field `name`
11+
}
12+
match d {
13+
Dog {} => {} //~ ERROR pattern does not mention fields `name`, `age`
1214
}
1315
}

src/test/ui/error-codes/E0027.stderr

+25-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,31 @@ error[E0027]: pattern does not mention field `name`
33
|
44
LL | Dog { age: x } => {}
55
| ^^^^^^^^^^^^^^ missing field `name`
6+
|
7+
help: include the missing field in the pattern
8+
|
9+
LL | Dog { age: x, name } => {}
10+
| ^^^^^^
11+
help: if you don't care about this missing field, you can explicitely ignore it
12+
|
13+
LL | Dog { age: x, .. } => {}
14+
| ^^^^
15+
16+
error[E0027]: pattern does not mention fields `name`, `age`
17+
--> $DIR/E0027.rs:13:9
18+
|
19+
LL | Dog {} => {}
20+
| ^^^^^^ missing fields `name`, `age`
21+
|
22+
help: include the missing fields in the pattern
23+
|
24+
LL | Dog { name, age } => {}
25+
| ^^^^^^^^^^^^^
26+
help: if you don't care about these missing fields, you can explicitely ignore them
27+
|
28+
LL | Dog { .. } => {}
29+
| ^^^^^^
630

7-
error: aborting due to previous error
31+
error: aborting due to 2 previous errors
832

933
For more information about this error, try `rustc --explain E0027`.

src/test/ui/structs/struct-field-cfg.stderr

+9
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ error[E0027]: pattern does not mention field `present`
1717
|
1818
LL | let Foo { #[cfg(any())] present: () } = foo;
1919
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `present`
20+
|
21+
help: include the missing field in the pattern
22+
|
23+
LL | let Foo { present } = foo;
24+
| ^^^^^^^^^^^
25+
help: if you don't care about this missing field, you can explicitely ignore it
26+
|
27+
LL | let Foo { .. } = foo;
28+
| ^^^^^^
2029

2130
error[E0026]: struct `Foo` does not have a field named `absent`
2231
--> $DIR/struct-field-cfg.rs:16:42

src/test/ui/structs/struct-pat-derived-error.stderr

+9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ error[E0027]: pattern does not mention fields `b`, `c`
1515
|
1616
LL | let A { x, y } = self.d;
1717
| ^^^^^^^^^^ missing fields `b`, `c`
18+
|
19+
help: include the missing fields in the pattern
20+
|
21+
LL | let A { x, y, b, c } = self.d;
22+
| ^^^^^^
23+
help: if you don't care about these missing fields, you can explicitely ignore them
24+
|
25+
LL | let A { x, y, .. } = self.d;
26+
| ^^^^
1827

1928
error: aborting due to 3 previous errors
2029

0 commit comments

Comments
 (0)