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

@@ -554,6 +554,46 @@ pub const TypeTable = struct {
};
}
/// Stable kind discriminant of a type, for comptime reflection branching.
/// TOTAL (never fails): an unnamed / non-aggregate type or an out-of-range id
/// is `other` (0). Codes are compiler-owned and stable — NOT tied to any sx
/// enum's declaration order; the sx side maps them. Backs the `type_kind`
/// reader. (A `tagged_union` is a payload-carrying enum; the sx metatype folds
/// codes 2 and 3 onto its single `.enum` TypeInfo variant.)
/// 0 other · 1 struct · 2 enum · 3 tagged_union · 4 tuple
/// 5 union · 6 array · 7 vector · 8 error_set
pub fn kindCode(self: *const TypeTable, id: TypeId) i64 {
if (id.index() >= self.infos.items.len) return 0;
return switch (self.get(id)) {
.@"struct" => 1,
.@"enum" => 2,
.tagged_union => 3,
.tuple => 4,
.@"union" => 5,
.array => 6,
.vector => 7,
.error_set => 8,
else => 0,
};
}
/// Integer value of enum variant `idx`: its explicit value when the enum
/// declares one (custom values or flags), else its ordinal. Null for a
/// non-enum type, a negative / out-of-range `idx`, or an out-of-range id.
/// Backs the `type_field_value` reader (mirrors the `field_value_int` builtin).
pub fn memberValue(self: *const TypeTable, id: TypeId, idx: i64) ?i64 {
if (idx < 0 or id.index() >= self.infos.items.len) return null;
const i: usize = @intCast(idx);
return switch (self.get(id)) {
.@"enum" => |e| blk: {
if (i >= e.variants.len) break :blk null;
if (e.explicit_values) |vals| if (i < vals.len) break :blk vals[i];
break :blk @intCast(i); // ordinal default
},
else => null,
};
}
/// Source-sensitive variant of `findByName`: asserts at most one named type
/// matches, then returns it (or null). Quarantines the global first-match
/// scan — new resolver code that must not silently pick a first-of-many