comptime VM: port the WRITE side (declare_type/pointer_to/register_type) -> first HANDLED lowering-time type-fns

declare_type / pointer_to / register_type are now serviced natively in
Vm.callCompilerFn, mirroring the legacy compiler_lib handlers (mint via
@constCast(table) — the lowering-time mint target is &module.types). register_type
reads the []Member slice from flat memory: ref_types is threaded through invoke ->
callCompilerFn so the slice element type (Member = {name: string, ty: Type}) gives
the field offsets + stride; each {name, ty} is decoded and minted with the same
kind branching + dup/payload rejections + idempotent re-fill as legacy.

Key unblock: the synthesized comptime type-fn wrapper was built with return type
.any, so regToValue bailed at the VM<->legacy boundary; changed to .type_value
(the legacy path reads via asTypeId regardless). The compiler-API write type-fns
(0631 register-graph, 0635 multi-edge import) now run HANDLED end-to-end on the VM
at lowering time — parity-correct, on the zeroed lowering-time context (fixed
member arrays, no allocation). The metatype make_enum/define examples still fall
back cleanly through call_builtin(define).

697/0 both gates + EXIT=0.
This commit is contained in:
agra
2026-06-18 14:19:54 +03:00
parent 7b1212b41e
commit 66005af478
3 changed files with 161 additions and 12 deletions

View File

@@ -31,11 +31,16 @@ with ONE welded mechanism. Branch: `reify` (off `master`). Update after every st
> wired end-to-end: foundation (`6844fb9`), resolver flip + full `.any`-ref migration (`94f60c5`),
> and the VM models `.type_value` natively (`554871b`). **697/0 BOTH gates + 494 unit tests.**
> `first_user` is now **100** (slots 2099 reserved builtin headroom so future builtins don't
> renumber user TypeIds / churn snapshots). What remains is the PAYOFF, no longer gated on the WALL:
> port the **WRITE side** (declare_type / register_type / pointer_to) into `Vm.callCompilerFn` +
> give the lowering-time path a **REAL Context** (CAllocator thunk func-refs, not zeroed) → the
> first **HANDLED** lowering-time type-fn end-to-end on the VM. Today those type-fns run partway on
> the VM then bail cleanly at the `define`/`register_type` `call_builtin` → legacy mints (parity).
> renumber user TypeIds / churn snapshots). The PAYOFF is now LANDED (`<this commit>`): the
> **WRITE side** (declare_type / register_type / pointer_to) is VM-native in `Vm.callCompilerFn`
> the compiler-API type-fns (`0631`/`0635`) run **HANDLED end-to-end on the VM at LOWERING
> time** (parity-correct), the first lowering-time comptime to do so; they run on the zeroed
> lowering-time context (no allocation). **697/0 both gates + EXIT=0.** What's LEFT toward the
> end-state ONE evaluator: (1) re-express the metatype `define`/`make_enum` over the compiler-API
> + delete the bespoke interp arms (the `make_enum` examples still fall back cleanly through
> `call_builtin(define)`); (2) a REAL lowering-time Context (CAllocator thunk func-refs) for
> List-growing type-fns — deferred (no HANDLED type-fn allocates); (3) eventually flip the VM to
> default + delete `interp.zig`.
>
> Done so far in Phase 3:
> - **READ side (7 readers, dual-path):** `find_type`/`type_kind`/`type_field_count`/
@@ -341,6 +346,27 @@ when reached (sentinels or accessor fns; see the design doc Risks).
`List` growth; orthogonal, see `current/CHECKPOINT-METATYPE.md`.)
## Log
- **Phase 3 P3.4 step 5 (VM plan) — WRITE side ported to the VM → FIRST HANDLED lowering-time type-fns (2026-06-18).**
Ported `declare_type` / `pointer_to` / `register_type` into `Vm.callCompilerFn`, mirroring the
legacy `compiler_lib` handlers (mint via `@constCast(table)` — the same mutable access the
read-side `intern` uses; the lowering-time mint target IS `&module.types`). `register_type`
reads the `[]Member` slice from FLAT MEMORY: threaded `ref_types` through `invoke` →
`callCompilerFn` so the slice's element type (`Member = {name: string, ty: Type}`) gives the
field offsets + stride; decodes each `{name, ty}` and branches on `kind` (1 struct · 2 enum ·
3 tagged_union · 4 tuple) exactly as legacy (dup-name / payload-on-enum rejections, idempotent
re-fill via `nominalIdentOf`). **Key unblock:** the synthesized comptime type-fn wrapper
(`createComptimeFunction`/`…WithPrelude`) was built with return type `.any` → `regToValue`
bailed at the VM↔legacy boundary; changed to `.type_value` (the legacy path reads via `asTypeId`
regardless, so no legacy change). **Result: the compiler-API write type-fns now run HANDLED
end-to-end on the VM at LOWERING time** — `0631` (register-graph: 2 HANDLED, A↔B cycle via
forward handles + `pointer_to`) and `0635` (multi-edge import: 2 HANDLED), parity-correct. They
run on the ZEROED lowering-time context (fixed `.[…]` member arrays, no allocation). The
metatype `make_enum`/`define` examples (`0632`) still fall back CLEANLY through
`call_builtin(define)` (the separate metatype path — re-expressing it onto the compiler-API is
the other half of P3.4). **697/0 BOTH gates + EXIT=0.** On `reify`. **Next:** (optional, deferred)
a REAL lowering-time Context (CAllocator thunk func-refs) for List-growing type-fns; and
re-express the metatype `define`/`make_enum` over the compiler-API to delete the bespoke interp
arms (the end-state: ONE evaluator).
- **Phase 3 P3.4 step 4 (VM plan) — model `.type_value` natively in the comptime VM (2026-06-18).**
The VM now HANDLES Type values instead of bailing: `kindOf(.type_value)` → `.word`; a new
`const_type` exec arm → the word `TypeId.index()`; `regToValue` maps a `.type_value` word back