Status: Superseded by ADR-281 — its D1-D3 are D20, D21 and D25 there; D4 is not carried Date: September 15, 2026 Target Version: Nikaia 0.0.8 Related: ADR-039 D10 (which decided the four doors and stated these two mistakes), ADR-064 (the type they are about), ADR-081 D2 (the expression span this does not have)
ADR-039 D10 gave shared mutable state four doors — get, set,
update, access — and named the two mistakes that come with them. Part III
Appendix C catalogued both, and nothing raised either:
error[NK2204]: `kasse` holds shared mutable state, and this assigns to it directly
error[NK2205]: this `set` reads `kasse` while computing what to store in it
That is the state that rots fastest: a check with no program to be tested against is correctness that quietly stops being true, because nothing exercises it. The lock itself has been built since ADR-064, and Part II 12.2’s counter compiles and runs at both settings, so these had a type to be about and no reason left to wait.
NK2204: an assignment straight into a SharedMut.kasse = 42 looks like an ordinary assignment and is not: the lock has to be
taken for the write, and what takes it is a door.
The message names the door with the value in it. The repair is mechanical, and a help line that said “use a door” would leave the reader to work out which of the four.
An expression has no span — ADR-081 D2 gave one to Binary and to
nothing else — so there is no source text to put in the help. A literal, a name
and a negation are rebuilt; anything else is an ellipsis. A help line that
quoted the wrong thing would be worse than one that quotes nothing, and the
shape the specification’s own example writes is a literal.
NK2205: a set given a value that was seen in a lock.kasse.set(kasse.get() + 100) takes the lock twice — once to read and once
to store — and between the two the value can change, so what is stored is
computed from a state that may no longer hold. The third door exists for exactly
this and takes the lock once.
What makes the refusal reach past the one line is the stamp: what a lock
hands out is a Seen[T], the stamp travels with the value through let,
arithmetic, calls, fields and time, and a set given a stamped value — or
standing under a stamped condition — is this refusal wherever the read was
(ADR-111 D1–D4). The get written inside the set is the
smallest case of the first shape.
NK2201 (no I/O while holding locked data) and NK2203 (a lock taken while a
lock is held) need to know what is inside a door and what a chain of calls
reaches; NK2503 needs the reachability walk
(ADR-039 D6). These two need one statement each, and shipping the
two that are local now beats shipping five that are half-analysed.
Nothing in examples/, tests/samples/ or crates/nikaia-std/src/ is refused,
which is what a refusal added to a language with programs in it owes. The walk
over a set’s argument is the emitter’s visit_expr, made pub(crate)
rather than copied: a second walk over the same shape is a second thing to keep
in step with the AST.
#175’s entry shrinks rather than closes — three of its five codes are still catalogued and not emitted, and the entry now says which and why.
NK2201, NK2203, NK2503. D4’s reason, and each stays on
#175 with what it needs.NK2204 fires where the target is a
name; a.b = 42 with a hull behind b is a shape nothing decides yet, and
saying nothing is the direction that cannot refuse a program that is right.set and get spread over two statements. D3’s own line: it is a
question about what happened in between.Checker::a_write_that_skips_the_door and Checker::written for NK2204;
Checker::a_set_that_reads_what_it_writes and Checker::a_get_inside for
NK2205, the second asked at the MethodCall arm rather than in call_on
because the rule is about the receiver’s name and that arm is handed a type.
emit::visit_expr becomes pub(crate). Exercised by seven programs in
crates/nikaia/tests/lock_doors.rs — both messages against the ones Appendix C
prints, the ellipsis, the get found three levels down, the three shapes that
must stay quiet, an ordinary assignment, and the corpus.