rustenumsmatchexhaustive

Prevent Rest Condition in Rust Match Statement


I'm working on a rust project that relies heavily on match statements. Rust's exhaustive matching is a big part of the reason that we picked this language to work in, and I'm curious if it's possible to not allow matches against an enum to include a rest condition _ => {} -- rather, we want to ensure that every single match statement matches against every variant of the enum. This is because the enum variants will grow over time as the project undergoes long-term development, and we want to make sure that every variant is always matched against.

For example:

enum MyEnum {
    VariantA,
    VariantB,
    VariantC,
    VariantD,
}

impl MyEnum {
    fn some_method(&self) {
        match self {
            MyEnum::VariantA => todo!(),
            MyEnum::VariantB => todo!(),
            _ => todo!(),  // <-- DON'T ALLOW THIS
        }
    }
}

Currently, we are simply communicating never to use rest conditions like this, but we're wondering if there's a way to enforce this more thoroughly.

I tried to search for information about macros, VSCode extensions, or other ways of checking for/enforcing that no rest conditions are included in match statements, but couldn't find anything. I also couldn't find a clearly-defined name for these conditions -- I call them "rest conditions" but didn't find official rust vocabulary for such cases. Not knowing a more widely-used term might have also hurt my ability to search.


Solution

  • Yes. You can enforce that by turning on Clippy's wildcard_enum_match_arm lint. For example following code:

    #![deny(clippy::wildcard_enum_match_arm)]
    
    enum MyEnum {
        VariantA,
        VariantB,
        VariantC,
        VariantD,
    }
    
    impl MyEnum {
        fn some_method(&self) {
            match self {
                MyEnum::VariantA => todo!(),
                MyEnum::VariantB => todo!(),
                _ => todo!(),  // <-- DON'T ALLOW THIS
            }
        }
    }
    

    Will fail cargo clippy check with following error:

    error: wildcard match will also match any future added variants
      --> src/lib.rs:15:13
       |
    15 |             _ => todo!(),  // <-- DON'T ALLOW THIS
       |             ^ help: try: `MyEnum::VariantC | MyEnum::VariantD`
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_enum_match_arm
    note: the lint level is defined here
      --> src/lib.rs:1:9
       |
    1  | #![deny(clippy::wildcard_enum_match_arm)]
       |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^