Files
Leonardo Maldonado 5f0b2079f8 feat: expand to 218 rules and refresh for the Rust 2024 edition
Add unsafe, concurrency, conversions, and pattern-matching categories plus rules across existing ones, and correct advice that was outdated for Rust 1.96.
2026-06-14 19:38:44 -03:00

2.7 KiB

pat-exhaustive-enum

Match owned enums exhaustively; avoid catch-all _ that hides new variants

Why It Matters

A _ => wildcard arm silently absorbs any variant added to an enum you own, converting what should be a compile-time error into a silent runtime no-op. Exhaustive matches let the compiler act as a checklist: add a variant, get a build failure everywhere it is unhandled. Reserve _ and .. for foreign #[non_exhaustive] enums, where the language requires a catch-all, and document why it is necessary.

Bad

#[derive(Debug)]
enum Status {
    Active,
    Pending,
    Closed,
}

fn describe(s: &Status) -> &'static str {
    match s {
        Status::Active => "active",
        _ => "inactive", // hides Status::Pending silently; adding a new variant goes unnoticed
    }
}

If Status::Suspended is later added, describe compiles and silently returns "inactive" for it — a logic bug the compiler never catches.

Good

#[derive(Debug)]
enum Status {
    Active,
    Pending,
    Closed,
}

fn describe(s: &Status) -> &'static str {
    match s {
        Status::Active => "active",
        Status::Pending => "pending",
        Status::Closed => "closed",
        // Adding Status::Suspended now causes a compile error here — intended.
    }
}

Grouping Variants with |

When several variants share the same handling, list them explicitly rather than falling back to _:

fn is_terminal(s: &Status) -> bool {
    match s {
        Status::Closed | Status::Pending => true,
        Status::Active => false,
    }
}

When _ Is Required: Foreign #[non_exhaustive] Enums

External crates may mark enums #[non_exhaustive], which means the compiler forces a wildcard. Document the intent:

// From a hypothetical external crate:
// #[non_exhaustive]
// pub enum TheirEvent { Click, Hover, /* ... future variants */ }

fn handle_event(event: &some_crate::TheirEvent) {
    match event {
        some_crate::TheirEvent::Click => { /* ... */ }
        some_crate::TheirEvent::Hover => { /* ... */ }
        // required by #[non_exhaustive]; intentionally a no-op for unknown variants
        _ => {}
    }
}

Clippy Lint

clippy::wildcard_enum_match_arm (part of clippy::restriction) warns when a wildcard arm in a match on a non-#[non_exhaustive] enum could be replaced with explicit variants. Enabling it catches drift over time.

See Also