comptime VM: VM-native metatype CONSTRUCTION — declare/define + tagged-union enum_init (P3.4 step 7)
The metatype type-construction builtins now run natively on the flat-memory
VM, so the construction examples run HANDLED end-to-end (no call_builtin
fallback to the legacy interp).
- Tagged-union enum_init WITH payload: allocate zeroed, write the tag at
offset 0, copy the payload at tag_size ({ header, [N x i8] } layout).
- New .call_builtin exec arm -> callBuiltinVm (VM-native mirror of the legacy
execBuiltinInner): declare(name) mints an empty forward nominal slot (shared
declareNominal, also used by declare_type); define(handle, info) reads the
TypeInfo tagged-union VALUE from flat memory and mints via defineFromInfo,
a faithful port of legacy defineEnum/defineStruct/defineTuple (all-void enum
-> real .enum per issue 0142, dup-name rejection, updatePreservingKey vs
replaceKeyedInfo). Unmodeled builtins bail -> legacy fallback (dual-path).
- Refactored the []{name,ty} decode out of registerTypeVm into a shared
decodeMemberSlice (+ decodeTypeSlice for bare-Type tuple elements).
- Correctness guard: enum_init/define assume a tag-headed layout, wrong for a
backing_type tagged union (laid out as the backing struct) — both now bail
loudly on backing_type != null rather than silent-clobber.
Examples 0614/0620/0621/0624/0632 run fully HANDLED on the VM; 0622/0623 run
define HANDLED then fall back at the still-unported type_info. VM output
byte-matches legacy for all 7. 697/0 both gates + all unit tests (added:
tagged-union enum_init payload layout).
This commit is contained in:
@@ -659,6 +659,36 @@ test "comptime_vm exec: payloadless enum_init + enum_tag" {
|
||||
try std.testing.expectEqual(@as(i64, 11), toI64(try v.run(&fb.func, &.{})));
|
||||
}
|
||||
|
||||
test "comptime_vm exec: tagged-union enum_init with payload lays out {tag@0, payload@tag_size}" {
|
||||
// The construction primitive `define` reuses: build `E.value(42)` where
|
||||
// `E = { value: i64, closed: void }` and verify the flat-memory bytes — tag 0
|
||||
// at offset 0, the i64 payload at offset tag_size (8). Mirrors the LLVM
|
||||
// `{ header, [N x i8] }` layout the rest of the compiler reads.
|
||||
const alloc = std.testing.allocator;
|
||||
var table = types.TypeTable.init(alloc);
|
||||
defer table.deinit();
|
||||
const ufields = [_]types.TypeInfo.StructInfo.Field{
|
||||
.{ .name = table.internString("value"), .ty = .i64 },
|
||||
.{ .name = table.internString("closed"), .ty = .void },
|
||||
};
|
||||
const e = table.intern(.{ .tagged_union = .{ .name = table.internString("E"), .fields = &ufields, .tag_type = .i64 } });
|
||||
|
||||
// return E.value(42) → the tagged-union value's Addr
|
||||
var fb = Fb.init(alloc, &.{}, e);
|
||||
defer fb.deinit();
|
||||
const b0 = fb.block(&.{});
|
||||
const p = fb.add(b0, inst(.{ .const_int = 42 }, .i64));
|
||||
const g = fb.add(b0, inst(.{ .enum_init = .{ .tag = 0, .payload = ref(p) } }, e));
|
||||
_ = fb.add(b0, inst(.{ .ret = .{ .operand = ref(g) } }, .void));
|
||||
|
||||
var v = vm.Vm.init(alloc);
|
||||
v.table = &table;
|
||||
defer v.deinit();
|
||||
const addr = try v.run(&fb.func, &.{});
|
||||
try std.testing.expectEqual(@as(u64, 0), try v.machine.readWord(addr, 8)); // tag
|
||||
try std.testing.expectEqual(@as(u64, 42), try v.machine.readWord(addr + 8, 8)); // payload
|
||||
}
|
||||
|
||||
test "comptime_vm exec: const_type yields a Type-value word; regToValue bridges it to .type_tag" {
|
||||
const alloc = std.testing.allocator;
|
||||
var table = types.TypeTable.init(alloc);
|
||||
|
||||
Reference in New Issue
Block a user