✓
Passing This code compiles and runs correctly.
Code
// The World in Koru — entry 4, the negative twin of 834_mutex_unlock.
// Doorway: Go's `mu.Unlock(); mu.Unlock()` — releasing a lock you've already
// released. In Go (and C) that's undefined behaviour: a runtime panic if you're
// lucky, silent corruption if you're not — `defer` does nothing to stop it.
//
// In Koru the released token's TYPE no longer carries `<held!>`, so a second
// `unlock` has no obligation to consume — the phantom checker rejects the reuse
// at compile time. Use-after-release is unrepresentable, not merely unlucky.
import std/io
pub event lock { name: string } -> string<held!>
lock -> name
pub event unlock { name: string<!held> }
unlock = std/io:print.ln("unlock {{ name:s }}")
// Release once (discharges <!held>), then try to release the same token again.
lock(name: "m"): m |> unlock(name: m) |> unlock(name: m)
Must fail at runtime with:
CONTAINS Use-after-dischargeError Verification
Actual Compiler Output
error[KORU030]: Use-after-discharge: binding 'm' was already discharged and cannot be used
--> phantom_semantic_check:19:0
❌ Compiler coordination error: Phantom semantic validation failed
error: CompilerCoordinationFailed
???:?:?: 0x10438b9d3 in _backend.RuntimeEmitter.emit (???)
???:?:?: 0x10438cb63 in _backend.main (???)Flows
subflow ~unlock click a branch to expand · @labels scroll to their anchor
print.ln (expr: "unlock {{ name:s }}")
flow ~lock click a branch to expand · @labels scroll to their anchor
lock (name: "m")
Test Configuration
MUST_FAIL