comptime VM arc: abi(.compiler) ABI, out as sx fn, VM-native diagnostics, BuildConfig threaded
Lands the full VM/compiler-API arc on branch reify (701/0 both gates): - abi(.compiler) ABI replaces abi(.zig) extern compiler + the fake #library "compiler"; bodiless decl = compiler-API surface, bodied = user compiler-domain fn (lowered for VM eval, emit-skipped). - out is a plain sx fn (libc write) — the out builtin deleted; the VM handles it via host-FFI. trace_resolve + interp_print_frames ported. - 4B VM-native diagnostics: 1179/1180 render proper comptime type construction failed: under strict. - S5a: build_options/set_post_link_callback on abi(.compiler) with BuildConfig threaded into the VM (green intermediate). - 0522 fixed (describe(args: []Type)); regression 0638. Strict deletion-gate down to 4 compiler_call bails (1609/1614/1615/1616) + 1654 (legitimate unresolvable-symbol diagnostic).
This commit is contained in:
@@ -376,6 +376,55 @@ test "comptime_vm exec: const_string length + str_eq/str_ne" {
|
||||
try std.testing.expectEqual(@as(i64, 3), toI64(try v.run(&fb.func, &.{})));
|
||||
}
|
||||
|
||||
test "comptime_vm exec: error_tag_name_get maps a tag id to its name string" {
|
||||
const alloc = std.testing.allocator;
|
||||
var table = types.TypeTable.init(alloc);
|
||||
defer table.deinit();
|
||||
_ = table.internTag("Foo");
|
||||
const bad = table.internTag("Bad"); // the tag we'll resolve
|
||||
|
||||
// return error_tag_name(<bad tag id>) → the string "Bad"
|
||||
var fb = Fb.init(alloc, &.{}, .string);
|
||||
defer fb.deinit();
|
||||
const b0 = fb.block(&.{});
|
||||
const id = fb.add(b0, inst(.{ .const_int = @intCast(bad) }, .i64));
|
||||
const name = fb.add(b0, inst(.{ .error_tag_name_get = .{ .operand = ref(id) } }, .string));
|
||||
_ = fb.add(b0, inst(.{ .ret = .{ .operand = ref(name) } }, .void));
|
||||
|
||||
var v = vm.Vm.init(alloc);
|
||||
v.table = &table;
|
||||
defer v.deinit();
|
||||
const word = try v.run(&fb.func, &.{});
|
||||
const val = try v.regToValue(alloc, &table, word, .string);
|
||||
defer alloc.free(val.string); // regToValue dupes the bytes
|
||||
try std.testing.expectEqualStrings("Bad", val.string);
|
||||
}
|
||||
|
||||
test "comptime_vm exec: type_is_unsigned(u32) - type_is_unsigned(i64) == 1" {
|
||||
const alloc = std.testing.allocator;
|
||||
var table = types.TypeTable.init(alloc);
|
||||
defer table.deinit();
|
||||
|
||||
// r_u := type_is_unsigned(u32) → 1 ; r_s := type_is_unsigned(i64) → 0
|
||||
// return r_u - r_s → 1 (only the correct unsigned/signed verdicts give 1)
|
||||
var fb = Fb.init(alloc, &.{}, .i64);
|
||||
defer fb.deinit();
|
||||
const b0 = fb.block(&.{});
|
||||
const ct_u = fb.add(b0, inst(.{ .const_type = .u32 }, .type_value));
|
||||
const au = [_]Ref{ref(ct_u)};
|
||||
const r_u = fb.add(b0, inst(.{ .call_builtin = .{ .builtin = .type_is_unsigned, .args = &au } }, .bool));
|
||||
const ct_s = fb.add(b0, inst(.{ .const_type = .i64 }, .type_value));
|
||||
const as = [_]Ref{ref(ct_s)};
|
||||
const r_s = fb.add(b0, inst(.{ .call_builtin = .{ .builtin = .type_is_unsigned, .args = &as } }, .bool));
|
||||
const diff = fb.add(b0, inst(.{ .sub = .{ .lhs = ref(r_u), .rhs = ref(r_s) } }, .i64));
|
||||
_ = fb.add(b0, inst(.{ .ret = .{ .operand = ref(diff) } }, .void));
|
||||
|
||||
var v = vm.Vm.init(alloc);
|
||||
v.table = &table;
|
||||
defer v.deinit();
|
||||
try std.testing.expectEqual(@as(i64, 1), toI64(try v.run(&fb.func, &.{})));
|
||||
}
|
||||
|
||||
test "comptime_vm exec: array_to_slice + index through slice + slice length" {
|
||||
const alloc = std.testing.allocator;
|
||||
var table = types.TypeTable.init(alloc);
|
||||
@@ -1262,7 +1311,7 @@ test "comptime_vm tryEval: pure function → Value; unsupported → null" {
|
||||
_ = fb.add(b0, inst(.{ .ret = .{ .operand = ref(m) } }, .void));
|
||||
const ok_id = module.addFunction(fb.func);
|
||||
|
||||
const v = vm.tryEval(alloc, &module, ok_id) orelse return error.VmShouldHaveHandledIt;
|
||||
const v = vm.tryEval(alloc, &module, ok_id, null, null) orelse return error.VmShouldHaveHandledIt;
|
||||
try std.testing.expectEqual(@as(i64, 42), v.int);
|
||||
|
||||
// fn bad() { compiler_call() } → an unported op → tryEval yields null (caller
|
||||
@@ -1274,7 +1323,7 @@ test "comptime_vm tryEval: pure function → Value; unsupported → null" {
|
||||
_ = fb2.add(c0, inst(.ret_void, .void));
|
||||
const bad_id = module.addFunction(fb2.func);
|
||||
|
||||
try std.testing.expect(vm.tryEval(alloc, &module, bad_id) == null);
|
||||
try std.testing.expect(vm.tryEval(alloc, &module, bad_id, null, null) == null);
|
||||
}
|
||||
|
||||
test "comptime_vm exec: division by zero and unsupported op bail loudly" {
|
||||
@@ -1432,7 +1481,7 @@ test "comptime_vm tryEval: deref of a null pointer bails (null, not a crash)" {
|
||||
|
||||
// The hardened accessors turn the null deref into error.OutOfBounds → run
|
||||
// bails → tryEval returns null (legacy fallback), NOT a debug panic.
|
||||
try std.testing.expect(vm.tryEval(alloc, &module, bad_id) == null);
|
||||
try std.testing.expect(vm.tryEval(alloc, &module, bad_id, null, null) == null);
|
||||
}
|
||||
|
||||
test "comptime_vm: arena allocations are aligned, non-null, and stable across grows" {
|
||||
|
||||
Reference in New Issue
Block a user