Skip to content

unreachable pattern lint should report some (or all) of the earlier match arms that subsume the unreachable one #127870

Closed
@pnkfelix

Description

@pnkfelix

Code

enum Sym { A(i32, i32), B, C }

fn foo(s: Sym) -> &'static str {
    match s {
        Sym::B    => "B",
        Sym::A(_, 0) => "Am,0",
        Sym::A(0, _) => "A0,n",
        /* imagine a *lot* of other match arms inserted in here */
        Sym::C       => "C",
        Sym::A(0, 0) => "A0,0",
        Sym::A(_, _) => "Am,n",
    }
}

fn main() {
    foo(Sym::A(0, 0));
    foo(Sym::A(1, 1));
    foo(Sym::B);
    foo(Sym::C);
}

Current output

warning: unreachable pattern
  --> src/main.rs:10:9
   |
10 |         Sym::A(0, 0) => "A0,0",
   |         ^^^^^^^^^^^^
   |
   = note: `#[warn(unreachable_patterns)]` on by default

Desired output

warning: unreachable pattern
  --> src/main.rs:10:9
   |
10 |         Sym::A(0, 0) => "A0,0",
   |         ^^^^^^^^^^^^
   |
   = note: `#[warn(unreachable_patterns)]` on by default
   |
   = note: the first pattern that makes this pattern unreachable is:
  --> src/main.rs:6:9
   |
 6 |         Sym::A(_, 0) => "Am,0",
   |         ^^^^^^^^^^^^

Rationale and extra context

I was recently adding a new enum variant that had a ton of other enum variants. I had to update an associated match expression to include it. Then, at some later point, I forgot that I had updated that match expression, redundantly added new match arms for the same variant, and got the above diangostic (which was set to be denied in my project and so it was a hard error).

I spent a little while puzzling over how the pattern could possibly be unreachable before I realized my mistake, in part because the list was so long that I had inserted the new variants at different points in the (unsorted) series of match arms. It was relatively trivial for me to diagnose in my own case, but I think my example above helps illustrate hypothetical scenarios where the compiler could do this mechanical work for us.

(Another options might be to report all the arms that would each independently subsume the unreachable one, as I have two such arms in my example above. But I'm not sure it would be worth the effort of computing that set ... its probably good enough to give the user the first counter-example and let them iteratively invoke the compiler if that's the usage pattern they want to follow.)

Other cases

No response

Rust Version

playground nightly version: 1.81.0-nightly

(2024-07-12 c6727fc9b5c64cefa726)

Anything else?

No response

Metadata

Metadata

Assignees

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsA-exhaustiveness-checkingRelating to exhaustiveness / usefulness checking of patternsA-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.A-patternsRelating to patterns and pattern matchingD-terseDiagnostics: An error or lint that doesn't give enough information about the problem at hand.L-unreachable_patternsLint: unreachable_patternsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions