diff options
| author | bors <bors@rust-lang.org> | 2023-04-09 20:57:06 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-04-09 20:57:06 +0000 |
| commit | 696aaad58c57a589f6fb2ecff5bae2eec581cb71 (patch) | |
| tree | e7e3dba6b267106715eac55d28834b6dec753cc8 | |
| parent | 39bf7777aab9ac1f6b0802cd52cd91d6e021aa91 (diff) | |
| parent | 3b38dd91126a647334af07d772ad809422918e5a (diff) | |
| download | rust-696aaad58c57a589f6fb2ecff5bae2eec581cb71.tar.gz rust-696aaad58c57a589f6fb2ecff5bae2eec581cb71.zip | |
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 {
| ~~~~~~
```
| -rw-r--r-- | compiler/rustc_hir_typeck/src/pat.rs | 23 | ||||
| -rw-r--r-- | tests/ui/structs/struct-tuple-field-names.rs | 3 | ||||
| -rw-r--r-- | tests/ui/structs/struct-tuple-field-names.stderr | 20 |
3 files changed, 42 insertions, 4 deletions
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 241535b29c5..af0bd26dec5 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -37,6 +37,10 @@ pointers. If you encounter this error you should try to avoid dereferencing the You can read more about trait objects in the Trait Objects section of the Reference: \ https://doc.rust-lang.org/reference/types.html#trait-objects"; +fn is_number(text: &str) -> bool { + text.chars().all(|c: char| c.is_digit(10)) +} + /// Information about the expected type at the top level of type checking a pattern. /// /// **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> { fields: &'tcx [hir::PatField<'tcx>], variant: &ty::VariantDef, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { - if let (Some(CtorKind::Fn), PatKind::Struct(qpath, ..)) = (variant.ctor_kind(), &pat.kind) { + if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) = + (variant.ctor_kind(), &pat.kind) + { + let is_tuple_struct_match = !pattern_fields.is_empty() + && pattern_fields.iter().map(|field| field.ident.name.as_str()).all(is_number); + if is_tuple_struct_match { + return None; + } + let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { s.print_qpath(qpath, false) }); @@ -1895,7 +1907,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prefix, unmentioned_fields .iter() - .map(|(_, name)| name.to_string()) + .map(|(_, name)| { + let field_name = name.to_string(); + if is_number(&field_name) { + format!("{}: _", field_name) + } else { + field_name + } + }) .collect::<Vec<_>>() .join(", "), if have_inaccessible_fields { ", .." } else { "" }, diff --git a/tests/ui/structs/struct-tuple-field-names.rs b/tests/ui/structs/struct-tuple-field-names.rs index 7bd54af1dbe..33f264aa250 100644 --- a/tests/ui/structs/struct-tuple-field-names.rs +++ b/tests/ui/structs/struct-tuple-field-names.rs @@ -12,4 +12,7 @@ fn main() { match y { S { } => {} //~ ERROR: tuple variant `S` written as struct variant [E0769] } + + if let E::S { 0: a } = x { //~ ERROR: pattern does not mention field `1` + } } diff --git a/tests/ui/structs/struct-tuple-field-names.stderr b/tests/ui/structs/struct-tuple-field-names.stderr index 5494c29a6fd..0b837a47a82 100644 --- a/tests/ui/structs/struct-tuple-field-names.stderr +++ b/tests/ui/structs/struct-tuple-field-names.stderr @@ -20,6 +20,22 @@ help: use the tuple variant pattern syntax instead LL | S(_, _) => {} | ~~~~~~ -error: aborting due to 2 previous errors +error[E0027]: pattern does not mention field `1` + --> $DIR/struct-tuple-field-names.rs:16:12 + | +LL | if let E::S { 0: a } = x { + | ^^^^^^^^^^^^^ missing field `1` + | +help: include the missing field in the pattern + | +LL | if let E::S { 0: a, 1: _ } = x { + | ~~~~~~~~ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | if let E::S { 0: a, .. } = x { + | ~~~~~~ + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0769`. +Some errors have detailed explanations: E0027, E0769. +For more information about an error, try `rustc --explain E0027`. |
