From 7d59b5eeb6c8b74d1d78780fe9f45b570d6dfce0 Mon Sep 17 00:00:00 2001 From: agra Date: Thu, 18 Jun 2026 12:30:35 +0300 Subject: [PATCH] =?UTF-8?q?CHECKPOINT-COMPILER-API:=20refresh=20resume=20b?= =?UTF-8?q?anner=20=E2=80=94=20Phase=203=20read+write=20done,=20lowering-t?= =?UTF-8?q?ime=20VM=20wired;=20next=20is=20the=20dedicated=20Type=20TypeId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Records the current state (read side, write side P3.3, lowering-time hardening + wiring + zeroed context P3.4) and pins the next focused step: a dedicated Type builtin TypeId (8B) distinct from .any (16B box) — ~123 .any refs across ~25 files, a cross-cutting change to run as its own session. Paused here at a clean, green boundary (697/697 both gates) per the decision to not rush it. --- current/CHECKPOINT-COMPILER-API.md | 68 +++++++++++++++++------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/current/CHECKPOINT-COMPILER-API.md b/current/CHECKPOINT-COMPILER-API.md index 38b9b133..bdba86ac 100644 --- a/current/CHECKPOINT-COMPILER-API.md +++ b/current/CHECKPOINT-COMPILER-API.md @@ -26,35 +26,45 @@ 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 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`. +> **Next action (2026-06-18) — PAUSED at a clean boundary; next step decided.** Phase 3 READ +> and WRITE sides are DONE, and the VM is now WIRED at the lowering-time comptime site +> (hardened, with legacy fallback). The first **HANDLED** lowering-time type-fn is gated on a +> **dedicated `Type` builtin TypeId** — that is the next focused effort (see "THE WALL" below). +> +> Done so far in Phase 3: +> - **READ side (7 readers, dual-path):** `find_type`/`type_kind`/`type_field_count`/ +> `type_nominal_name`/`type_field_name`/`type_field_type`/`type_field_value`, each backed by a +> `TypeTable` query both the legacy handler and the VM call (no drift). Examples 0628–0630. +> - **WRITE side (P3.3, legacy-only at lowering time):** `declare_type` + `pointer_to` + ONE +> kind-branching `register_type` (subsumes `define`'s per-kind dispatch; codes match +> `type_kind`: 1 struct · 2 actual `.@"enum"` · 3 tagged_union · 4 tuple). Idempotent re-fill +> (two-edge import). Plus two fixes (issue 0142): all-void enum → real `.@"enum"` (was a +> verifySizes panic); bare `EnumType.variant` qualified construction. Examples 0631–0635, 0187. +> - **Lowering-time VM (P3.4):** hardened the VM against malformed lowering-time IR (`refTy`, +> bailing `aggType`, bounds-checked branch targets — bails, never panics); wired `tryEval` +> into `runComptimeTypeFunc` behind the flag with legacy fallback; materialized a zeroed +> lowering-time `Context` (the global isn't built yet at lowering). All measured green. +> +> **THE WALL (next step):** a `Type` *value* is an 8-byte tid, but `.any` (the boxed-any) is a +> 16-byte `{tag,value}` — and they share one TypeId (`.any`). So a `Type` in an aggregate +> (`Member.ty`/`EnumVariant.payload`) is sized 16B while the value is 8B → every lowering-time +> type-fn bails at `const_type` / the Member-array build. Can't make `kindOf(.any)` a word: +> at EMIT time `.any` really is a 16B box (variadic any, 0603), so that would silently corrupt +> it. The correct fix is a **dedicated `Type` builtin TypeId (8B), distinct from `.any`** — +> measured at **~123 `.any` references across ~25 files** (pack.zig has 30), a ~100-touch-point +> cross-cutting change → its own focused session (USER CHOSE to pause rather than rush it). +> Rejected alternatives: a scoped "lowering-mode treats `.any` as a word" flag (silent-wrong on +> a real Any box in a reflection type-fn); scalar-only Type-fns (safe but no real corpus type-fn +> is scalar-only — they all build a Member/variant aggregate). +> +> **Decisions recorded:** `find_type` returns a non-optional `TypeId` using `unresolved`(0), NOT +> `?Type`; reader names use the `type_*` family (avoid colliding with std `field_name`/`type_name`); +> the write side is a single kind-branching `register_type`; the write side stays LEGACY-only +> until the VM runs at lowering time (needs the `Type` TypeId). End-state guarantee: ONE +> evaluator — `interp.zig` deleted; dual-path + fallback are transitional (see PLAN end state). +> Build/verify: `zig build && zig build test` (**697**, gate OFF). Run the corpus ON the VM: +> `zig build test -Dcomptime-flat` OR env `SX_COMPTIME_FLAT=1`. Coverage trace: +> `SX_COMPTIME_FLAT_TRACE=1` (now also prints lowering-time `type-fn` HANDLED/fallback lines). ### (superseded) prior weld resume Phase 1 done; Phase 2 welded structs were working via reflection + memory-order