✓
Passing Passing: the compiler rejects this program as expected.
Code
// OWED refusal: composite custody is per-path — an arm that settles only
// `v.r1` while `v.r2` stands undischarged must refuse. The debts are
// independent leaves; settling one does not settle the bundle. Sibling of
// 699_027 (whole-value must-discharge) and 699_031 (full settle).
import std/io
import std/proto
import std/channel
import std/pump
import app/lib/res
std/proto(Env) {
r1: *app/lib/res:Resource<owned!>
r2: *app/lib/res:Resource<owned!>
}
pub tor mk-env { a: *app/lib/res:Resource<!owned>, b: *app/lib/res:Resource<!owned> } -> Env
mk-env -> { r1: a, r2: b }
std/channel:new(inbox, capacity: 8) { env: Env }
std/channel(inbox)
! env v |> app/lib/res:free(r: v.r1) |> std/io:print.ln("leaked r2")
app/lib/res:new(): a |> app/lib/res:new(): b |> mk-env(a, b): e |> std/channel:send(inbox, e)
| ok |> std/io:print.ln("sent")
| full |> app/lib/res:free(r: e.r1) |> app/lib/res:free(r: e.r2) |> std/io:print.ln("full")
| closed |> app/lib/res:free(r: e.r1) |> app/lib/res:free(r: e.r2) |> std/io:print.ln("closed")
std/pump:create(main)
| drained |> std/io:print.ln("drained")
std/pump(main)
! step |> inbox-step()
! live |> inbox-live()
std/pump:run(main)
Supporting Files
// A minimal OWNED-POINTER resource type (non-string), for generalizing B-narrow
// past std/string. `new` issues <owned!>; `free` is the canonical VOID
// discharger consuming <!owned>; `tag` borrows to read a field.
const std = @import("std");
const Resource = struct { tag: i64 };
~pub tor new { } -> *Resource<owned!>
~proc new|zig {
const r = std.heap.page_allocator.create(Resource) catch unreachable;
r.* = .{ .tag = 42 };
return r;
}
// Canonical discharger: consumes <!owned>, frees the resource. Void (no output).
~pub tor free { r: *Resource<!owned> }
~proc free|zig {
std.heap.page_allocator.destroy(r);
}
// Borrow: read the tag without consuming the obligation.
~pub tor tag { r: *Resource<owned> } -> i64
~proc tag|zig {
return r.tag;
}
Actual compiler output
error[KORU030]: Resource 'r2' obligation <owned!> was not discharged. No tor accepts <!owned>.
--> tests/regression/600_STDLIB/699_CHANNEL/699_032_composite_kind_partial_settle/input.k:22:0
❌ Compiler coordination error: Auto-discharge failed (multiple disposal options or no disposal event)
(set KORU_BACKEND_TRACE=1 for the backend return trace)Must fail at runtime with:
CONTAINS r2
CONTAINS not dischargedError output must contain
r2Flows
flow ~std/proto click a branch to expand · @labels scroll to their anchor
std/proto (Env, source: r1: *app/lib/res:Resource<owned!>
r2: *app/lib/res:Resource<owned!>)
flow ~new click a branch to expand · @labels scroll to their anchor
new (expr: inbox, capacity: 8, source: env: Env)
flow ~std/channel click a branch to expand · @labels scroll to their anchor
std/channel (inbox)
flow ~new click a branch to expand · @labels scroll to their anchor
new
flow ~create click a branch to expand · @labels scroll to their anchor
create (expr: main)
flow ~std/pump click a branch to expand · @labels scroll to their anchor
std/pump (main)
flow ~run click a branch to expand · @labels scroll to their anchor
run (main)
Test Configuration
MUST_ERROR