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:
@@ -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.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 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
|
||||
|
||||
Reference in New Issue
Block a user