051 union with consume marker

✓ Passing This code compiles and runs correctly.

Code

// Test 330_051: Union with consume marker
// Tests that !opened|closing discharges obligation from either state
// Demonstrates: consume marker (!) applies to entire union

~import "$app/handle"

// Test 1: finalize() from opened state - discharges obligation
~app.handle:open()
| opened h1 |> app.handle:finalize(h: h1.h)
    | done |> _

// Test 2: finalize() from closing state - also discharges obligation
~app.handle:open()
| opened h1 |> app.handle:start_close(h: h1.h)
    | closing h2 |> app.handle:finalize(h: h2.h)
        | done |> _
input.kz

Imported Files

// Library module: handle
// Demonstrates phantom state unions - events that accept multiple states

const std = @import("std");

// Handle type with phantom states
const Handle = struct {
    id: i32,
};

// Open a handle - produces obligation (must be finalized)
~pub event open {}
| opened { h: *Handle[opened!] }

~proc open {
    std.debug.print("Opening handle\n", .{});
    const allocator = std.heap.page_allocator;
    const h = allocator.create(Handle) catch unreachable;
    h.* = Handle{ .id = 42 };
    return .{ .opened = .{ .h = h } };
}

// Start closing - transitions to 'closing' state (keeps obligation)
~pub event start_close { h: *Handle[opened] }
| closing { h: *Handle[closing] }

~proc start_close {
    std.debug.print("Starting close: {d}\n", .{h.id});
    return .{ .closing = .{ .h = h } };
}

// Finalize - accepts EITHER opened OR closing with consume marker
// The !prefix means this DISCHARGES the obligation
~pub event finalize { h: *Handle[!opened|closing] }
| done {}

~proc finalize {
    std.debug.print("Finalizing handle: {d}\n", .{h.id});
    // Clean up the handle
    return .{ .done = .{} };
}
handle.kz