match Covers Every Case, and the Refusal Is This Compiler’sStatus: Superseded by ADR-291 — its D1-D3 are D19-D21 there
Date: September 19, 2026
Target Version: Nikaia 0.0.30
Related: ADR-145 (the catch-all arm is else),
ADR-137 §4 (which left this open), ADR-023 D1 (an
error type is an enum), ADR-024 D1 (the ledger, and the absence
of a claim), Part I 3.4, Part III C.1 and C.4
ADR-137 §4 left exhaustiveness open — a question about types
this compiler does not yet answer. It is not open below: Rust refuses a
non-exhaustive match, so a Nikaia match with a missing variant was refused
by the backend, in its words, on a Nikaia line. That is
Part III C.1’s class, and all this decides is whose
message the reader gets.
The page already promised the rule. Part I 3.4’s own first sentence says a
match ensures that every possible case is handled, and nothing in this
compiler ensured it.
else is how the rest is said.match code {
200 => "ok",
404 => "not found",
else => "other", // required: the set of `i64` is not written out
}
match op {
Op::Plus => a + b,
Op::Times => a * b, // complete: the enum has two variants
}
A match over an enum is complete when every variant is named, and needs
no else; over anything else it needs one, because the set is not enumerable
in arms. NK1151 names what is missing: the variants for an enum, and else
for everything else.
else was _ when the question was asked, and the answer arrived one
record later than the spelling (ADR-145).
other => … binds and matches anything, so a match that ends in one is
complete. That is not a special case bolted on: it is what the arm already
means (Part I 3.4), read by the same rule else is.
Part III C.4: a refusal on a guess is a correct
program refused, and it is the worse of the two mistakes. A match over a
value this compiler could not type keeps the answer it has today — the
backend’s — and gets a better one the day the type does.
This is the one place the rule is weaker than it reads, and it is the same weakness every other check here has for the same reason.
enum gains a variant and every match over it that has no else is
refused here — which is the point of the rule and is what a ledger the
build reads makes possible across a package boundary too.match, and one refusal.200..299 and 1 | 2 are
ADR-137 D1’s and unbuilt; when they land, whether a set of
ranges covers an integer is arithmetic this record does not ask for. An
else covers meanwhile.Event::Click(Point { x, .. }) — which
is the same question one level down and waits on the same record.All of it, and the shape it took is smaller than the question suggested: the check is does anything here catch everything, and only where nothing does is the scrutinee’s type asked about at all.
An enum’s variants come from the same map NK1135 and the variant rule
already read, so a package’s enum is covered as this file’s is the day its
ledger is in hand.
The bool case is the one that is neither, and it is written out: true
and false are two arms and a complete match, which no enum map knows and no
else is needed for. Without it match flag { true => 1, false => 0 } — which
Rust accepts — would have been refused, and that is C.4 exactly.
A char, an i64 and a String need else, and the message says so
rather than listing a set nobody can write out.
Seven tests in crates/nikaia/tests/match_coverage.rs.