comptime VM: Phase 3 — field-level reflection readers
Three more read-only compiler-API readers on the TypeId-handle shape, each backed
by a new TypeTable query that both the legacy handler and the VM call (no drift):
type_nominal_name(t: TypeId) -> StringId (nominalName; loud-bail for unnamed types)
type_field_name(t: TypeId, idx: i64) -> StringId (memberName)
type_field_type(t: TypeId, idx: i64) -> TypeId (memberType)
All loud-bail on out-of-range idx / no-member — no silent default. First multi-arg
compiler fns (callCompilerFn now reads arg 1 = idx); added Vm.argHandle/argTypeId
range-checked arg readers and moved find_type/type_field_count onto them. Names use
the type_* family to avoid colliding with the std metatype builtins (field_name /
type_name in core.sx); the new TypeTable.nominalName is distinct from the existing
typeName(id) display-string renderer.
Example 0629 reflects Pair { lo: Point; hi: Point } — each field name + the nominal
name of a field's type, #run-folded, VM-HANDLED natively. VM unit test added.
Parity 690/690 (gate OFF and -Dcomptime-flat).
This commit is contained in:
@@ -26,26 +26,30 @@ with ONE welded mechanism. Branch: `reify` (off `master`). Update after every st
|
||||
> breaks cross-compilation — host vs target layout — and loses the sandbox. A
|
||||
> flat-memory VM keeps both while getting native bytes + speed.)
|
||||
>
|
||||
> **Next action (2026-06-18):** **Phase 3 is UNDER WAY.** The VM now hosts the first
|
||||
> read-only reflection readers — `find_type(name: StringId) -> TypeId` and
|
||||
> `type_field_count(t: TypeId) -> i64` — bound exactly like the `intern`/`text_of` seed
|
||||
> (a type handle is a plain `u32` `TypeId`, so the calls stay clean scalar host-calls).
|
||||
> Example `0628` chains `intern → find_type → type_field_count`, VM-HANDLED natively.
|
||||
> Parity **689/689** (gate ON and OFF), VM unit test added. Phase 1.final op-porting was
|
||||
> already complete (the VM covers scalars/control-flow/aggregates/strings/optionals/enums,
|
||||
> calls+recursion, the implicit context + full allocator protocol, globals, failables +
|
||||
> return traces); both comptime call sites route through the VM with legacy fallback.
|
||||
> **Forward (P3.2):** more read-only readers on the same `TypeId`-handle shape
|
||||
> (`type_name`, `field_name`, `field_type`, kind queries), then `register_struct` (the
|
||||
> first MUTATING fn — mints a `TypeId`; resolve the mutable-table / host-ABI-vs-target-ABI
|
||||
> boundary deliberately). Re-expressing `declare`/`define`/`type_info` as sx (the metatype,
|
||||
> which runs at LOWERING time) needs the VM hardened against malformed lowering-time IR
|
||||
> first — keep it on the legacy path until then. Phase 2 (bytecode) is the orthogonal
|
||||
> speed work. **Decision recorded:** `find_type` returns a non-optional `TypeId` using the
|
||||
> `unresolved` (0) sentinel, NOT `?Type` (a `Type` value is `.any`-typed, which the VM
|
||||
> doesn't represent, and an optional can't cross the eval bridge) — see `PLAN-COMPILER-VM.md`
|
||||
> Phase 3 progress note.
|
||||
> Build/verify: `zig build && zig build test` (689, gate OFF). Run the corpus ON the VM:
|
||||
> **Next action (2026-06-18):** **Phase 3 is UNDER WAY.** The VM now hosts five read-only
|
||||
> reflection readers, all on the same plain-`u32`-handle shape (a `TypeId` is a `u32`, like
|
||||
> `StringId`), so the calls stay clean scalar host-calls — handle in, scalar out, no
|
||||
> marshaling: `find_type(name) -> TypeId`, `type_field_count(t) -> i64`,
|
||||
> `type_nominal_name(t) -> StringId`, `type_field_name(t, idx) -> StringId`,
|
||||
> `type_field_type(t, idx) -> TypeId`. Each is backed by a `TypeTable` query
|
||||
> (`findByName`/`memberCount`/`nominalName`/`memberName`/`memberType`) that BOTH the legacy
|
||||
> handler and the VM call, so the two paths can't drift. Examples `0628` (`find_type` +
|
||||
> `type_field_count`) and `0629` (field reflection over `Pair { lo: Point; hi: Point }`),
|
||||
> both VM-HANDLED natively. Parity **690/690** (gate ON and OFF), VM unit tests added.
|
||||
> Phase 1.final op-porting was already complete (the VM covers
|
||||
> scalars/control-flow/aggregates/strings/optionals/enums, calls+recursion, the implicit
|
||||
> context + full allocator protocol, globals, failables + return traces); both comptime
|
||||
> call sites route through the VM with legacy fallback.
|
||||
> **Forward (P3.3):** `register_struct` (the first MUTATING fn — mints a `TypeId`; resolve
|
||||
> the mutable-table / host-ABI-vs-target-ABI boundary deliberately), plus any remaining
|
||||
> read-only readers the metatype needs (kind query, `field_value_int`). Re-expressing
|
||||
> `declare`/`define`/`type_info` as sx (the metatype, which runs at LOWERING time) needs the
|
||||
> VM hardened against malformed lowering-time IR first — keep it on the legacy path until
|
||||
> then. Phase 2 (bytecode) is the orthogonal speed work. **Decisions recorded:** `find_type`
|
||||
> returns a non-optional `TypeId` using the `unresolved` (0) sentinel, NOT `?Type`; reader
|
||||
> names use the `type_*` family to avoid colliding with the std metatype builtins
|
||||
> (`field_name`/`type_name` in core.sx) — see `PLAN-COMPILER-VM.md` Phase 3 progress note.
|
||||
> Build/verify: `zig build && zig build test` (690, gate OFF). Run the corpus ON the VM:
|
||||
> `zig build test -Dcomptime-flat` (the build flag) OR env `SX_COMPTIME_FLAT=1`. Coverage
|
||||
> trace: `SX_COMPTIME_FLAT_TRACE=1`.
|
||||
|
||||
@@ -318,6 +322,21 @@ when reached (sentinels or accessor fns; see the design doc Risks).
|
||||
`List` growth; orthogonal, see `current/CHECKPOINT-METATYPE.md`.)
|
||||
|
||||
## Log
|
||||
- **Phase 3 P3.2 (VM plan) — field-level reflection readers: `type_nominal_name` + `type_field_name` + `type_field_type` (2026-06-18).**
|
||||
Three more `compiler`-library readers on the same `TypeId`-handle shape (added to
|
||||
`compiler_lib.bound_fns` AND `Vm.callCompilerFn`), each backed by a new `TypeTable` query
|
||||
BOTH paths call (no drift): `nominalName` (a named type's own name handle; loud-bail for
|
||||
unnamed types like `i64`/pointers), `memberName` (struct/union/tagged-union field, enum
|
||||
variant, named-tuple element), `memberType` (struct/tuple/array/vector member type). All
|
||||
loud-bail on out-of-range idx / no-member (no silent default). First MULTI-ARG compiler
|
||||
fns — `callCompilerFn` reads arg 1 = idx; added `Vm.argHandle`/`argTypeId` (range-checked
|
||||
u32/TypeId arg reads) and refactored `find_type`/`type_field_count` onto them. Named
|
||||
`type_*` to avoid clashing with the std metatype builtins (`field_name`/`type_name` exist
|
||||
in core.sx); `nominalName` (the TypeTable method) is distinct from the existing
|
||||
`typeName(id) []const u8` display-string renderer. Example `0629-comptime-compiler-field-reflect`
|
||||
reflects `Pair { lo: Point; hi: Point }` — each field name + the nominal name of a field's
|
||||
type, all `#run`-folded, all VM-HANDLED natively. VM unit test added (type_field_name → "hi";
|
||||
type_nominal_name(type_field_type(Pair,0)) → "Point"). **Parity 690/690** (gate ON and OFF).
|
||||
- **Phase 3 P3.1 (VM plan) — first read-only reflection readers: `find_type` + `type_field_count` (2026-06-18).**
|
||||
Two more `compiler`-library fns, bound the same way as the `intern`/`text_of` seed (added
|
||||
to `compiler_lib.bound_fns` for the legacy handler + the welded-decl export check, AND to
|
||||
|
||||
@@ -275,13 +275,27 @@ host through it:
|
||||
marker (see CLAUDE.md REJECTED PATTERNS — a dedicated sentinel is the required shape),
|
||||
so the caller checks the handle against 0. This keeps the reader a clean scalar mirror
|
||||
of `intern`/`text_of` and defers `.any`/optional plumbing to when it's actually needed.
|
||||
- **Next (P3.2):** more read-only readers on the same `TypeId`-handle shape (`type_name(t)
|
||||
-> StringId`, `field_name(t, i) -> StringId`, `field_type(t, i) -> TypeId`, kind queries),
|
||||
then `register_struct` (the first MUTATING fn — mints a `TypeId`; resolve the mutable-table
|
||||
/ host-ABI-vs-target-ABI boundary deliberately, per the open questions). Re-expressing
|
||||
`declare`/`define`/`type_info` as sx (the metatype, which runs at LOWERING time) still
|
||||
needs the VM hardened against malformed lowering-time IR first — keep that on the legacy
|
||||
path until then (see the resume note in CHECKPOINT-COMPILER-API.md).
|
||||
- **(P3.2) Field-level reflection readers — `type_nominal_name` + `type_field_name` +
|
||||
`type_field_type` (DONE).** Three more readers on the same `TypeId`-handle shape (each
|
||||
backed by a new `TypeTable` query that BOTH the legacy handler and the VM call, so no
|
||||
drift): `type_nominal_name(t: TypeId) -> StringId` (`nominalName` — a named type's own
|
||||
name; loud-bail for unnamed types), `type_field_name(t: TypeId, idx: i64) -> StringId`
|
||||
(`memberName` — struct/union/tagged-union field, enum variant, named-tuple element), and
|
||||
`type_field_type(t: TypeId, idx: i64) -> TypeId` (`memberType` — struct/tuple/array/vector
|
||||
member type). All loud-bail on out-of-range idx / no-member (no silent default). These are
|
||||
the first MULTI-ARG compiler fns (the VM's `callCompilerFn` now reads arg 1 = idx); added
|
||||
`Vm.argHandle`/`argTypeId` helpers (range-checked u32/TypeId arg reads). Naming uses the
|
||||
`type_*` family so nothing collides with the std metatype builtins (`field_name`/`type_name`
|
||||
exist in `core.sx`). Example `0629` reflects `Pair { lo: Point; hi: Point }` — reads each
|
||||
field name and the nominal name of a field's type, all folded at `#run`, all VM-HANDLED
|
||||
natively. Parity **690/690** (gate ON and OFF); VM unit test added.
|
||||
- **Next (P3.3):** `register_struct` (the first MUTATING fn — mints a `TypeId`; resolve the
|
||||
mutable-table / host-ABI-vs-target-ABI boundary deliberately, per the open questions),
|
||||
plus any remaining read-only readers needed to re-express the metatype (kind query,
|
||||
`field_value_int` for enums). Re-expressing `declare`/`define`/`type_info` as sx (the
|
||||
metatype, which runs at LOWERING time) still needs the VM hardened against malformed
|
||||
lowering-time IR first — keep that on the legacy path until then (see the resume note in
|
||||
CHECKPOINT-COMPILER-API.md).
|
||||
|
||||
### Phase 3 — Compiler-API on flat memory (resume the stream — no weld)
|
||||
With native-byte comptime values, re-home the compiler-API:
|
||||
|
||||
Reference in New Issue
Block a user