Skip to content

Force ADT to be matched exhaustively (opposite of #[non_exhaustive]) #69930

@Aaron1011

Description

@Aaron1011

The #[non_exhaustive] attribute prevents exhaustively matching an enum outside of the defining crate. However, it's sometimes useful to have the opposite of this behavior - that is, prevent non-exhaustively matching an enum within the defining crate.

For example, non-exhaustively matching on DefPathData or TyKind is often the wrong choice. By writing an exhaustive match (explicitly mentioning all variants), any additions/removals from the enum will require explicit acknowledgment at the match site, helping to prevent bugs.

Examples from rustc:

// Nothing to do for these. Match exhaustively so this fails to compile when new
// variants are added.
StatementKind::AscribeUserType(..)
| StatementKind::FakeRead(..)
| StatementKind::Nop
| StatementKind::Retag(..)
| StatementKind::StorageLive(..) => {}
}

// N.B., deliberately force a compilation error if/when new fields are added.
let TraitItemRef { id, ident, ref kind, span: _, ref defaultness } = *trait_item_ref;

// N.B., deliberately force a compilation error if/when new fields are added.
let ImplItem {
hir_id: _,
ident,
ref vis,
ref defaultness,
attrs,
ref generics,
ref kind,
span: _,
} = *impl_item;

It would be useful to have a compiler lint to enforce this programmatically.

As an initial implementation, we could add an unstable attribute #[rustc_exhaustive] and an internal lint EXHAUSTIVE_MATCH. This lint fires on any non-exhaustive match or destructuring let expression (not if let/while let for single enum variants) that match on an ADT annotated with #[rustc_exhaustive]. Since this would be a lint, it could be allowed on a case-by-case basis (e.g. performing an early exit on TyKind::Error or TyKind::Infer).

If this proves useful, it could be made available to all Rust programs after an RFC.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-exhaustiveness-checkingRelating to exhaustiveness / usefulness checking of patternsA-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.C-feature-requestCategory: A feature request, i.e: not implemented / a PR.T-langRelevant to the language team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions