Issue #985: Two overlap branches that update one SharedMut are accepted; Part II 12.2 says two writing doors on one lock collide (NK2104)

Open and answer this issue on GitHub.

ready · opened 2026-10-30 · updated 2026-10-30 · 0 comments

Found while preparing ADR-async-1 (#983), checked on develop 4f0372c with target/fast/nikaia check.

Probe (a.nika):

fn main() {
    let seen = SharedMut(0)
    let p = overlap {
        seen.update fn(mut v) { v += 1 }
        seen.update fn(mut v) { v += 2 }
    }
    println(f"{seen.get()}")
}

nikaia check prints Checked a.nika. Expected: NK2104 at the second branch, naming the lock: Part II 12.2 says set and update are writes … Any two of the writing forms are ordered by the rule that orders two printlns, and two println branches are refused today (Both touch stdout, and one writes to it). The walk does not account a lock reached through a local binding, so it falls under C.4 (not accounted, not refused), though the binding is a plain local the walk can see.

The same shape is in tests/language/src/task_scope.nika tests 1 and 3 (two seen.update tasks); under async (ADR-async-1 D8) they would be refused once this is fixed, and the migration rewrites them with the group’s value.

To build

  1. In the touch walk (crates/nikaia-std/src/tools/touch.nika, check_walks.nika), a door (get/access read, set/update write) on a SharedMut or Locked bound to a local or a parameter is a touch of that lock, named by the binding.
  2. Two branches writing one such lock: NK2104, both reach the lock seen, and one writes it; two gets: accepted.
  3. Tests: tests/compiler/tests/overlap_two_updates_one_lock.nika (.stderr with NK2104), overlap_two_gets_one_lock.nika (.stdout), overlap_updates_two_locks.nika (accepted).

Generated by Claude Code

Back to Open Issues