Skip to content

unhelpful compiler error when using curly braces with enum variants in matches #79652

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
woody77 opened this issue Dec 3, 2020 · 5 comments
Closed
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` C-bug Category: This is a bug. D-incorrect Diagnostics: A diagnostic that is giving misleading or incorrect information. D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@woody77
Copy link

woody77 commented Dec 3, 2020

I tried this code:

enum Foo {
    Bar(i32),
}

fn main() {
   let f = Foo::Bar(3);
   
   // compiler error that could be clearer:
   if let Foo::Bar{} = f {
      println!("hello");
   }
   
   // better suggestion for the compiler error:
   if let Foo::Bar(_) = f {
       println!("goodbye");
   }
}

playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4984d4711270142a41aa9a0e77eb82d8

I expected to see this happen:

A suggestion to use a match pattern such as:

if let Foo::Bar(val) = f {

or

if let Foo::Bar(_) = f {

Instead, this happened:

error[E0027]: pattern does not mention field `0`
 --> src/main.rs:9:11
  |
9 |    if let Foo::Bar{} = f {
  |           ^^^^^^^^^^ missing field `0`
  |
help: include the missing field in the pattern
  |
9 |    if let Foo::Bar { 0 } = f {
  |                    ^^^^^
help: if you don't care about this missing field, you can explicitely ignore it
  |
9 |    if let Foo::Bar { .. } = f {
  |                    ^^^^^^
@woody77 woody77 added the C-bug Category: This is a bug. label Dec 3, 2020
@JohnTitor JohnTitor added A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` D-incorrect Diagnostics: A diagnostic that is giving misleading or incorrect information. D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 3, 2020
@GuillaumeGomez
Copy link
Member

Well, you can in fact do:

if let Foo::Bar { 0: i } = f {
    println!("hello");
}

@PatchMixolydic
Copy link
Contributor

PatchMixolydic commented Dec 4, 2020

Incidentally, placing just an identifier in the braces (without the field name) produces a clearer diagnostic, which may also be useful in the case presented in the report:

if let Foo::Bar{ foo } = f {
   println!("hello");
}
error[E0769]: tuple variant `Foo::Bar` written as struct variant
 --> src/main.rs:9:11
  |
9 |    if let Foo::Bar{ foo } = f {
  |           ^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `Foo::Bar(foo)`

Using 0 directly as the suggestion in the report suggests (without binding the field to a valid identifier like in the above comment) causes an error, as one might expect:

   if let Foo::Bar{ 0 } = f {
      println!("hello");
   }
error: expected identifier, found `0`
 --> src/main.rs:9:21
  |
9 |    if let Foo::Bar{ 0 } = f {
  |           --------  ^ expected identifier
  |           |
  |           while parsing the fields for this pattern

I'd posit that using the struct syntax to bind values from a tuple variant would be rather strange/unexpected, so the diagnostics should probably push towards the use of the tuple syntax instead. I'm only one person, though, and I'm far from an expert on these matters.

@LeSeulArtichaut LeSeulArtichaut self-assigned this Dec 7, 2020
@LeSeulArtichaut
Copy link
Contributor

Also note that this diagnostic gets emitted for any tuple struct, not just enum variants:

struct Bar(i32);

fn main() {
   let f = Bar(3);
   
   // compiler error that could be clearer:
   if let Bar{} = f {
      println!("hello");
   }
}
error[E0027]: pattern does not mention field `0`
 --> src/main.rs:7:11
  |
7 |    if let Bar{} = f {
  |           ^^^^^ missing field `0`
  |
help: include the missing field in the pattern
  |
7 |    if let Bar { 0 } = f {
  |               ^^^^^
help: if you don't care about this missing field, you can explicitely ignore it
  |
7 |    if let Bar { .. } = f {
  |               ^^^^^^

@LeSeulArtichaut
Copy link
Contributor

This seems to be fixed now:

error[E0769]: tuple variant `Foo::Bar` written as struct variant
 --> src/main.rs:9:11
  |
9 |    if let Foo::Bar{} = f {
  |           ^^^^^^^^^^
  |
help: use the tuple variant pattern syntax instead
  |
9 |    if let Foo::Bar(_) = f {
  |                   ^^^

@Dylan-DPC
Copy link
Member

Closing this as fixed

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` C-bug Category: This is a bug. D-incorrect Diagnostics: A diagnostic that is giving misleading or incorrect information. D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants