From 0e890b99921b8f9a3bb8cd09c87cf8b3cb1a0a27 Mon Sep 17 00:00:00 2001 From: agra Date: Fri, 12 Jun 2026 07:41:48 +0300 Subject: [PATCH] =?UTF-8?q?checkpoint:=20MEM=20record-keeping=20=E2=80=94?= =?UTF-8?q?=20facade=20completion,=20phase=20ground=20truth,=202.2=20state?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Brings the MEM checkpoint up to the 2026-06-11 sessions: the std.sx pure-re-export facade arc (49a36bb/c75cd9c + issues 0120-0122), the allocator primitive rename (88bae3c), opt-in UFCS (a47ea14), Phase 2.2 typed helpers (84e0fb0), BufAlloc by-value init (51194a2); next step Phase 2.3 diagnostic wrappers. Older 2026-05-25-era records fold into collapsed details blocks. --- current/CHECKPOINT-MEM.md | 239 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) diff --git a/current/CHECKPOINT-MEM.md b/current/CHECKPOINT-MEM.md index 9d5c19e..b83e4e2 100644 --- a/current/CHECKPOINT-MEM.md +++ b/current/CHECKPOINT-MEM.md @@ -5,6 +5,39 @@ Tracking checkpoint for the mem.sx Zig-aligned implementation ## Last completed step +**Allocator primitive rename — `alloc`→`alloc_bytes`, +`dealloc`→`dealloc_bytes` (`88bae3c`, 2026-06-11).** Phase 4's naming +piece pulled forward per Agra's call (Option A in the 2.2 naming fork): +the bare names free up NOW so the Phase 2.2 helpers land under their +FINAL Appendix-A names (`alloc(T,n)` / `free(s)` / `create` / `destroy` +/ `clone` / `resize` / `mem_realloc`) with zero later churn. Phase 4 +shrinks to signature expansion (size/align params + resize/remap + +deinit) only. + +What changed (signatures unchanged — 2-method era continues): +- `std.sx` protocol decl; `std/mem.sx` 6 impls + internals; library + call sites (glyph_cache/json/state/renderer); 13 example .sx files + (incl. the two custom `Tracer` impls in 0306/0808 — caught broken + mid-step by stdout-diff review BEFORE pinning; the first `--update` + had captured their broken output, restored + fixed + re-pinned). +- Compiler: `interp.zig` thunk-name lookups + (`__thunk_CAllocator_Allocator_alloc_bytes`/`_dealloc_bytes`) — the + ONE hard name coupling; `allocViaContext` + default-context emission + are slot-positional (rename-safe); ffi.zig's `"alloc"` check is the + Obj-C `Cls.alloc()` intercept (unrelated, untouched). +- 37 `.ir` snapshots re-pinned (thunk symbols + reflection + field-name strings); all 37 verified stdout-clean before update; + path-noise churn reverted. +- External repos migrated + gated: game (`main.sx`, SxChess.app + builds + bundles) and m3te (`board_fx.sx`, `main.sx`, + `tools/key_particle.sx`; tools/run_tests.sh 23/23). Obj-C zero-arg + `.alloc()` calls are NOT protocol calls — excluded by pattern. + +Gates: zig build 0, zig build test 0, suite 582/582, m3te 23/23, +game rebuilt. + +
Prior steps (2026-05-25 era) + - **`resolveType(null) → .s64` silent fallback removed.** `resolveType` now takes a non-optional `*const Node`; the `null → .s64` branch is gone. Callers that legitimately had no annotation handle it @@ -140,8 +173,66 @@ Tracking checkpoint for the mem.sx Zig-aligned implementation of zeros, on both interp and codegen paths. 156/156 example tests + chess clean. +
+ ## Current state +**std.sx-as-pure-re-exports plan COMPLETE** (2026-06-11, +Agra-directed end-to-end). std.sx is now a facade of alias +declarations only (`49a36bb`): implementations live in std/core.sx +(builtins, libc escape hatch, Context/Allocator/Into/Source_Location/ +`string` — the reserved name needs and permits no alias), std/fmt.sx +(print/format/any_to_string/string ops), std/list.sx (List); the +namespace tail is unchanged and `core`/`fmt`/`list` carry alongside +it. Consumer surface byte-identical; 37 .ir snapshots re-pinned +(pure renumbering, digit-normalized diff empty). + +Issues filed AND resolved along the way (all same-day, +Agra-authorized): 0120 generic-struct head aliases (`f2db8ec`, +example 0211), 0121 fn aliases of every kind incl. comptime-pack +(`721369a`, example 0546), 0122 whole-program passes pinning the +source context per decl (`340be40` — latent on master, exposed by +the facade; coverage 0129/1047/1049/1052/1053/1056). Protocol +aliases (plain + Into's xx path) and #builtin/#foreign aliases +probe-verified working; param-protocol impl dot-calls are a designed +opt-in gap, not a bug. + +Gates at completion: zig build test 426/426, suite 588/588, +m3te 23/23, game SxChess builds + bundles. Suite baseline 588. + +**(2026-06-11) Phase-by-phase ground truth** (verified against the +tree; the sections below this one are the 2026-05-25 era record): +- Phase 1 DONE (xx heap-copy via context.allocator; serializer; the + whole implicit-Context refactor). +- Phase 2.1 DONE-equivalent: allocators.sx became `std/mem.sx` via the + STDLIB restructure (`59f0aa7`). +- **Primitive rename DONE (`88bae3c`)** — see "Last completed step". + Protocol is `alloc_bytes(size)` / `dealloc_bytes(ptr)` (2-method + era signatures). +- Phase 2.2 helpers: NOT YET — next step. Final names per Appendix A: + `create(a,$T)->*T`, `alloc(a,$T,n)->[]T`, `destroy(a,ptr)`, + `free(a,slice)`, `clone(src,a)`, `resize(slice,a,n)`, + `mem_realloc(a,ptr,old,new,align)`. The `free` helper requires + REMOVING std.sx's bare `malloc`/`free` foreign decls (lines ~13-16; + `libc_malloc`/`libc_free` aliases already exist) and migrating ~30 + bare uses (mostly examples) — fold into the helpers step. +- Phase 2.3: TrackingAllocator exists; FailingAllocator + + LoggingAllocator missing. +- Phase 3 (caller migration to helpers): not started. +- Phase 4: now signature-expansion only (alloc_bytes gains alignment; + dealloc_bytes gains size+align; + resize/remap/deinit) — naming + piece already landed. +- Phase 5 (--leak-check + specs Memory chapter): not started. +- NOTE: plan's "init returns Allocator via xx heap-copy" section is + SUPERSEDED by the by-value convention (CLAUDE.md "Allocator + construction"); BufAlloc.init still returns *BufAlloc (state lives + in the caller's buffer — review at Phase 4 whether to align). +- Suite baseline 582; gates now: zig build && zig build test && + bash tests/run_examples.sh (+ m3te 23/23 + game build for + std-touching steps). The old 148-159 counts below are historical. + +
2026-05-25 era state (historical) + Phase 0.0c shipped (allocator API on one-line `init` returning `*T`; TrackingAllocator added). 148/148 tests pass. @@ -270,8 +361,77 @@ bypass) is FULLY CLOSED. User-typed `context.allocator.X` flows through the real protocol vtable at codegen *and* runs the same chain at comptime in the interp. No remaining shortcut. +
+ +## Current state + +**Opt-in UFCS landed (`a47ea14`, 2026-06-11)** — the canonical dot +surface now works: `context.allocator.create(Session)`, +`slice.clone(a)`. Agra specified the model in-session (three +clarifying rulings): free-fn dot-calls are OPT-IN via +`name :: ufcs (params) { body }` (NEW declaration form) or +`name :: ufcs target;` (alias); plain fns are direct/`|>`-only with a +tailored rejection. Implementation inverted TWO pre-existing gaps: +unannotated fns used to dot-dispatch (removed; 6 example files +audited + migrated, ZERO reliance in m3te/game) and aliases did NOT +dot-dispatch at all (0036 only ever pinned direct+pipe). Generic ufcs +fns bind `$T` from the receiver; protocol receivers dispatch own +methods first, fall through to ufcs fns for non-members +(protocolHasMethod gate in lower/call.zig). Root-cause bonus: +`inferGenericReturnType` now delegates to `buildTypeBindings` (ONE +binding builder) — structured generic params (`[]$T`) no longer type +direct calls as `T{}` stubs. mem.sx helpers marked `ufcs`; specs.md +§UFCS rewritten around the opt-in matrix. Tests: 0053 (matrix), 1166 +(rejection), 0838 re-pinned (dot+pipe+direct). Gates: 585/585, zbt 0, +m3te 23/23, game builds. 0119 RESOLVED (final banner). + +**Phase 2.2 DONE (`84e0fb0`, 2026-06-11).** The 0119 block resolved as +a LANGUAGE RULING, not a compiler fix (Agra, in-session): dot-form UFCS +on generic free functions is not the contract — UFCS free-fn +dot-dispatch is the annotated `ufcs` alias mechanism (concrete +targets), and the FLUENT spelling for free functions is the pipe: +`context.allocator |> create(Session)` desugars at parse time to the +direct call, which dispatches generics through normal monomorphization +(verified for protocol + slice receivers). specs.md §UFCS corrected +(it overstated "generic functions" for the dot form). Issue 0119 +carries the RESOLVED banner; residual unfiled corner: a `ufcs` alias +naming a generic target doesn't dot-dispatch either. + +Landed: +- `std/mem.sx` typed helpers, era-complete bodies, final names: + `create(a,$T)->*T`, `destroy(a,*$T)`, `alloc(a,$T,n)->[]T`, + `free(a,[]$T)`, `clone(src,a)`, `resize(slice,a,n)` (fresh storage + + copy + free-old; old slice dangles), `mem_realloc(a,ptr,old,new, + align)` (alloc+copy+dealloc; align unhonored until the protocol + carries alignment — documented inline). NO zero-init (Zig-aligned). +- std.sx bare `malloc`/`free` decls REMOVED (libc_malloc/libc_free + stay as the raw escape hatch); users migrated: examples + 0205/0604/0804/0806/0808/1610 + game/chess/pieces.sx. +- Regression: examples/0838-memory-helpers.sx (whole surface, direct + + `|>` spellings, TrackingAllocator balances 8/8). 37 .ir re-pins + (constant-pool renumbering from the removed decls — the + ISSUE-MEM-004 cascade; all verified stdout-clean pre-update). +- KNOWN GAP: `string` does NOT bind a `[]$T` param (probe: "unknown + type 'T'") — string-clone story deferred (sx string is [:0]u8-shaped; + decide at Phase 4/5). + +Gates: zig build 0, zbt 0, suite 583/583, m3te 23/23, game SxChess.app +builds. + ## Next step +**Phase 2.3 — diagnostic wrappers**: `FailingAllocator` (delegates to +parent while budget remains, then alloc returns null) and +`LoggingAllocator` (tag-prefixed prints, delegates) in `std/mem.sx`, +2-method-era bodies, by-value `init` per the CLAUDE.md convention. +Then Phase 3 (migrate std.sx/library/example callers to the helpers — +NOTE std.sx itself cannot import mem.sx (circular); its internals keep +alloc_bytes), Phase 4 (protocol signature expansion: alignment + size +on the primitives, resize/remap/deinit — naming already landed), +Phase 5 (--leak-check + specs Memory chapter). + +
2026-05-25 era next-step record (historical) + Phase 1.3 (closure env allocation through context) shipped in commit `8e21cc5`. Phase 1.4 (codegen serializer for all interp Value variants) shipped this session. Phase 1.2 (free / malloc through @@ -300,6 +460,8 @@ Open follow-ups, in roughly the order they make sense: the canonical buffer/string case is already handled by `[]T` / `string`. +
+ ## Phase 0.3 audit findings — chess allocator usage (closed) After Step 5 / matchContextAllocCall removal, every consumer call @@ -324,6 +486,83 @@ Allocator value naturally. ## Log +- **2026-06-11 (latest)** — Redundant flat `#import "modules/std/mem.sx"` + dropped from the facade (`c75cd9c`, Agra spotted it): the tail's + `mem ::` import already covers the graph needs (ufcs helpers + + CAllocator); the double import was duplicating lowered IR (~2.5k + lines across 37 re-pinned .ir snapshots, output byte-identical). + Gates: suite 588/588, zbt 0, m3te 23/23, game builds. +- **2026-06-11 (prior)** — std.sx restructured to a pure re-export + facade (`49a36bb`): all implementations moved to std/core.sx / + std/fmt.sx / std/list.sx; std.sx = alias decls + namespace tail. + En route, two more issues filed AND resolved: 0121 fn aliases + (`721369a` — renamed aliases were broken for EVERY fn kind, not + just packs; scan-time fn_ast_map registration via the shared + alias-chain walk; example 0546) and 0122 ambient source-context + bugs in convergeClosureShapeSets / checkErrorFlow / unknown-type + loop (`340be40` — latent on master, exposed by the facade). + Probe-verified before executing: protocols (plain + Into xx path), + #builtin / #foreign aliases, reserved `string` (no alias needed or + possible). 37 .ir re-pins (pure renumbering). Gates: zbt 426/426, + suite 588/588, m3te 23/23, game builds + bundles. +- **2026-06-11 (prior)** — Issue 0120 filed AND resolved (Agra-directed + same-session fix). Found probing the std.sx-as-pure-re-exports + restructure: generic-struct head alias (`BoxAlias :: Box;`) lowered + silently to `.unresolved` → LLVM backend panic; cross-module + `Box :: r.Box;` re-export invisible. Fix: `selectGenericStructHead` + follows const-alias decls hop-by-hop from each ALIAS AUTHOR's source + (`aliasedStructTemplate`, nominal.zig; `namespaceAliasVerdictFrom` + for `ns.X` RHS), checked before the template map so a facade's + same-name re-export beats an invisible global template; plus the + missing "unknown type" diagnostic on the `.call` type-head tail + (resolveTypeCallWithBindings). Also fixed PRE-EXISTING stale unit + test (calls.test.zig UFCS plan — predated a47ea14's opt-in model; + master was 425/426). specs.md Type Aliases + readme re-export + section + Decisions Log updated. Regression: examples/0211 (+rich/ + +facade companions). Gates: zbt 426/426, suite 587/587. +- **2026-06-11 (prior)** — BufAlloc.init by-value (`51194a2`, Agra + request): init no longer carves its state struct off the buffer's + head (`-> BufAlloc`, plain literal; the old `-> *BufAlloc` cost 24 + bytes of every buffer and returned null under min-size). The + CLAUDE.md by-value convention now holds for ALL allocators. + Regression: examples/0839 (full-capacity 64+64 on a 128 buffer — + failed pre-fix; exact-fit, overflow, reset). 0129's pinned output + unchanged. .ir churn: init's signature (sret) + renumbering. + Gates: 586/586, zbt 0, m3te 23/23, game builds. +- **2026-06-11 (earlier)** — Opt-in UFCS (`a47ea14`). Agra's model: + dot-calls opt-in via `:: ufcs (...)` marker or `:: ufcs target;` + alias; plain fns direct/`|>`-only. Parser (ufcs-fn form, + FnDecl.is_ufcs), call-plan + lowering gates (calls.zig, + lower/call.zig), protocol-receiver fall-through, generic dispatch + with receiver-bound `$T`, inferGenericReturnType → buildTypeBindings + (fixes pre-existing `T{}` mis-typing of structured-param generics). + 6 reliant examples migrated; mem helpers marked ufcs; specs §UFCS + rewritten; tests 0053+1166+0838. 585/585, zbt 0, m3te 23/23, game + builds. 0119 closed with the full arc in its banner. +- **2026-06-11 (later)** — Phase 2.2 shipped (`84e0fb0`). Typed helpers + in std/mem.sx (create/destroy/alloc/free/clone/resize/mem_realloc, + era-complete bodies, no zero-init); bare malloc/free dropped from + std.sx (6 example files + game pieces.sx migrated to libc_*). The + 0119 "blocker" resolved as Agra's language ruling: generic free fns + are NOT dot-rewritten — fluent spelling is `|>` (parse-time desugar + → direct call → normal monomorphization; verified on protocol + + slice receivers). specs.md §UFCS corrected; 0119 RESOLVED banner. + Regression examples/0838 (direct + |> spellings; tracker 8/8). + 37 .ir re-pins (const-pool renumbering). Gates: 583/583, zbt 0, + m3te 23/23, game builds. String-clone deferred (string doesn't bind + []$T — known gap noted). +- **2026-06-11** — Allocator primitive rename (`88bae3c`): protocol + `alloc`→`alloc_bytes`, `dealloc`→`dealloc_bytes` (2-method-era + signatures unchanged). Phase 4's naming piece pulled forward (Agra + Option A) so Phase 2.2 helpers land final-named once. Touched: + std.sx decl, mem.sx 6 impls, 4 library files, 13 examples (incl. + two custom Tracer impls — initially missed, caught by pre-pin + stdout review after the first --update captured their broken + output; restored, fixed, re-pinned), interp.zig thunk-name strings, + 37 .ir snapshots. Externals migrated + gated: game (SxChess.app + builds) + m3te (23/23). Suite 582/582, zbt 0. Discriminator note: + Obj-C `.alloc()` is zero-arg; Allocator `.alloc(size)` has an arg — + the sed keyed on `\.alloc\((?!\))`. - **2026-05-25 (latest)** — `resolveType(null) → .s64` removed. Signature changed to non-optional `*const Node`; 12 callers surveyed and classified. The three unguarded ones — top-level