Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Better error message when missing prefix in multiple patterns #50831

Closed
fbenkstein opened this issue May 17, 2018 · 6 comments · Fixed by #63406
Closed

Better error message when missing prefix in multiple patterns #50831

fbenkstein opened this issue May 17, 2018 · 6 comments · Fixed by #63406
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-feature-request Category: A feature request, i.e: not implemented / a PR.

Comments

@fbenkstein
Copy link

Given the example code:

enum E { A, B, C }
fn f() -> E { unimplemented!(); }

fn main() {
    match f() {
        A => print!("It was A!"),
        _ => print!("Something else"),
    }
}

I get a really nice warning message about what I did wrong:

warning[E0170]: pattern binding `A` is named the same as one of the variants of the type `E`
 --> src/main.rs:6:9
  |
6 |         A => print!("It was A!"),
  |         ^
  |
  = help: if you meant to match on a variant, consider making the path in the pattern qualified: `E::A`

However, if I change the main function to match multiple patterns:

fn main() {
    match f() {
        A => print!("It was A!"),
        B | C => print!("It was B or C!"),
    }
}

The error message is really confusing with no hint how to fix it:

error[E0408]: variable `B` is not bound in all patterns
 --> src/main.rs:8:13
  |
8 |         B | C => print!("It was B or C!"),
  |         -   ^ pattern doesn't bind `B`
  |         |
  |         variable not in all patterns

Please expand the error message for the second case to look a bit more like the first case.

@kennytm kennytm added A-diagnostics Area: Messages for errors, warnings, and lints C-feature-request Category: A feature request, i.e: not implemented / a PR. labels May 17, 2018
@estebank
Copy link
Contributor

Triage: no change.

We need to supply the line

 = help: if you meant to match on a variant, consider making the path in the pattern qualified: `E::A`

in E0408.

@jakubadamw
Copy link
Contributor

@estebank, so I thought I would implement the change you've proposed but have been thinking how best to restrict the kinds of cases where this help note would be appended to the error as I figured it may be rather noisy and/or confusing within the context of some false negatives. So during resolution we of course cannot look at the types to see if it's possible we're matching against an enum. But what do you think about having the help note kick in only if the binding starts with an upper case letter? I know this is a convention that should not really be a concern of the compiler but seeing that using it would only make the diagnostic note a bit more fine-grained, perhaps it's not a terrible idea?

@estebank
Copy link
Contributor

estebank commented Aug 8, 2019

@jakubadamw we already do that in some places, like the parser to infer intent, but in this case how would you figure out that you want to suggest E::B and E::C without resolving E?

I believe a more holistic solution would be to detect "variable not bound in all patterns" errors where all bindings are single idents, record that fact while throwing the current error and recovering as if there had been a single variable, and later when we have access to the machinery E0170 uses emit a warning suggesting E::B and E::C. It is a bit more involved but if we recover as if only B had been present the current diagnostic should kick in suggesting E::B (leaving E::C without a suggestion).


Edit: that won't work as things stand, as the warning won't be emitted today if there are errors, I think. That would also need to be changed to make it always be emitted :-/

@jakubadamw
Copy link
Contributor

jakubadamw commented Aug 9, 2019

@estebank, no, I didn't mean to say we need to suggest possible variants. I too concluded that it's non-trivial with the current ordering of passes and the early bailout (indeed, type checking is impossible without resolution succeeding).

I was going to add the help note you proposed back in May, just that I would make it dependent on bindings having a Variant-alike naming. From what you're saying there's a precedent in libsyntax, so I guess this is an acceptable solution? I'll make a PR then.

@estebank
Copy link
Contributor

estebank commented Aug 9, 2019

@jakubadamw sorry, I misunderstood. Go ahead, it sounds good.

@jakubadamw
Copy link
Contributor

@estebank, no, it's likely me who wasn't clear enough. :) I submitted a PR.

bors added a commit that referenced this issue Aug 9, 2019
…qualified-path, r=<try>

Suggest using a qualified path in patterns with inconsistent bindings

A program like the following one:

```rust
enum E { A, B, C }
fn f(x: E) -> bool {
    match x {
        A | B => false,
        C => true
    }
}
```

is rejected by the compiler due to `E` variant paths not being in scope.
In this case `A`, `B` are resolved as pattern bindings and consequently
the pattern is considered invalid as the inner or-patterns do not bind
to the same set of identifiers.

This is expected but the compiler errors that follow could be surprising
or confusing to some users. This commit adds a help note explaining that
if the user desired to match against variants or consts, they should use
a qualified path. The help note is restricted to cases where the identifier
starts with an upper-case sequence so as to reduce the false negatives.

Since this happens during resolution, there's no clean way to check what
it is the patterns match against. The syntactic criterium, however, is in line
with the convention that's assumed by the `non-camel-case-types` lint.

Fixes #50831.
Centril added a commit to Centril/rust that referenced this issue Aug 12, 2019
…es-suggest-qualified-path, r=petrochenkov

Suggest using a qualified path in patterns with inconsistent bindings

A program like the following one:

```rust
enum E { A, B, C }
fn f(x: E) -> bool {
    match x {
        A | B => false,
        C => true
    }
}
```

is rejected by the compiler due to `E` variant paths not being in scope.
In this case `A`, `B` are resolved as pattern bindings and consequently
the pattern is considered invalid as the inner or-patterns do not bind
to the same set of identifiers.

This is expected but the compiler errors that follow could be surprising
or confusing to some users. This commit adds a help note explaining that
if the user desired to match against variants or consts, they should use
a qualified path. The help note is restricted to cases where the identifier
starts with an upper-case sequence so as to reduce the false negatives.

Since this happens during resolution, there's no clean way to check what
it is the patterns match against. The syntactic criterium, however, is in line
with the convention that's assumed by the `non-camel-case-types` lint.

Fixes rust-lang#50831.
Centril added a commit to Centril/rust that referenced this issue Aug 12, 2019
…es-suggest-qualified-path, r=petrochenkov

Suggest using a qualified path in patterns with inconsistent bindings

A program like the following one:

```rust
enum E { A, B, C }
fn f(x: E) -> bool {
    match x {
        A | B => false,
        C => true
    }
}
```

is rejected by the compiler due to `E` variant paths not being in scope.
In this case `A`, `B` are resolved as pattern bindings and consequently
the pattern is considered invalid as the inner or-patterns do not bind
to the same set of identifiers.

This is expected but the compiler errors that follow could be surprising
or confusing to some users. This commit adds a help note explaining that
if the user desired to match against variants or consts, they should use
a qualified path. The help note is restricted to cases where the identifier
starts with an upper-case sequence so as to reduce the false negatives.

Since this happens during resolution, there's no clean way to check what
it is the patterns match against. The syntactic criterium, however, is in line
with the convention that's assumed by the `non-camel-case-types` lint.

Fixes rust-lang#50831.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-feature-request Category: A feature request, i.e: not implemented / a PR.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants