Sisu
E0130

match that does not cover every value

ErrorUnsafe fix

Built from the repository at commit a8614dc.

A match needs an arm for every value its scrutinee can hold. When a value reaches no arm, the error names one such value as a pattern, at the match keyword: "match does not cover Mul(_, _)". When an arm has the missing value's variant at the top, a label on that arm says which part of the variant it covers: "Add(Num(_), _) covers only Num(_), _". When a guarded arm may not match the value, a label on the match keyword says so: a guarded arm covers nothing, since its guard can be false.

Integers and chars are finite, so literals and ranges that together hold every value cover the type: 0..=127 and 128..=255 cover a u8. A missing integer or char is named as the first gap from the bottom, "match does not cover 10..=255", with the help "add _ =>"; so is a string, which only _ or a name covers.

An optional has two values to cover: None, and Some of each value inside. A missing value of an optional is named as a pattern at the optional's position: "match does not cover None", "match does not cover Some(None)" in an optional of an optional, or the missing variant of the enum inside, "match does not cover Square(_)".

Why

A match is an expression, so it must produce a value, or leave, for every input. Checking coverage when the program compiles turns a forgotten variant into an error at the match, instead of a crash when that value arrives. Rust and Swift reject such a match too. Adding a variant to an enum then points at every match that must handle it.

The unsafe fix adds _ => todo as the last arm. It is unsafe because a catch-all also takes every variant added later, which then goes unnoticed.

Broken

enum Expr {
    Num(i64)
    Add(Expr, Expr)
    Mul(Expr, Expr)
}

fn eval(e: Expr) -> i64 {
    match e {
        Num(n) => n
        Add(a, b) => eval(a) + eval(b)
    }
}

fn main() {
    print(eval(Expr.Add(Expr.Num(1), Expr.Num(2))))
    print(eval(Expr.Mul(Expr.Num(2), Expr.Num(3))))
}

What sisu says

error[E0130]: `match` does not cover `Mul(_, _)`
  --> E0130.sisu:8:5
   |
 8 |     match e {
   |     ^^^^^
   |
help: add a `_ =>` arm
   |
11 +         _ => todo
   |

sisu: 1 error
sisu: for more on a code, run `sisu explain <code>`: E0130

Fixed

enum Expr {
    Num(i64)
    Add(Expr, Expr)
    Mul(Expr, Expr)
}

fn eval(e: Expr) -> i64 {
    match e {
        Num(n) => n
        Add(a, b) => eval(a) + eval(b)
        Mul(a, b) => eval(a) * eval(b)
    }
}

fn main() {
    print(eval(Expr.Add(Expr.Num(1), Expr.Num(2))))
    print(eval(Expr.Mul(Expr.Num(2), Expr.Num(3))))
}

Related

  • W0006: an arm that no value reaches.