comptime VM: Phase 3 — type_kind + type_field_value readers (read side complete)

The last two read-only readers the metatype's type_info(T) needs, each backed by
a TypeTable query both the legacy handler and the VM call (no drift):

  type_kind(t: TypeId) -> i64            (kindCode; stable discriminant, total — never bails)
  type_field_value(t: TypeId, idx) -> i64 (memberValue; enum explicit value or ordinal)

kindCode codes (compiler-owned, stable): 0 other / 1 struct / 2 enum /
3 tagged_union / 4 tuple / 5 union / 6 array / 7 vector / 8 error_set.

With these, the READ side is complete: find_type + type_kind + type_field_count +
type_field_{name,type} + type_nominal_name + type_field_value cover everything
reflectTypeInfo reads — a comptime sx fn can fully reflect a struct/enum/tuple
into data with no #builtin.

Example 0630 reflects Color / WindowFlags(flags) / Point. VM unit test added.

Revised forward direction: the write side will be ONE register_type(info) fn that
branches on the kind in the compiler (subsuming define's per-kind dispatch), not a
per-kind register_struct.

Parity 691/691 (gate OFF and -Dcomptime-flat).
This commit is contained in:
agra
2026-06-18 09:47:23 +03:00
parent d23e208430
commit 27bc301651
10 changed files with 252 additions and 29 deletions

View File

@@ -52,6 +52,8 @@ pub const bound_fns = [_]BoundFn{
.{ .sx_name = "type_nominal_name", .handler = handleTypeNominalName },
.{ .sx_name = "type_field_name", .handler = handleTypeFieldName },
.{ .sx_name = "type_field_type", .handler = handleTypeFieldType },
.{ .sx_name = "type_kind", .handler = handleTypeKind },
.{ .sx_name = "type_field_value", .handler = handleTypeFieldValue },
};
/// Look up a compiler function by its sx name. Returns null when the name is not
@@ -151,3 +153,20 @@ fn handleTypeFieldType(interp: *Interpreter, args: []const Value) InterpError!Va
const mty = interp.module.types.memberType(tid, args[1].int) orelse return error.TypeError;
return Value{ .int = mty.index() };
}
/// `type_kind(t: TypeId) -> i64` — the stable kind discriminant (see
/// `TypeTable.kindCode`). Total: an unnamed/non-aggregate type reads `other` (0).
fn handleTypeKind(interp: *Interpreter, args: []const Value) InterpError!Value {
if (args.len != 1) return error.TypeError;
const tid: types.TypeId = @enumFromInt(try handleArg(args, 0));
return Value{ .int = interp.module.types.kindCode(tid) };
}
/// `type_field_value(t: TypeId, idx: i64) -> i64` — enum variant `idx`'s integer
/// value (explicit or ordinal). Loud error for a non-enum or out-of-range idx.
fn handleTypeFieldValue(interp: *Interpreter, args: []const Value) InterpError!Value {
if (args.len != 2 or args[1] != .int) return error.TypeError;
const tid: types.TypeId = @enumFromInt(try handleArg(args, 0));
const v = interp.module.types.memberValue(tid, args[1].int) orelse return error.TypeError;
return Value{ .int = v };
}