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:
@@ -26,30 +26,33 @@ 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 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:
|
||||
> **Next action (2026-06-18):** **Phase 3 is UNDER WAY — the READ side is COMPLETE.** The VM
|
||||
> hosts seven 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_kind(t) -> i64`,
|
||||
> `type_field_count(t) -> i64`, `type_nominal_name(t) -> StringId`,
|
||||
> `type_field_name(t, idx) -> StringId`, `type_field_type(t, idx) -> TypeId`,
|
||||
> `type_field_value(t, idx) -> i64`. Each is backed by a `TypeTable` query
|
||||
> (`findByName`/`kindCode`/`memberCount`/`nominalName`/`memberName`/`memberType`/`memberValue`)
|
||||
> that BOTH the legacy handler and the VM call, so the two paths can't drift. Together they
|
||||
> cover everything `reflectTypeInfo` reads. Examples `0628`–`0630`, all VM-HANDLED natively.
|
||||
> Parity **691/691** (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) — revised direction:** the WRITE side is ONE `register_type(info)` fn that
|
||||
> takes a type-info value and **branches on the kind in the compiler** (subsuming
|
||||
> `define`'s per-kind dispatch), NOT a per-kind `register_struct`. Open design points when
|
||||
> reached: the flat-memory shape of `info`, the mutable-table / host-ABI-vs-target-ABI
|
||||
> boundary, pointer-escape/lifetime. 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); the
|
||||
> write side is a single kind-branching `register_type` — see `PLAN-COMPILER-VM.md` Phase 3
|
||||
> progress note.
|
||||
> Build/verify: `zig build && zig build test` (691, 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`.
|
||||
|
||||
@@ -322,6 +325,20 @@ when reached (sentinels or accessor fns; see the design doc Risks).
|
||||
`List` growth; orthogonal, see `current/CHECKPOINT-METATYPE.md`.)
|
||||
|
||||
## Log
|
||||
- **Phase 3 P3.2b (VM plan) — kind + enum-value readers: `type_kind` + `type_field_value`; READ side complete (2026-06-18).**
|
||||
The last two read-only readers the metatype's `type_info(T)` needs (added to
|
||||
`compiler_lib.bound_fns` AND `Vm.callCompilerFn`, each backed by a `TypeTable` query both
|
||||
call): `type_kind(t) -> i64` (`kindCode` — a stable, compiler-owned discriminant: 0 other ·
|
||||
1 struct · 2 enum · 3 tagged_union · 4 tuple · 5 union · 6 array · 7 vector · 8 error_set;
|
||||
TOTAL, never bails) and `type_field_value(t, idx) -> i64` (`memberValue` — an enum variant's
|
||||
explicit value or ordinal; mirrors the `field_value_int` builtin; loud-bail for non-enum /
|
||||
out-of-range). Example `0630-comptime-compiler-type-kind` reflects `Color` / `WindowFlags`
|
||||
(flags) / `Point`. **The READ side is now COMPLETE** — `find_type` + `type_kind` +
|
||||
`type_field_count` + `type_field_name`/`type_field_type`/`type_nominal_name` +
|
||||
`type_field_value` cover everything `reflectTypeInfo` reads. VM unit test added. **Parity
|
||||
691/691** (gate ON and OFF). **Revised forward direction (per the user):** the WRITE side is
|
||||
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`.
|
||||
- **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
|
||||
|
||||
@@ -289,11 +289,29 @@ host through it:
|
||||
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
|
||||
- **(P3.2b) Kind + enum-value readers — `type_kind` + `type_field_value` (DONE).** The last
|
||||
two read-only readers the metatype's `type_info(T)` needs, completing the READ side: a
|
||||
comptime sx fn can now fully reflect a struct/enum/tagged-union/tuple into data with no
|
||||
`#builtin`. `type_kind(t: TypeId) -> i64` (`TypeTable.kindCode` — a stable, compiler-owned
|
||||
discriminant: 0 other · 1 struct · 2 enum · 3 tagged_union · 4 tuple · 5 union · 6 array ·
|
||||
7 vector · 8 error_set; TOTAL — never bails, an unnamed/non-aggregate type reads `other`)
|
||||
and `type_field_value(t: TypeId, idx: i64) -> i64` (`TypeTable.memberValue` — an enum
|
||||
variant's explicit value or ordinal; mirrors the `field_value_int` builtin; loud-bail for
|
||||
a non-enum / out-of-range idx). Example `0630` reflects `Color`/`WindowFlags`(flags)/`Point`.
|
||||
Parity **691/691** (gate ON and OFF); VM unit test added.
|
||||
- **READ side now complete:** `find_type` + `type_kind` + `type_field_count` +
|
||||
`type_field_name` + `type_field_type` + `type_nominal_name` + `type_field_value` cover
|
||||
everything `reflectTypeInfo` reads.
|
||||
- **Next (P3.3) — ONE `register_type(info)` write fn (revised direction, 2026-06-18):** per
|
||||
the user, the mutating side is NOT per-kind (`register_struct`/`register_enum`/…) but a
|
||||
SINGLE function that takes a type-info value and **branches on the kind in the compiler**,
|
||||
minting the right `TypeInfo`. This subsumes `define`'s `defineStruct`/`defineEnum`/
|
||||
`defineTuple` dispatch into one host-side switch. Open design points to resolve when
|
||||
reached: the flat-memory shape of the `info` argument the sx side passes (a tagged
|
||||
`{ kind, payload }` over the readers' handle types), the mutable-table / host-ABI-vs-
|
||||
target-ABI boundary, and pointer-escape/lifetime (escaping field arrays copied into
|
||||
compiler-owned memory at the boundary). 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).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user