let Takes One Name, or a Flat Tuple of ThemStatus: Superseded by ADR-291 — its D1-D5 are D1-D5 there
Date: September 15, 2026
Target Version: Nikaia 0.0.8
Related: ADR-050 (overlap { … }, whose own line this makes a
program), ADR-037 D6 and D7 (the sharing floor a destructure
leaves alone), ADR-089 D2 (the parse-error note, whose shape this
copies)
let (user, rights, prefs) = overlap { … } // Part I 8.1.2
let (tx, rx) = channel::bounded(100) // Part II 12.5
Neither parsed. let takes one name, and a destructuring let is a form
the specification uses twice, for two different constructs, and defines nowhere
— Part I 2.1 introduces let with a name and says nothing about a pattern.
overlap { … } met this rather than made it: the construct is built and was
reached by its tuple in the meantime (let r = overlap { … }, then r.0),
which works and reads worse than what the page promises.
match has patterns already and this is not them. What the two sites need is
taking apart a tuple whose arity is known; a bigger answer would be a decision
rather than this repair.
Stmt::Let’s name: Ident became names: Vec<Ident>, so every reader had to
look — nineteen of them, which is the point. A second variant would be additive
and cheaper, and a walk that has to remember it is a walk that will forget it.
What each reader decided is worth having in one place, because three of them chose to decline rather than to handle it:
| reader | with several names |
|---|---|
| the checker | binds each name to the part at its index, or to ? |
| the emitter | Rust’s own tuple pattern — nothing to translate |
views |
marks every name a carrier, because a view reaches each part |
contracts::order |
opaque: it carries one bound name, so it declines to reorder |
contracts::sharing |
records no handle, leaving each part at ADR-037 D6’s atomic floor |
dsl |
skips: a deferred block is one value and cannot be bound to a tuple |
The last three are the same polarity three times: an analysis that cannot answer says nothing rather than guessing, and each of them fails safe — no reordering, no atomic taken away, no parameters claimed.
A value whose type this compiler cannot see is ?, and refusing a destructure
of one because it looks like the wrong width would refuse a correct program
(Part III C.4). What a wrong width costs today is the
language below saying so about a let the author did write, which is smaller
and honest. The day a tuple’s width is known for certain is the day to refuse it
here.
NK1136.let (a, b): T = … would have to say which name T is about and nothing
decides that. Refused rather than ignored, because ignoring it takes something
the author wrote and drops it.
It does not parse, and a bare parse error says a list of tokens — which does not
tell a reader that the shape is what is missing. parser::let_names_note
supplies the sentence, recognised from the rendering for
ADR-089 D2’s reason: the failure happens after ( has matched, so
the backend’s message is about the token it stopped at.
Part I 8.1.2’s own line is a program. channel::bounded is not, and for a
reason that has nothing to do with this: there is no channel
(#259).
Nothing else in the tree moves — every let in examples/, tests/samples/
and crates/nikaia-std/src/ binds one name, so the whole change is reachable
only by writing the new form.
#224’s entry closes — let takes one name, and the specification
writes it taking several.
_. It parses as a name and has since long before this form existed
(let _ = f() lowers today), so refusing it here would narrow something
already accepted and would say nothing about the single-name spelling beside
it. That it reaches Rust’s wildcard rather than a binding is a finding of
its own and is on #209.let (a: i64, b) = …) is written nowhere and would be a decision.contracts::order and contracts::sharing decline. Both are
deliberate holes with the safe polarity, and both close by carrying several
names rather than by changing a rule.let_names and let_name_tail in the grammar, parser::let_names_note,
Stmt::Let::names, Checker::tuple_let with NK1136, the emitter’s tuple
pattern, and the six readers above. Exercised by seven programs in
crates/nikaia/tests/tuple_let.rs — the shape compiled and run, Part I
8.1.2’s own line, a part answering for the type it was taken from, NK1136, the
nested refusal and its sentence, an unrelated bracket that must not get that
sentence, and the single-name form untouched.