✓
Passing Passing: the compiler rejects this program as expected.
Code
// 330_146 — a binding discharged by an EARLIER call stays dead inside a
// `!` arm of a LATER call.
//
// `pump(w1)` consumes w1's obligations; on `| done` the loop has returned
// them and `close(d1)` settles the re-issued `active!`. w1 itself is
// discharged — the custody that made it live belonged to the FIRST pump's
// `! tick`. Inside the SECOND pump's `! tick`, only w2 (that call's own
// consumed argument) is live; reading w1 is use-after-discharge.
import app/win
import std/io
app/win:open()
| win w1 |> app/win:pump(w: w1)
! tick _ |> app/win:read(w: w1)
| done d1 |> app/win:close(w: d1)
|> app/win:open()
| win w2 |> app/win:pump(w: w2)
! tick _ |> app/win:read(w: w1)
| done d2 |> app/win:close(w: d2)
| err e2 |> std/io:print.ln(e2)
| err e |> std/io:print.ln(e)
Supporting Files
// 330_146 companion module — the window/frames analog as minimal tors.
const std = @import("std");
pub const Win = struct { n: i32 };
~pub tor open {} | win *Win<opened!> | err string
~proc open|zig {
const w = std.heap.page_allocator.create(Win) catch unreachable;
w.* = .{ .n = 1 };
return .{ .win = w };
}
~pub tor read { w: *Win<opened|active> }
~proc read|zig { _ = w.n; }
~pub tor close { w: *Win<!active> }
~proc close|zig { std.heap.page_allocator.destroy(w); }
~pub tor pump { w: *Win<!opened|!active> }
! tick i64
| done *Win<active!>
~proc pump|zig {
tick(0);
return .{ .done = w };
}
Actual compiler output
error[KORU030]: Use-after-discharge: binding 'w1' was already discharged and cannot be used
--> tests/regression/300_ADVANCED_FEATURES/330_PHANTOM_TYPES/330_146_event_arm_prior_discharge_stays_dead_in_arm/input.k:18:13Must fail at runtime with:
CONTAINS error[KORU030]
CONTAINS Use-after-dischargeFlows
flow ~open click a branch to expand · @labels scroll to their anchor
open
Test Configuration
MUST_ERROR