✓
Passing Passing: the compiler rejects this program as expected.
Code
// 690_058 — the drain ENFORCEMENT (negative). An ambiguous *Transaction<active!>
// column with NO `! discharge` handler bolted onto the store. Proves koru FORCES
// the drain: no silent drop of ambiguous elements.
//
// The diagnostic is KORU160, and WHERE it points is half the pin. The store
// declaration is what is wrong — a store that cannot say how it drains — so the
// error is spoken by the store transform, located at the declaration, and it
// names `! discharge` as the fix. An insert of an ambiguous column also leaks
// its obligation, and KORU030 would report that at the CALL SITE, which is
// correct code; the store speaks during the transform phase, so the analysis
// pass that would say the confusing thing never runs.
import std/store
import app/lib/tx
std/store:new(txns, capacity: 8) { tx: *app/lib/tx:Transaction<active!> }
app/lib/tx:begin(): t1 |> std/store:insert(txns) { tx: t1 }
| row _ |> _
Supporting Files
// An AMBIGUOUS owned resource: *Transaction<active!> with TWO void dischargers
// consuming <!active> — commit AND rollback. The store cannot pick, so an owned
// column of this type must be DRAINED (caller discharges each element), not
// auto-torn-down. (Mirrors 690_035's entity ambiguity one level down.)
const std = @import("std");
const Transaction = struct { id: i32 };
~pub tor begin { } -> *Transaction<active!>
~proc begin|zig {
const t = std.heap.page_allocator.create(Transaction) catch unreachable;
t.* = .{ .id = 7 };
return t;
}
~pub tor commit { tx: *Transaction<!active> }
~proc commit|zig {
std.debug.print("commit {d}\n", .{tx.id});
std.heap.page_allocator.destroy(tx);
}
~pub tor rollback { tx: *Transaction<!active> }
~proc rollback|zig {
std.debug.print("rollback {d}\n", .{tx.id});
std.heap.page_allocator.destroy(tx);
}
Actual compiler output
error[KORU160]: std/store:new(txns): column *app/lib/tx:Transaction<!active> has 2 ways to discharge and the store cannot pick one for you
--> tests/regression/600_STDLIB/690_STORE/690_058_store_ambiguous_column_undrained_leaks/input.k:15:0
hint: say which at the store, where it is static for the program's lifetime: bolt `! discharge item |> app/lib/tx:<discharger>(item.<field>)` onto the declaration and teardown fires it per still-live elementMust contain:
the store cannot pick oneFlows
flow ~new click a branch to expand · @labels scroll to their anchor
new (txns, capacity: 8, source: tx: *app/lib/tx:Transaction<active!>)
flow ~begin click a branch to expand · @labels scroll to their anchor
begin
Test Configuration
MUST_ERROR