ffi checkpoint: step 5 done — generic Into(Block) impl + 3 unblocking bug fixes
This commit is contained in:
@@ -6,6 +6,82 @@ add a test and make it pass — that's two commits).
|
||||
|
||||
## Last completed step
|
||||
|
||||
**M5.A.next.5 — generic `Into(Block) for Closure(..$args) -> $R`**
|
||||
(commits `3bd6f26` → `2eaf932`, plus 3 unblocking compiler-bug
|
||||
fixes — issues 0048 / 0049 / 0050).
|
||||
|
||||
The visible end-user payoff for the whole variadic-heterogeneous-
|
||||
type-packs feature. One stdlib impl replaces every per-signature
|
||||
hand-rolled `Into(Block)` pair; the compiler monomorphises the
|
||||
impl body per call shape and emits a dedicated `__invoke`
|
||||
`callconv(.c)` trampoline + Block literal via a single `#insert
|
||||
build_block_convert($args, $R)`.
|
||||
|
||||
| Slice | Commit | What |
|
||||
|---|---|---|
|
||||
| 5.0 probe | (no commit) | Confirmed nested `() -> Ret callconv(.c) { body }` parses + `@inner` address-of binds + indirect call works. The trampoline emission pattern is unblocked at the language-surface level. |
|
||||
| issue-0048 xfail | `8fcf352` | Bare `$args` slice loses `.len` across a function-call boundary — pin via `examples/173-pack-bare-args-cross-call.sx`. |
|
||||
| issue-0048 fix | `0ede097` | `lazyLowerFunction` saves/nulls `pack_arg_nodes` / `pack_param_count` / `pack_arg_types` / `inline_return_target` before lowering the callee body. Without it, a lazily lowered regular fn called from inside a pack-fn mono inherited the outer pack maps and `lowerFieldAccess`'s `<pack_name>.len` intercept folded the callee's same-named param to the outer mono's arity. |
|
||||
| issue-0049 xfail | `64dcbca` | New-form variadic `..parts: []string` defined in stdlib + called from another module crashes LLVM emit (`LLVMBuildExtractValue` inside `emitStrCmp`). Pinned via the path_join migration. |
|
||||
| issue-0049 fix | `b5301c4` | `resolveParamType` + `packVariadicCallArgs` now detect when a variadic param's declared type is already a slice (`..name: []T`) and use it as the element-shape container rather than wrapping `[]T` to `[][]T`. |
|
||||
| variadic migration | `5b3d864` | Stdlib (`format` / `print` / `open`) and example fixtures (`19` / `20` / `50` / `120` / `ffi-foreign-cvariadic`) move to new `..name: []T` syntax. |
|
||||
| variadic cutover | `952dc0e` | Parser hard-rejects the legacy `name: ..T` form. `specs.md` documents `..name: []T` as the surface syntax. |
|
||||
| issue-0050 xfail | `ec2a99a` | Generic-mono path (`monomorphizeFunction`) leaks the outer pack-fn's `pack_arg_types` into the generic's body lowering — `args.len` constant-folds to the wrong arity per `examples/175-generic-fn-pack-state-leak.sx`. |
|
||||
| issue-0050 fix | `5316bf7` | Same isolation pattern as 0048 applied to `monomorphizeFunction`. |
|
||||
| 5.1.A xfail | `3bd6f26` | `build_block_convert(args: []Type, $ret: Type) -> string` undefined — pin output format via `examples/176-build-block-convert.sx` across 3 void shapes + 1 non-void shape. |
|
||||
| 5.1.B fix | `aeb950b` | Builder added to `library/modules/std/objc_block.sx`. Emits nested `callconv(.c)` trampoline + Block literal source. |
|
||||
| 5.2.A xfail | `f5342e9` | Generic `Into(Block)` impl absent — `Closure(s64, s64) -> void` (uncovered by hand-rolled impls) emits the "no Into(Block) for cl_s64_s64__void" diagnostic per `examples/177-generic-into-block.sx`. |
|
||||
| 5.2.B fix | `165b621` | Generic impl `Closure(..$args) -> $R` added with `#insert build_block_convert($args, $R)`. `lowerExpr`'s `.comptime_pack_ref` + `resolveTypeArg` + `type_bridge.isTypeShapedAstNode` extended so impl-mono `$args` (pack_bindings) and `$R` (type_bindings) resolve in both expr and type positions. |
|
||||
| 5.3 | `2eaf932` | Delete hand-rolled `__block_invoke_void` + `__block_invoke_bool` + the two per-shape impls. The generic impl covers both at runtime. |
|
||||
|
||||
What's now possible end-to-end (from
|
||||
`examples/177-generic-into-block.sx`):
|
||||
|
||||
```sx
|
||||
#import "modules/std/objc_block.sx";
|
||||
|
||||
main :: () -> s32 {
|
||||
cl := (a: s64, b: s64) => { g_a = a; g_b = b; };
|
||||
blk : Block = xx cl; // generic impl mono'd for
|
||||
// Closure(s64, s64) -> void
|
||||
invoke_fn : (*Block, s64, s64) -> void callconv(.c) = xx blk.invoke;
|
||||
invoke_fn(@blk, 10, 20);
|
||||
0;
|
||||
}
|
||||
```
|
||||
|
||||
The `xx cl : Block` site monomorphises the generic
|
||||
`Into(Block) for Closure(..$args) -> $R` impl. Inside the impl
|
||||
mono, `#insert build_block_convert($args, $R)` evaluates the
|
||||
builder at comptime with `$args = [s64, s64]` and `$R = void`,
|
||||
and substitutes the resulting source — a nested
|
||||
`__invoke :: (block_self: *Block, arg0: s64, arg1: s64) -> void
|
||||
callconv(.c) { ... }` trampoline plus the Block literal that
|
||||
points its `invoke` slot at `@__invoke`. Stack-local block layout
|
||||
matches Apple's published spec; UIKit / Foundation consumers can
|
||||
take this directly.
|
||||
|
||||
Adding a new closure shape to stdlib used to mean writing a
|
||||
per-signature `__block_invoke_<sig>` trampoline + a focused
|
||||
`Into(Block) for Closure(<sig>)` impl. Now: no stdlib edit
|
||||
needed. The generic impl emits per-call-shape on demand.
|
||||
|
||||
217/217 example tests + `zig build test` green.
|
||||
|
||||
Known follow-ups (out of scope for step 5):
|
||||
- `string`-typed arg in a generic block trampoline segfaults at
|
||||
runtime — the 16-byte `{ptr, len}` slice doesn't round-trip
|
||||
through the `callconv(.c)` ABI cleanly in the generated
|
||||
trampoline. Hand-rolled impls didn't hit this because they
|
||||
pre-dated string-arg shapes. Real closures of shape `Closure(
|
||||
string, ...) -> ...` are uncommon in Apple block APIs; revisit
|
||||
when a UIKit caller needs it.
|
||||
- Step 6 of the pack feature (rewriting `print` / `format` to
|
||||
use `..$args: []$T` for compile-time arity + type checking
|
||||
instead of `..args: []Any` runtime boxing).
|
||||
|
||||
---
|
||||
|
||||
**M5.A.next.4A.bare — bare `$args` + dynamic reflection intrinsics**
|
||||
(commits `c792642` → `2162662`, 5 slices in order).
|
||||
|
||||
@@ -852,19 +928,22 @@ plus 2 codegen fixes surfaced along the way.**
|
||||
|
||||
## Current state
|
||||
|
||||
- 213/213 example tests pass; `zig build test` green.
|
||||
- issue-0048 (bare `$args` slice loses `.len` across function-
|
||||
call boundary — root cause: `lazyLowerFunction` did not save/
|
||||
restore `pack_arg_nodes` / `pack_param_count` / `pack_arg_types`
|
||||
/ `inline_return_target`, so a lazily lowered callee inside a
|
||||
pack-fn mono inherited the outer pack maps and `lowerFieldAccess`'s
|
||||
`<pack_name>.len` intercept folded the callee's same-named param
|
||||
to the outer mono's arity). FIXED — defer-restore block added to
|
||||
`lazyLowerFunction`; regression locked in at
|
||||
`examples/173-pack-bare-args-cross-call.sx`.
|
||||
- Step 5.0 probe done — nested `() -> Ret callconv(.c) { body }`
|
||||
parses, `@inner` address-of binds to a fn-pointer, indirect call
|
||||
works. The trampoline emission pattern is unblocked.
|
||||
- 217/217 example tests pass; `zig build test` green.
|
||||
- **Step 5 of the variadic heterogeneous type packs feature done
|
||||
end-to-end.** Generic `Into(Block) for Closure(..$args) -> $R`
|
||||
impl in stdlib emits per-call-shape `__invoke` trampoline +
|
||||
Block literal via `#insert build_block_convert($args, $R)`.
|
||||
Hand-rolled `__block_invoke_void` / `__block_invoke_bool`
|
||||
deleted; `examples/95` / `96` route through the generic
|
||||
unchanged.
|
||||
- Three compiler-bug fixes landed alongside step 5 — issues
|
||||
0048 (`lazyLowerFunction` pack-state leak), 0049 (new-form
|
||||
variadic `..name: []T` cross-module emit crash), 0050
|
||||
(`monomorphizeFunction` pack-state leak). Each is captured by
|
||||
a focused regression test (`examples/173` / `174` / `175`).
|
||||
- Legacy variadic syntax `name: ..T` rejected at parse time;
|
||||
stdlib (`path_join` / `format` / `print` / `open`) and example
|
||||
fixtures migrated to `..name: []T`. `specs.md` updated.
|
||||
- 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
|
||||
|
||||
Reference in New Issue
Block a user