comptime VM: Phase 3 — find_type + type_field_count reflection readers

First read-only compiler-API reflection readers, bound the same way as the
intern/text_of seed (compiler_lib.bound_fns + Vm.callCompilerFn, native on flat
memory, no marshaling). A type handle is a plain u32 TypeId (like StringId), so
both stay clean scalar host-calls:

  find_type(name: StringId) -> TypeId          (TypeTable.findByName; unresolved/0 if absent)
  type_field_count(t: TypeId) -> i64           (new TypeTable.memberCount; loud-bail, no silent 0)

memberCount is the single source both the legacy handler and the VM read, so the
two paths can't drift. find_type returns a non-optional TypeId using the
unresolved(0) sentinel for not-found rather than ?Type — a Type value is
.any-typed (which the flat-memory VM does not represent) and an optional can't
cross the legacy<->VM eval boundary; unresolved is the project-blessed "no type"
marker.

Example 0628 chains intern -> find_type -> type_field_count (+ a not-found
lookup), folded at #run, VM-HANDLED natively. VM unit test added.

Parity 689/689 (gate OFF and -Dcomptime-flat).
This commit is contained in:
agra
2026-06-18 09:25:26 +03:00
parent 0367d96d9b
commit a9302a8b50
10 changed files with 247 additions and 15 deletions

View File

@@ -480,6 +480,26 @@ pub const TypeTable = struct {
return null;
}
/// Member count of an aggregate type: struct/union/tagged-union fields, enum
/// variants, or array/vector length. Returns null for a type that has no
/// member count (a scalar, pointer, the `unresolved` sentinel, …) — so a
/// caller bails loudly rather than reading a silent 0. The comptime
/// compiler-API reflection reader `type_field_count` rides on this (both the
/// legacy `compiler_lib` handler and the flat-memory VM call it, so the two
/// paths can never drift). Out-of-range ids return null, not a panic.
pub fn memberCount(self: *const TypeTable, id: TypeId) ?i64 {
if (id.index() >= self.infos.items.len) return null;
return switch (self.get(id)) {
.@"struct" => |s| @intCast(s.fields.len),
.@"union" => |u| @intCast(u.fields.len),
.tagged_union => |u| @intCast(u.fields.len),
.@"enum" => |e| @intCast(e.variants.len),
.array => |a| @intCast(a.length),
.vector => |v| @intCast(v.length),
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