Issue #677: NK2203: a lock taken inside a lock is specified as refused (Part III C.6, ADR-281) but builds today

Open and answer this issue on GitHub.

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

What is wrong

Part III C.6 and Part II 12.3 say that taking a lock while a lock is held is always a compile-time error (NK2203), written nested, reached through a chain of calls, or opened as a scope inside the block. The compiler does not refuse it. The roadmap row for ADR-281 says the same (NK2201 and NK2203 “are not written”), and the touches_a_lock column is inferred but read by nothing (crates/nikaia/tests/lock_column.rs).

Found while checking the examples for the website’s “What Nikaia checks” section: the page had claimed NK2203 works, and it does not.

Probe

Built from develop at ccf982f, target/release/nikaia check:

struct Account {
    balance: i64,
}

fn main() {
    let a = SharedMut(Account { balance: 100 })
    let b = SharedMut(Account { balance: 100 })
    a.update fn(mut from) {
        from.balance -= 30
        b.update fn(mut to) { to.balance += 30 }
    }
}

Result: Checked. Expected: error[NK2203]: `update` takes a lock, but you're already holding one here. (the message in Part III C.6).

The same lock twice, a.access fn(x) { a.update fn(mut y) { y.balance += 1 } }, is also accepted.

What is refused today: a pause inside a door (NK2202, time::sleep under update), and update_all(a, b) builds.

To build

  1. NK2203 for a door (access, update, set, access_all, update_all) opened directly inside another door’s block, with the message and help of C.6.
  2. The same through a chain of calls, read from the touches_a_lock column: a call whose answer is touches a lock is refused, one whose answer is undecided is not (Part III C.4: never refuse a correct program).
  3. A task::scope opened inside a door’s block (the scope waits for its tasks).
  4. Tests for each shape, the update_all way out accepted, and the probes above as refusals.
  5. Measure the refusal against examples/ before it lands: no program there may newly fail.
  6. The website says that a hand-written nested lock is not yet refused (index.html, “Tasks that get stuck”); change that sentence when this lands. The commit that finishes step 6 writes Fixes #677.

Back to Open Issues