From 1add93f083461dea8da58ba12ecabbfb79489d32 Mon Sep 17 00:00:00 2001 From: agra Date: Wed, 27 May 2026 19:22:08 +0300 Subject: [PATCH] =?UTF-8?q?ffi=20checkpoint:=20step=204A=20done=20?= =?UTF-8?q?=E2=80=94=20bare=20$args=20+=20dynamic=20reflection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Logs the five 4A.bare slices (c792642 → 2162662): - 4A.bare.1.A: parser-rejection lock-in for bare $args. - 4A.bare.1.B: parser/AST/lowering — bare $args evaluates to a comptime []Type slice via new buildPackSliceValue helper + ComptimePackRef AST node. - 4A.bare.4.A: silent-.s64 lock-in for dynamic type_name(list[i]). - 4A.bare.4.B: tryLowerReflectionCall splits on isStaticTypeArg; dynamic args emit callBuiltin(.type_name, ...) for the interp's runtime arm. - 4A.bare.5: end-to-end smoke (examples/172-pack-builder-smoke.sx). Step 5 (generic Into(Block) impl in stdlib) is now fully unblocked on the type-system side. Test count 212/212. Remaining within step 4: - 4B compile_error intrinsic. - type_eq / has_impl dynamic-arg dispatch (same isStaticTypeArg split that type_name got). - has_impl interp-time protocol-map snapshot. --- current/CHECKPOINT-FFI.md | 81 +++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 7 deletions(-) diff --git a/current/CHECKPOINT-FFI.md b/current/CHECKPOINT-FFI.md index 52283a7..2863fd7 100644 --- a/current/CHECKPOINT-FFI.md +++ b/current/CHECKPOINT-FFI.md @@ -6,6 +6,71 @@ add a test and make it pass — that's two commits). ## Last completed step +**M5.A.next.4A.bare — bare `$args` + dynamic reflection intrinsics** +(commits `c792642` → `2162662`, 5 slices in order). + +Closes out step 4A. `$args` referenced bare (without `[...]`) +in expression position evaluates to a comptime `[]Type` slice; +`type_name()` correctly dispatches via the +interp's runtime arm when the argument isn't statically +resolvable. Together these are the foundation step 5's +generic Into(Block) builder body rests on. + +| Slice | Commit | What | +|---|---|---| +| 4A.bare.1.A | `c792642` | Expected-failing lock-in for bare `$args` (parser rejection diff). | +| 4A.bare.1.B | `5a4a19b` | Parser makes `[` optional after `$`; new `ComptimePackRef` AST node + sema no-op arms + `lowerExpr` arm calling new `buildPackSliceValue(arg_types)` helper. Helper emits `alloca [N x Any]`, one `const_type(arg_tys[i])` per slot, then a `{data_ptr, len}` slice aggregate. emit_llvm's `const_type` arm relaxed to silent undef-i64 (storage of Type values in runtime aggregates is harmless; loud bail moves to USE sites). | +| 4A.bare.4.A | `95e61d8` | Expected-failing lock-in for `type_name(list[i])` silently returning "s64" via `resolveTypeArg`'s catch-all `else => .s64`. | +| 4A.bare.4.B | `d99c0fd` | `tryLowerReflectionCall` splits on new `isStaticTypeArg(node)` helper. Static args fold to const_string (today's fast path); dynamic args emit `callBuiltin(.type_name, [arg_ref])` for the interp's arm. emit_llvm's reflection-builtin arm relaxed to silent undef-i64 — same reasoning as const_type: storage-position misuse is impossible, use-site misuse caught by the interp arm's `asTypeId orelse bailDetail`. | +| 4A.bare.5 | `2162662` | End-to-end smoke `examples/172-pack-builder-smoke.sx`. `describe(..$args)` walks `$args` at #run time, calls `type_name(list[i])` per position. Four call shapes (empty, one-arg, two-arg, four-mixed) verify the full chain works. | + +What now works end-to-end (from `examples/172-pack-builder-smoke.sx`): + +```sx +describe :: (..$args) -> string { + list := $args; + s := "["; + i : s64 = 0; + while i < list.len { + if i > 0 { s = concat(s, ", "); } + s = concat(s, type_name(list[i])); + i = i + 1; + } + s = concat(s, "]"); + return s; +} + +#run { print("{}\n", describe(true, 3.14, "x", 99)); } +// → [bool, f64, string, s64] +``` + +The pack flows through a real `[]Type` slice value; the loop +indexes dynamically; each element's TypeId comes back through +the type_name interp arm; the per-position concrete type +names are joined into a string. All at interp time inside +`#run`. No silent paths anywhere. + +Known follow-ups (not blocking step 5): +- `type_eq` / `has_impl` dynamic-arg dispatch — should follow + the same `isStaticTypeArg` split that `type_name` got in + 4A.bare.4.B. Today their dynamic-arg case still silently + folds via the same `resolveTypeArg .s64` fall-through. + Wire when a real use case needs them. +- `has_impl` interp arm — still bails "not yet wired". + Needs a protocol-map snapshot on `Interpreter.init`. +- `any_to_string`'s `case type:` in stdlib still uses + `xx val to string`. Once `.type_tag` flows into a print + path, the bitcast guard fires loudly — fix is to replace + with `type_name(val)` once value-form `type_name` lowers + through the dynamic path. + +212/212 example tests + `zig build test` green. + +Step 5 (generic `Into(Block)` impl) is now fully unblocked +on the type-system side. + +--- + **M5.A.next.4 — activate Value.type_tag (Type as a first-class value)** (commits `ac60d98`, `9600ba5`, `55c72af`, `fd03b58` — 4 slices). @@ -787,7 +852,7 @@ plus 2 codegen fixes surfaced along the way.** ## Current state -- 209/209 example tests pass; `zig build test` green. +- 212/212 example tests pass; `zig build test` green. - Phase 3.0/3.1/3.2 + M1.0–M1.3 + M2.1–M2.3 + M3 + M4.0 + M4.A all landed. - Pack feature step 1 done (1c.A → 1d.B; commits bb6eca6 → 08feb60). - Pack feature step 2 done — typed `args[$i]` at literal indices @@ -806,6 +871,10 @@ plus 2 codegen fixes surfaced along the way.** - Pack feature step 4.0–4.3 done — `Value.type_tag` activated honestly; source-language `$args[$i]` in expression position yields a comptime Type value end-to-end. +- Pack feature step 4A.bare done — bare `$args` evaluates to a + comptime `[]Type` slice; dynamic `type_name(list[i])` lowers + through the interp's runtime arm via a new `isStaticTypeArg` + split in `tryLowerReflectionCall`. - iOS-sim chess running end-to-end (verified post-step-2b screencap). - Chess on macOS / iOS-sim / Android all build and run. @@ -817,15 +886,13 @@ heterogeneous picks, OOB diagnostics, bare/runtime `args` access, mixed comptime+pack, `$args[$i]` in type positions, type-reflection intrinsics. -Step 4 partially done — `.type_tag` activation + `$args[$i]` -in expression position landed (4.0–4.3). Still open within -step 4: +Step 4A done end-to-end (4.0 → 4.3 → 4A.bare). Step 4 remaining: - 4B `compile_error(fmt, args)` comptime intrinsic — raise a build-time diagnostic from inside a builder. Small commit set; not blocking step 5 but useful for builder error paths. -- 4A's bare `$args` (whole pack as `[]Type` value) — the only - remaining shape needed for step 5's full generic builder - pattern; single-element `$args[$i]` works today. +- `type_eq` / `has_impl` dynamic-arg dispatch — follow the + same `isStaticTypeArg` split that `type_name` got in + 4A.bare.4.B. - `has_impl` interp arm — currently bails, needs a protocol- map snapshot on `Interpreter.init`.