Skip to content

Commit 3b38dd9

Browse files
committed
better diagnostics for pattern matching tuple structs
Better diagnostic message when trying to pattern match a tuple struct with a struct pattern.
1 parent 82bfda8 commit 3b38dd9

File tree

3 files changed

+42
-4
lines changed

3 files changed

+42
-4
lines changed

compiler/rustc_hir_typeck/src/pat.rs

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

39+
fn is_number(text: &str) -> bool {
40+
text.chars().all(|c: char| c.is_digit(10))
41+
}
42+
3943
/// Information about the expected type at the top level of type checking a pattern.
4044
///
4145
/// **NOTE:** This is only for use by diagnostics. Do NOT use for type checking logic!
@@ -1671,7 +1675,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16711675
fields: &'tcx [hir::PatField<'tcx>],
16721676
variant: &ty::VariantDef,
16731677
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
1674-
if let (Some(CtorKind::Fn), PatKind::Struct(qpath, ..)) = (variant.ctor_kind(), &pat.kind) {
1678+
if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) =
1679+
(variant.ctor_kind(), &pat.kind)
1680+
{
1681+
let is_tuple_struct_match = !pattern_fields.is_empty()
1682+
&& pattern_fields.iter().map(|field| field.ident.name.as_str()).all(is_number);
1683+
if is_tuple_struct_match {
1684+
return None;
1685+
}
1686+
16751687
let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
16761688
s.print_qpath(qpath, false)
16771689
});
@@ -1893,7 +1905,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18931905
prefix,
18941906
unmentioned_fields
18951907
.iter()
1896-
.map(|(_, name)| name.to_string())
1908+
.map(|(_, name)| {
1909+
let field_name = name.to_string();
1910+
if is_number(&field_name) {
1911+
format!("{}: _", field_name)
1912+
} else {
1913+
field_name
1914+
}
1915+
})
18971916
.collect::<Vec<_>>()
18981917
.join(", "),
18991918
if have_inaccessible_fields { ", .." } else { "" },

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

Lines changed: 3 additions & 0 deletions
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

Lines changed: 18 additions & 2 deletions
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)