catch That Names Every Error Type Arriving Is CompleteStatus: Accepted
Date: October 15, 2026
Answers: whether a match over a catch’s error needs else where it
names every type that can arrive (issue #625)
Related:
ADR-023 D4 (two axes: variants closed, types open; changed here);
ADR-280 D18 (else with more than one type; changed here);
ADR-308 D11 (NK2402, a grown set; changed here);
ADR-345 D2 (a fatal error is taken only by name);
ADR-351 (the set of a function value);
ADR-288 D32 (the author warned of a lost promise);
Part I 7.1; Part III C.3
Is the set of error types arriving at a catch closed? The compiler infers
it over the whole program (Part I 7.1), and a catch sees its sum. A match
over error that names a variant of every type in it covers everything that
can arrive. The rule so far asked for else all the same, because the set of
types was held to be open.
From memory, not checked against a current manual.
| Language | A handler over several error types |
|---|---|
| Rust | the error is one enum; a match naming every variant is exhaustive; a library opts out with #[non_exhaustive] |
| Swift (typed throws) | a catch over throws(E) is exhaustive over E |
| OCaml | polymorphic variants: a match over the inferred row is exhaustive |
| Java | checked exceptions: the list is written by hand, a catch for each is complete |
| Kotlin, C#, Python | unchecked: a handler is never complete |
| Option | Why it lost, or won |
|---|---|
A The set of types stays open: two or more need else |
a catch is never a proof that every failure is handled; the two axes of ADR-023 D4 keep two rules, though the reason for an open set there (a call behind dyn) no longer exists |
B The set is closed: a match naming every type is complete |
chosen (D1-D5) |
match over a catch’s error that names every type in the set is complete.The set of error types arriving at a catch is closed, as the variants of
one error type are. A match over error is complete where every non-fatal
type in the set is covered: each of its variants named, or the type taken by a
bare name. A fatal type need not be named: else does not take it either, and
it passes on (ADR-345 D2). else stays allowed, and takes whatever is not
named.
else.Where the set holds "?" (a call into code no ledger describes) or a
from(p) not yet replaced by what the caller passed (ADR-351 D4), a match
over it needs else: what cannot be named cannot be listed. It is NK1151.
match at the catch, narrated from the ledger.When a callee’s set gains a type, a match that was complete without else
no longer is, and it is NK1151. The message names the new type, the callee
and the call that brings it in, from the ledger diff, as NK2401 narrates a
broken borrow. A match with else, and a handler that does not match, take
the new error, and are told so with NK2402, a warning, as before.
pub function is warned when its set grows.Where the committed ledger has a set for a pub function and the build finds
it larger, the build warns (NK2404) at the statement that brings the new
type in, with the calls that lead there: a caller that names every type stops
building. Committing the ledger acknowledges it, as ADR-288 D32 does for a lost
sync. It is a warning to the author, not a classification of the change
(ADR-288 rejected that: the same change breaks some callers and not others).
match lowers with no catch-all arm.The generated sum (ADR-280 D15) is matched by its members; where every one is
named, no _ arm is written.
dyn;
there is no dyn (Part I: a trait is not a type), and the one residue left,
code no ledger describes, is D2’s."?" and an open from(p) are exactly what the compiler does not
know; listing is impossible there, and else is the honest handler.else. Whoever wants a handler that absorbs growth writes else, and keeps
ADR-308 D11’s warning.Rejected: A, above. Rejected: a marker on a library’s function that its
set may grow (Rust’s #[non_exhaustive]): a caller that wants robustness has
else already, and a word the author must remember is the kind this language
declines (ADR-258).
catch without else is a proof that every failure that can reach it is
handled; a fatal one still passes on unless named.NK2404), the caller is told why
(NK1151 with the ledger’s narration).NK2402 stays for handlers with else and for those that do not match.