✓
Passing This code compiles and runs correctly.
Code
// SUBFLOW-IMPLEMENTED EFFECTS, obligations, no-escape negative (pure .k, no
// proc) — the subflow sibling of 400_103, the discriminator. `! each` carries
// no <state!> resume, so an obligation born in the consumer's handler CANNOT
// escape the firing. Here the handler creates a <field!> obligation
// (std/field:new) and never frees it — unbalanced, and it must be rejected
// with KORU030 even though the generator is a pure-Koru subflow. If this is
// silently accepted, obligation tracking is not wired through the
// subflow-implemented firing path.
//
// COMPILER_FLAGS: --auto-discharge=disable (the 2104_21 precedent). With
// default flags this program is LEGAL: std/field:free is the unambiguous
// discharge for <field!>, so the auto-discharge inserter settles the
// obligation per-firing (the free lands INSIDE the handler body — the
// per-firing rule holding by insertion, identically for proc-backed and
// subflow-backed generators). The enforcement path this test pins only
// exists with insertion off; without the flag the pin would contradict
// the auto-discharge feature itself.
import std/io
import std/field
import std/control
pub event gen { n: usize }
! each usize
| done usize
gen = for(0..n)
! each i |> each(i)
| done => done n
gen(n: 3)
! each i |> std/field:new(bits: 64)
| field f |> std/io:print.ln("leaking {{ i:d }}")
| err _ |> _
| done _ |> _
Backend must reject with:
CONTAINS error[KORU030]
CONTAINS was not dischargedError Verification
Actual Compiler Output
error[KORU030]: Resource 'f' carries obligation <field!> was not discharged. Call: std.field:free
--> phantom_semantic_check:31:0
❌ Compiler coordination error: Phantom semantic validation failed
error: CompilerCoordinationFailed
/Users/larsde/src/koru/tests/regression/400_RUNTIME_FEATURES/400_137_effect_subflow_obligation_cannot_escape/backend.zig:95:13: 0x100d539d3 in emit (backend)
return error.CompilerCoordinationFailed;
^
/Users/larsde/src/koru/tests/regression/400_RUNTIME_FEATURES/400_137_effect_subflow_obligation_cannot_escape/backend.zig:202:28: 0x100d54b63 in main (backend)
const generated_code = try RuntimeEmitter.emit(compile_allocator, final_ast);
^Flows
subflow ~gen click a branch to expand · @labels scroll to their anchor
for (0..n)
flow ~gen click a branch to expand · @labels scroll to their anchor
gen (n: 3)
Test Configuration
MUST_FAIL
Compiler Flags:
--auto-discharge=disable