✓
Passing Passing: the compiler rejects this program as expected.
Code
// PIN: an obligation created inside a label-fold body and dropped at the
// @loop back-edge is refused — scope tracking traces @loop jumps back to
// #loop, sees the opened file goes nowhere on that edge, and raises KORU030
// ("discharge it before jumping"). Complements 330_075, which pins the
// same rule for a carried obligation dropped via an empty @loop().
~import app/fs
const std = @import("std");
~tor iterate { count: i32 }
| more i32
| fin i32
~proc iterate|zig {
if (count < 3) {
return .{ .more = count + 1 };
}
return .{ .fin = count };
}
~tor spin {} -> i32
~spin = #loop iterate(count: 0)
| more n |> app/fs:open(path: "test.txt"): f |> @loop(count: n)
| fin r -> r
~spin()
Supporting Files
// Library module: fs
// Single disposal event
const std = @import("std");
const File = struct { handle: i32 };
// Open a file - returns opened! state (requires cleanup)
~pub tor open { path: string } -> *File<opened!>
~proc open|zig {
std.debug.print("Opening file\n", .{});
const f = std.heap.page_allocator.create(File) catch unreachable;
f.* = File{ .handle = 42 };
return f;
}
// Close - the ONLY consumer of <!opened>
~pub tor close { file: *File<!opened> }
~proc close|zig {
std.debug.print("Closing file\n", .{});
}
Actual compiler output
error[KORU030]: Label jump '@loop' drops cleanup obligation for 'f' - pass it as an argument or discharge it before jumping
--> tests/regression/300_ADVANCED_FEATURES/330_PHANTOM_TYPES/330_017_scope_label_loop/input.kz:19:5Must contain:
error[KORU030]Flows
subflow ~spin click a branch to expand · @labels scroll to their anchor
#loop iterate (count: 0)
flow ~spin click a branch to expand · @labels scroll to their anchor
spin
Test Configuration
MUST_ERROR