**FIXED.** `lowerComptimeCall` now allocates a result slot when the body contains a `return` statement and reroutes `lowerReturn` to store into it instead of emitting `ret` into the caller's basic block. Regression test: [examples/issue-0045.sx](../examples/issue-0045.sx). # Symptom Calling a fn declared with `..$args` (variadic heterogeneous type pack, parser-accepted as of commit `a51fe26`) — even with zero positional arguments — emits LLVM IR that fails verification: ``` LLVM verification failed: Terminator found in the middle of a basic block! label %entry ``` No IR is printed by `sx ir`; the `sx run` JIT exits 1 immediately. Expected: at minimum, the empty-pack call site should compile and execute the fn body. Plan step 2 ("Runtime indexing + mono expansion") specifies per-mono mangling and `..$args` expansion to N positional IR params; until that lands, calling such a fn should at minimum emit a clear "pack-fn calls not yet implemented" diagnostic rather than corrupt IR. # Reproduction ```sx foo :: (..$args) -> s64 { return 42; } main :: () -> s32 { n : s64 = foo(); return 0; } ``` ``` $ ./zig-out/bin/sx run repro.sx LLVM verification failed: Terminator found in the middle of a basic block! label %entry ``` `foo()` with zero args, one arg (`foo(1)`), or multiple args (`foo(1, "hello")`) all produce the same crash. # Background After M5.A.next.1b (commit `a51fe26`), `parseParams` accepts `..$args` as a parameter declaration. The Param is recorded with `is_variadic = true`, `is_comptime = true`, `type_expr = inferred_type`. `parseFnDecl`'s `collectTypeParams` then registers `args` as a type-param (because `is_comptime = true`), so `fd.type_params.len > 0`. This routes the fn through the existing generic-fn path: `lowerFnDecl` skips eager lowering, expecting calls to monomorphise at first use. But the existing monomorphisation machinery binds a single TypeId per `$T` name — it has no notion of a *pack* (a variable-length list of TypeIds bound positionally). When the call site tries to monomorphise with the call's args, the body's `args` parameter gets resolved to a single (probably default `.s64`) TypeId, but the call-site arg-packing path (`packVariadicCallArgs`) treats it as a regular `..T` slice — the two views disagree and the emitted IR is malformed. The bug isn't in step 1's code itself; it's the gap between "step 1 made the syntax parseable" and "step 2 hasn't made the calls executable yet." # Investigation prompt For a fresh session picking this up: Plan step 2 ("Runtime indexing + mono expansion") in `~/.claude/plans/lets-see-options-for-merry-dijkstra.md` is the intended fix: 1. Detect pack-fns at declaration: the fn has a trailing param with `is_variadic && is_comptime` (no concrete type annotation distinguishes it from a regular `args: ..T` variadic). 2. Per-call monomorphisation: bind `$args := [T1, ..., Tn]` from the call site's concrete arg types. Each unique `(arg-type-tuple, $ret)` combination gets its own mono. 3. Expand the pack into N positional IR params in the mono's signature; mangling encodes the pack shape so distinct monos get distinct symbols. 4. Body `args[$i]` at comptime-known `$i` lowers to the i-th expanded param load (return type from `$args[$i]`). Key files: - `src/ir/lower.zig`: - `lowerFnDecl` (around line 949 — generic skip) needs to keep skipping pack-fns. - `monomorphizeFunction` (line 7834) needs a pack-aware path that binds `pack_bindings` (the field added in commit `08feb60` for impl matching) instead of just `type_bindings`. - `packVariadicCallArgs` (line 7275) should NOT run for pack fns — args stay positional, not slice-packed. - Index-expression lowering needs an `args[$i]` arm that reads the i-th positional param. - `src/ir/types.zig`: `FunctionInfo`/`ClosureInfo` have `pack_start` already (added in commit `6582449`); the mono's expanded signature should NOT carry `pack_start` (it's a concrete shape). Verification: the repro above compiles and prints "42" when run as `./zig-out/bin/sx run repro.sx`. A new `examples/156-pack-fn-mono.sx` (number depends on next free slot) should be added per the FFI cadence rule (xfail-lock-in then green). Alternative interim option: if step 2 is too large to land in one session, gate `parseFnDecl` to reject pack params with an explicit "pack-fn body lowering not yet implemented; only impl target types accept `..$args` today" diagnostic. Lets the parser accept the syntax in impl headers (step 1's payoff) while preventing the LLVM verifier crash. The diagnostic disappears when step 2 lands. # Verification Once the fix is in: ```sh ./zig-out/bin/sx run examples/156-pack-fn-mono.sx # Expected: prints "42" ``` Full suite + zig test must still pass.