Skip to content

Commit 696aaad

Browse files
committed
Auto merge of #109760 - MaciejWas:struct-tuple-field-names-suggestion, r=jackh726
Better diagnostic when pattern matching tuple structs Fixes #108284 When trying to pattern match a tuple struct we might get a flawed error message if there are missing fields. E.g. ``` let x = Foo(100, 200); if let Foo { 0: bar } = x { ... } ``` Produces this error: ``` error[E0769]: tuple variant `Foo` written as struct variant --> hello.rs:5:12 | 5 | if let Foo { 0: foo } = x { | ^^^^^^^^^^^^^^ | help: use the tuple variant pattern syntax instead | 5 | if let Foo(_, _) = x { | ~~~~~~ ``` Which doesn't highlight that we can still use the struct syntax but we need to fill missing fields. This pr changes this error to: ``` error[E0027]: pattern does not mention field `1` --> hello.rs:5:12 | 5 | if let Foo { 0: foo } = x { | ^^^^^^^^^^^^^^ missing field `1` | help: include the missing field in the pattern | 5 | if let Foo { 0: foo, 1: _ } = x { | ~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | 5 | if let Foo { 0: foo, .. } = x { | ~~~~~~ ```
2 parents 39bf777 + 3b38dd9 commit 696aaad

File tree

3 files changed

+42
-4
lines changed

3 files changed

+42
-4
lines changed

compiler/rustc_hir_typeck/src/pat.rs

+21-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ pointers. If you encounter this error you should try to avoid dereferencing the
3737
You can read more about trait objects in the Trait Objects section of the Reference: \
3838
https://doc.rust-lang.org/reference/types.html#trait-objects";
3939

40+
fn is_number(text: &str) -> bool {
41+
text.chars().all(|c: char| c.is_digit(10))
42+
}
43+
4044
/// Information about the expected type at the top level of type checking a pattern.
4145
///
4246
/// **NOTE:** This is only for use by diagnostics. Do NOT use for type checking logic!
@@ -1673,7 +1677,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16731677
fields: &'tcx [hir::PatField<'tcx>],
16741678
variant: &ty::VariantDef,
16751679
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
1676-
if let (Some(CtorKind::Fn), PatKind::Struct(qpath, ..)) = (variant.ctor_kind(), &pat.kind) {
1680+
if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) =
1681+
(variant.ctor_kind(), &pat.kind)
1682+
{
1683+
let is_tuple_struct_match = !pattern_fields.is_empty()
1684+
&& pattern_fields.iter().map(|field| field.ident.name.as_str()).all(is_number);
1685+
if is_tuple_struct_match {
1686+
return None;
1687+
}
1688+
16771689
let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
16781690
s.print_qpath(qpath, false)
16791691
});
@@ -1895,7 +1907,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18951907
prefix,
18961908
unmentioned_fields
18971909
.iter()
1898-
.map(|(_, name)| name.to_string())
1910+
.map(|(_, name)| {
1911+
let field_name = name.to_string();
1912+
if is_number(&field_name) {
1913+
format!("{}: _", field_name)
1914+
} else {
1915+
field_name
1916+
}
1917+
})
18991918
.collect::<Vec<_>>()
19001919
.join(", "),
19011920
if have_inaccessible_fields { ", .." } else { "" },

tests/ui/structs/struct-tuple-field-names.rs

+3
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,7 @@ fn main() {
1212
match y {
1313
S { } => {} //~ ERROR: tuple variant `S` written as struct variant [E0769]
1414
}
15+
16+
if let E::S { 0: a } = x { //~ ERROR: pattern does not mention field `1`
17+
}
1518
}

tests/ui/structs/struct-tuple-field-names.stderr

+18-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,22 @@ help: use the tuple variant pattern syntax instead
2020
LL | S(_, _) => {}
2121
| ~~~~~~
2222

23-
error: aborting due to 2 previous errors
23+
error[E0027]: pattern does not mention field `1`
24+
--> $DIR/struct-tuple-field-names.rs:16:12
25+
|
26+
LL | if let E::S { 0: a } = x {
27+
| ^^^^^^^^^^^^^ missing field `1`
28+
|
29+
help: include the missing field in the pattern
30+
|
31+
LL | if let E::S { 0: a, 1: _ } = x {
32+
| ~~~~~~~~
33+
help: if you don't care about this missing field, you can explicitly ignore it
34+
|
35+
LL | if let E::S { 0: a, .. } = x {
36+
| ~~~~~~
37+
38+
error: aborting due to 3 previous errors
2439

25-
For more information about this error, try `rustc --explain E0769`.
40+
Some errors have detailed explanations: E0027, E0769.
41+
For more information about an error, try `rustc --explain E0027`.

0 commit comments

Comments
 (0)