match that does not cover every value
ErrorUnsafe fixA 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.
Sisu