ffi M5.A.next: checkpoint — pack feature step 1 done (1c.A → 1d.B)
Logs the four commits that closed out step 1 of the variadic heterogeneous type packs feature: - 1c.A: parser-rejection lock-in for `..$args` inside `Closure(...)`. - 1c.B: parser + AST + types.zig `pack_start` representation. - 1d.A: impl-matching concrete-only miss lock-in. - 1d.B: pack-aware impl matching with $args + $R binding through `param_impl_pack_map` and `pack_bindings`. Next step is plan step 2 — runtime `args[$i]` indexing + per-mono mangling — opening the door to body-side pack reflection that step 5 needs to retire the hand-rolled `Into(Block)` impls. Also catches up the 1b entry which the prior session left uncommitted in the working tree.
This commit is contained in:
@@ -6,8 +6,148 @@ add a test and make it pass — that's two commits).
|
||||
|
||||
## Last completed step
|
||||
|
||||
**M5.A.next.1d.B — variadic heterogeneous type packs: pack-aware impl
|
||||
matching** (commit `08feb60`).
|
||||
|
||||
Pack-shaped impls (`impl P(...) for Closure(..$args) -> $R`) now
|
||||
match concrete closure sources at xx resolution time. Concrete
|
||||
impls retain priority — pack matching only fires when
|
||||
`param_impl_map` misses on the concrete key.
|
||||
|
||||
New plumbing in [src/ir/lower.zig](../src/ir/lower.zig):
|
||||
|
||||
- `PackParamImplEntry` carries the pack-shaped source TypeId plus
|
||||
the pack-var and ret-var names extracted from the impl AST's
|
||||
`target_type_expr`. `registerParamImpl` detects pack-shaped
|
||||
sources via `pack_start != null` on the resolved closure type
|
||||
and additionally registers in a new `param_impl_pack_map`
|
||||
keyed by `"Proto\x00<arg_mangled>"` (no source suffix).
|
||||
- `tryUserConversion` re-shapes the lookup so the pack path runs
|
||||
on miss. `tryPackImplMatch` walks the pack entries, verifies
|
||||
the source's fixed prefix matches the impl's prefix, binds
|
||||
the pack-var to the source's tail param TypeIds, binds the
|
||||
ret-var (when the impl's return is generic) to the source
|
||||
return, and monomorphises the convert method. Mangled name
|
||||
stays keyed on the concrete source so distinct call shapes
|
||||
monomorphise separately.
|
||||
- `pack_bindings: ?StringHashMap([]const TypeId)` is saved /
|
||||
restored around monomorphisation, mirroring `type_bindings`.
|
||||
- `resolveClosureTypeWithBindings` handles the `closure_type_expr`
|
||||
node during type resolution: when the closure carries a
|
||||
`pack_name` AND `pack_bindings` has a binding for it, the
|
||||
bound TypeIds are appended after the fixed prefix and the
|
||||
result is a concrete (non-pack) closure type — so the impl
|
||||
body's `self: Closure(..$args) -> $R` substitutes to the
|
||||
concrete source closure during monomorphisation.
|
||||
|
||||
`examples/155-pack-impl-match.sx` flips from the
|
||||
"no Into(Block) for cl_s32_bool__bool" lock-in diagnostic to
|
||||
"pack impl match ok": one user-declared
|
||||
`impl Into(Block) for Closure(..$args) -> $R` covers a
|
||||
`Closure(s32, bool) -> bool` source that stdlib has no
|
||||
hand-rolled impl for. The constructed Block isn't invoked
|
||||
(invoke=null) — the test exercises matching + monomorphisation,
|
||||
not the trampoline (step 5 of the plan).
|
||||
|
||||
Same-file duplicate pack impls diagnose at registration;
|
||||
cross-module pack-impl visibility and multi-pack-impl
|
||||
specificity are deferred (matching the concrete path's existing
|
||||
TODOs).
|
||||
|
||||
193/193 example tests + `zig build test` green. Step 1 of the
|
||||
pack-feature plan ("Parser + type rep + impl matching") is now
|
||||
done.
|
||||
|
||||
**Next step** — Step 2 of the plan: runtime indexing
|
||||
(`args[$i]`) lowers to positional access; per-mono mangling
|
||||
extends with a stable pack-shape hash. Builder fns receive
|
||||
`$args` (a comptime `[]Type`) as a regular value parameter.
|
||||
Replaces a hand-rolled Into impl in stdlib once step 2 + step
|
||||
3 (type-reflection intrinsics) land.
|
||||
|
||||
---
|
||||
|
||||
**M5.A.next.1d.A — pack impl matching: lock in concrete-only miss**
|
||||
(commit `ce3c2fe`).
|
||||
|
||||
Pinned today's matching behaviour ahead of 1d.B. A user-declared
|
||||
`impl Into(Block) for Closure(..$args) -> $R` registers under a
|
||||
pack-shaped source key in `param_impl_map`; the xx site mangles
|
||||
the concrete `Closure(s32, bool) -> bool` source and finds
|
||||
nothing → the existing focused diagnostic fires ("no `Into(Block)
|
||||
for cl_s32_bool__bool` impl — add a per-signature
|
||||
`__block_invoke_<sig>` trampoline + Into impl..."). The pack impl
|
||||
is reachable in the file but never considered.
|
||||
|
||||
`examples/155-pack-impl-match.sx` captures the rejection at line
|
||||
43 column 21 (the `xx cl : *Block` site). 193/193 example tests
|
||||
+ `zig build test` green.
|
||||
|
||||
---
|
||||
|
||||
**M5.A.next.1c.B — pack type rep: Closure(..$args) parses + interns**
|
||||
(commit `6582449`).
|
||||
|
||||
`parseTypeExpr`'s `Closure(...)` arm now accepts a trailing
|
||||
`..$name` (sigil optional) as a variadic-pack marker. Pack must
|
||||
be terminal — `)` is the only token accepted after the name.
|
||||
`ClosureTypeExpr` AST gains `pack_name: ?[]const u8` carrying
|
||||
the identifier so later slices can name the binding.
|
||||
|
||||
`FunctionInfo` / `ClosureInfo` in `src/ir/types.zig` grow a
|
||||
`pack_start: ?u32 = null` field. `Closure(..$args) -> R` interns
|
||||
as `params = []`, `pack_start = Some(0)` — distinct from any
|
||||
concrete `Closure(...) -> R` shape thanks to updated hash/eql
|
||||
arms. New constructor pair `closureTypePack` /
|
||||
`functionTypePack` keeps the existing single-shape constructors
|
||||
unchanged.
|
||||
|
||||
`type_bridge.resolveClosureType` calls `closureTypePack` when
|
||||
`pack_name != null`. The pack starts after the fixed prefix,
|
||||
so `Closure(Prefix, ..$args)` resolves with `params = [Prefix]`,
|
||||
`pack_start = Some(1)`.
|
||||
|
||||
`examples/154-pack-type-rep.sx` flips from rejecting-with-error
|
||||
to positive parse smoke. 192/192 example tests + `zig build
|
||||
test` green.
|
||||
|
||||
---
|
||||
|
||||
**M5.A.next.1c.A — pack type rep: lock in parser rejection**
|
||||
(commit `bb6eca6`).
|
||||
|
||||
Locked in today's `parseTypeExpr` Closure-arm rejection of `..$args`.
|
||||
`examples/154-pack-type-rep.sx` uses `..$args` inside a
|
||||
`Closure(...)` type expression — the pack-shape spelling used by
|
||||
impl headers like `impl Into(Block) for Closure(..$args) -> $R`.
|
||||
Today's parser recognized `..$args` only at parameter-list sites
|
||||
(1b); the Closure type arm called `parseTypeExpr` per position
|
||||
and hit "expected type name" at line 18 column 26.
|
||||
|
||||
---
|
||||
|
||||
**M5.A.next.1b — variadic heterogeneous type packs: parser accepts
|
||||
`..$args`** (commit `a51fe26`).
|
||||
|
||||
`parseParams()` in `src/parser.zig:1558` accepts a leading `..`
|
||||
before the optional `$` sigil and the parameter name. The old
|
||||
`args: ..T` form (variadic marker after the colon) still works —
|
||||
both paths set the same `is_variadic` flag. A pack declaration
|
||||
`..$args` parses as:
|
||||
- `is_variadic = true` (leading `..`)
|
||||
- `is_comptime = true` (the `$` sigil)
|
||||
- `type_expr = inferred_type` (no `:` annotation)
|
||||
|
||||
`examples/150-pack-parse.sx` flipped from rejecting-with-error to
|
||||
positive parse smoke. The no-colon branch of `parseParams`
|
||||
propagates `is_variadic` and `is_comptime` onto the Param
|
||||
struct, so later slices can read both flags from the parsed AST.
|
||||
191/191 example tests + `zig build test` green.
|
||||
|
||||
---
|
||||
|
||||
**M5.A.next.1a — variadic heterogeneous type packs: parse lockin**
|
||||
(this commit).
|
||||
(`ad82847`).
|
||||
|
||||
First slice of the `..$args` (variadic heterogeneous type pack)
|
||||
feature per the plan saved at
|
||||
|
||||
Reference in New Issue
Block a user