ffi checkpoint: step 4A done — bare $args + dynamic reflection

Logs the five 4A.bare slices (c7926422162662):

- 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.
This commit is contained in:
agra
2026-05-27 19:22:08 +03:00
parent 21626628cd
commit 1add93f083

View File

@@ -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(<dynamic-arg>)` 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 `$<pack_name>`; 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.0M1.3 + M2.1M2.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.04.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.04.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`.