Refutability: Whether a Pattern Might Fail to Match

Patterns are either irrefutable (always match) or refutable (can fail to match).

Irrefutable Patterns

  • x in let x = 5
  • (a, b) in let (a, b) = (1, 2)
  • Always succeed, can’t fail

Refutable Patterns

  • Some(x) in if let Some(x) = value
  • Can fail if value doesn’t match expected shape

Context Requirements

Irrefutable patterns only:

  • let statements
  • Function parameters
  • for loops

Refutable patterns accepted:

  • if let expressions
  • while let expressions
  • match arms (except final arm)

Common Errors

Using refutable pattern with let:

fn main() {
    let some_option_value: Option<i32> = None;
    let Some(x) = some_option_value;
}

Error:

$ cargo run
   Compiling patterns v0.1.0 (file:///projects/patterns)
error[E0005]: refutable pattern in local binding
 --> src/main.rs:3:9
  |
3 |     let Some(x) = some_option_value;
  |         ^^^^^^^ pattern `None` not covered
  |
  = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
  = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html
  = note: the matched value is of type `Option<i32>`
help: you might want to use `let else` to handle the variant that isn't matched
  |
3 |     let Some(x) = some_option_value else { todo!() };
  |                                     ++++++++++++++++

For more information about this error, try `rustc --explain E0005`.
error: could not compile `patterns` (bin "patterns") due to 1 previous error

Fix with let...else:

fn main() {
    let some_option_value: Option<i32> = None;
    let Some(x) = some_option_value else {
        return;
    };
}

Using irrefutable pattern with if let:

fn main() {
    let x = 5 else {
        return;
    };
}

Warning:

$ cargo run
   Compiling patterns v0.1.0 (file:///projects/patterns)
warning: irrefutable `let...else` pattern
 --> src/main.rs:2:5
  |
2 |     let x = 5 else {
  |     ^^^^^^^^^
  |
  = note: this pattern will always match, so the `else` clause is useless
  = help: consider removing the `else` clause
  = note: `#[warn(irrefutable_let_patterns)]` on by default

warning: `patterns` (bin "patterns") generated 1 warning
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.39s
     Running `target/debug/patterns`

Summary: Use the right pattern type for the context. The compiler enforces these rules to prevent logic errors.