ffi M5.A.next.1c.B: pack type rep — Closure(..$args) parses + interns

`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)`.

No semantic effect yet — the signature exists in the type table
but no matching code reads `pack_start`. Step 1d wires impl
matching: `Closure(..$args) -> $R` binds against any concrete
closure source type in `tryUserConversion` / `registerParamImpl`.

`examples/154-pack-type-rep.sx` flips from rejecting-with-error
to positive parse smoke (prints "pack type rep ok").

192/192 example tests + `zig build test` green.
This commit is contained in:
agra
2026-05-27 12:12:16 +03:00
parent bb6eca6b91
commit 65824494a7
6 changed files with 58 additions and 2 deletions

View File

@@ -492,6 +492,10 @@ pub const ClosureTypeExpr = struct {
param_types: []const *Node,
param_names: ?[]const ?[]const u8 = null, // optional documentation names
return_type: ?*Node, // null = void return
/// Variadic heterogeneous type pack trailing the param list.
/// `Closure(..$args) -> R` ⇒ pack_name = "args", param_types = [].
/// `Closure(Prefix, ..$args)` ⇒ pack_name = "args", param_types = [Prefix].
pack_name: ?[]const u8 = null,
};
pub const TupleTypeExpr = struct {