✓
Passing This code compiles and runs correctly.
Code
// PIN: `--auto-discharge=disable` must still enforce an obligation that has
// passed through a bare-borrow.
//
// `open` grants <hashing!>. `update` BORROWS it (bare <hashing>), so `d` is
// still live and still owing after the call. We then FORGET to finalize `d`.
// `koruc --help` promises: "Disable automatic disposal insertion — phantom
// errors WILL fire for unsatisfied obligations." So disable must reject this
// with "was not discharged", borrow or no borrow.
//
// Enforcement under disable lives in a different pass (phantom-semantic-checker)
// than under default (auto-discharge-inserter); this pins that the two agree on
// whether an obligation survives a bare-borrow. Control: the green sibling
// 2104_21_open_tx_forgot_close is the same forgotten-discharge WITHOUT a borrow.
//
// MUST_ERROR under --auto-discharge=disable (see COMPILER_FLAGS).
~import app/digest
~import std/io
~app/digest:open(): d |> app/digest:update(d, n: 1) |> std/io:print.ln("forgot to finalize d after a borrow")
Must contain:
not dischargedFlows
flow ~open click a branch to expand · @labels scroll to their anchor
open
Imported Files
// Mock digest lifecycle — mirrors the real shape of evp's `hashing` obligation
// (koru-libs evp/index.kz) without any external C. `open` grants <hashing!>;
// `update` BORROWS it (bare <hashing>) so the same handle stays live and still
// owing after the call; `final.hex`/`final.bytes` CONSUME it (<!hashing>) and
// discharge the obligation. page_allocator stands in for the EVP context so the
// pin has zero link dependencies.
const std = @import("std");
const Digest = struct { n: i64 };
~pub tor open {} -> *Digest<hashing!>
~proc open|zig {
const d = std.heap.page_allocator.create(Digest) catch unreachable;
d.* = Digest{ .n = 0 };
return d;
}
// Feed a chunk. BORROWS the handle (bare <hashing>): the obligation stays with
// the caller, so `d` is still live (and still owing <hashing!>) after this call.
~pub tor update { d: *Digest<hashing>, n: i64 }
~proc update|zig {
d.n += n;
}
// Discharge the obligation. Two options, neither a `[!]` default — same as evp.
~pub tor final.hex { d: *Digest<!hashing> } -> string
~proc final.hex|zig {
std.heap.page_allocator.destroy(d);
return "hex";
}
~pub tor final.bytes { d: *Digest<!hashing> } -> string
~proc final.bytes|zig {
std.heap.page_allocator.destroy(d);
return "bytes";
}
Test Configuration
Compiler Flags:
--auto-discharge=disable