ffi checkpoint: 2a control-flow fix + step 2/3 roadmap

Logs the 2a.C/2a.D pair (6b7a66b + e6d6903) — the if-return
regression in issue-0045's original fix, now resolved via the
SSA "return-done block" pattern.

Step 2 is functionally sufficient for the impl-matching payoff
(step 5 of the plan); per-call-shape monomorphisation deferred
until a real workload demands it.

Step 3 ("Type-reflection intrinsics") flagged as the natural
next slice: `$args[$i]` in type positions unlocks the block-
trampoline body in stdlib's generic Into(Block) impl, which is
the visible payoff of the whole pack feature.
This commit is contained in:
agra
2026-05-27 14:58:13 +03:00
parent e6d6903708
commit 39a804f25e

View File

@@ -6,6 +6,48 @@ add a test and make it pass — that's two commits).
## Last completed step
**M5.A.next.2a.D — inline-return uses CFG terminator, not block_terminated**
(commit `e6d6903`, lock-in `6b7a66b`).
Fixes a control-flow regression in issue-0045's original fix
(commit `9e78790`). The original set `block_terminated = true`
after each inline `return X;` to skip dead code in the inlined
body — but the flag leaked past structured control flow. A
body shaped `if cond { return X; }; return Y;` had its
trailing `return Y;` short-circuited at `lowerBlockValue`'s
`if (self.block_terminated) return null;` check. For the false-
condition path, the slot was never written → load read
uninitialised stack memory.
Reshaped to the classical SSA "return-done block" pattern:
- `InlineReturnInfo` gains a `done_bb: BlockId` field — a
fresh basic block allocated by `lowerComptimeCall` per
comptime-call instance.
- `lowerReturn`'s inline path stores into the slot, drains
defers, and emits `br done_bb`. The basic block's terminator
carries the "no fall-through" signal; the
`block_terminated` flag is no longer touched.
- `lowerComptimeCall` lowers the body, then unconditionally
switches to done_bb and loads the slot. Tail-expression
bodies (rare when has_return is true) get a synthetic store
+ br so the CFG stays well-formed.
`examples/157-pack-if-return.sx` flips from `8354116000` (the
uninit slot load) to `-1`. A three-way `classify(..$args)`
smoke confirms multi-return-path bodies work for any of the
three branches; defer-with-return still fires the defer at the
correct exit.
issue-0046 (nested `print` inside `..$args` body that also
`return`s) is unrelated to this fix and is still open — same
two faces as filed: interp panic for plain comptime, "unresolved
'result'" for pack-fn.
196/196 example tests + `zig build test` green.
---
**M5.A.next.2a.B — pack typed indexing: `args[$i]` substitutes call arg**
(commit `cd36784`, lock-in `223ec3d`).
@@ -484,13 +526,42 @@ plus 2 codegen fixes surfaced along the way.**
## Current state
- 195/195 example tests pass; `zig build test` green.
- 196/196 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 2a done — typed `args[$i]` at literal indices (cd36784).
- Pack feature step 2a done — typed `args[$i]` at literal indices
(cd36784) + control-flow CFG terminator fix (e6d6903).
- issue-0045 (comptime-fn-with-return verifier crash) fixed (9e78790).
- issue-0046 (nested-comptime-call + return) FILED, not blocking
next slices since builders run inside `#insert`, not inside
public pack-fn bodies.
- Chess on macOS / iOS-sim / Android all build and run.
## Pack feature — next slice options
Step 2 ("Runtime indexing + mono expansion") is functionally
sufficient for the impl-matching payoff (step 5) thanks to step
1d.B's per-mono mangling on `<src>.convert__<dst>` keys.
Remaining within step 2 is real per-call-shape monomorphisation
(today pack-fns inline at every call site) — performance/IR-size
concern, not correctness. Defer until a real workload demands it.
Step 3 ("Type-reflection intrinsics") is the natural next slice:
- `$args[$i]` in TYPE positions (param types, return types,
fn-pointer types, struct fields).
- `type_name`, `type_eq`, `has_impl` comptime intrinsics.
- Unlocks the block-trampoline body in stdlib's generic
`Into(Block) for Closure(..$args) -> $R` impl — the body
needs `typed_fn : (*void, $args[0], $args[1]) -> $R = xx ...`
per-position type interpolation.
Step 4 (`#insert` pack passthrough + `compile_error`) is a
parser/interp tweak letting builders raise build-time
diagnostics from inside `#insert` bodies.
Steps 5 and 6 are stdlib refactors gated on step 3's
type-position substitution landing.
**M4.0 — context.allocator threading** (4 commits this session):
- `__sx_allocator: Allocator` prepended at field index 0 of every
sx-defined class's state struct