Skip to content

Commit

Permalink
Auto merge of rust-lang#109760 - MaciejWas:struct-tuple-field-names-s…
Browse files Browse the repository at this point in the history
…uggestion, r=jackh726

Better diagnostic when pattern matching tuple structs

Fixes rust-lang#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 {
  |                        ~~~~~~
```
  • Loading branch information
bors committed Apr 9, 2023
2 parents 39bf777 + 3b38dd9 commit 696aaad
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 4 deletions.
23 changes: 21 additions & 2 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand Down Expand Up @@ -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)
});
Expand Down Expand Up @@ -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 { "" },
Expand Down
3 changes: 3 additions & 0 deletions tests/ui/structs/struct-tuple-field-names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`
}
}
20 changes: 18 additions & 2 deletions tests/ui/structs/struct-tuple-field-names.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

0 comments on commit 696aaad

Please sign in to comment.