From e395a08331c3ebd88402b4a9095b8016f74f570d Mon Sep 17 00:00:00 2001 From: agra Date: Sat, 30 May 2026 03:06:03 +0300 Subject: [PATCH] lang F1 6: pack-spread in parameterized-type args (Combined($R, ..sources.T)) Parser now accepts a `..` spread in a parameterized-type arg list; in instantiateGenericStruct a spread arg bound to the variadic type-param expands via packTypeElems (so `..sources.T` projects each source pack element protocol type-arg into ..$Ts). `Combined(s64, ..sources.T)` for a VL(s64) source instantiates Combined(s64, s64). examples/209 (with explicit per-element xx erase). 244 examples + unit green. Next: (..sources) whole-pack materialization with per-element erasure into the protocol-typed field (c.sources = (..sources) currently segfaults). --- examples/209-pack-type-arg-spread.sx | 27 ++++++++++++++++++++ src/ir/lower.zig | 13 ++++++++++ src/parser.zig | 6 +++++ tests/expected/209-pack-type-arg-spread.exit | 1 + tests/expected/209-pack-type-arg-spread.txt | 1 + 5 files changed, 48 insertions(+) create mode 100644 examples/209-pack-type-arg-spread.sx create mode 100644 tests/expected/209-pack-type-arg-spread.exit create mode 100644 tests/expected/209-pack-type-arg-spread.txt diff --git a/examples/209-pack-type-arg-spread.sx b/examples/209-pack-type-arg-spread.sx new file mode 100644 index 0000000..4e5e9bc --- /dev/null +++ b/examples/209-pack-type-arg-spread.sx @@ -0,0 +1,27 @@ +// Phase 6 — pack-spread in a parameterized-type's arg list: +// `Combined($R, ..sources.T)`. Inside a pack-fn, `..sources.T` projects each +// source's protocol type-arg and spreads them into the generic struct's pack +// type-param `..$Ts`, so `Combined(s64, ..sources.T)` for a single `VL(s64)` +// source instantiates `Combined(s64, s64)` (field `sources: (VL(s64))`). + +#import "modules/std.sx"; + +VL :: protocol(T: Type) { get :: () -> T; } +IntCell :: struct { v: s64; } +impl VL(s64) for IntCell { get :: (self: *IntCell) -> s64 => self.v; } + +Combined :: struct($R: Type, ..$Ts: []Type) { + sources: (..VL(Ts)); + value: $R; +} + +make :: (..sources: VL) -> s64 { + c : Combined(s64, ..sources.T) = ---; // instantiate with the spread type-arg + c.sources.0 = xx sources[0]; // erase the concrete source to VL(s64) + return c.sources.0.get(); +} + +main :: () -> s32 { + print("{}\n", make(IntCell.{ v = 7 })); // 7 + 0; +} diff --git a/src/ir/lower.zig b/src/ir/lower.zig index 0759c0e..2e46b0a 100644 --- a/src/ir/lower.zig +++ b/src/ir/lower.zig @@ -11495,6 +11495,19 @@ pub const Lowering = struct { if (tp.is_variadic) { var pack_tys = std.ArrayList(TypeId).empty; for (args[i..]) |a| { + // A spread arg `..sources.T` expands to the source pack's + // per-element (projected) types; a plain arg is one type. + if (a.data == .spread_expr) { + if (self.packTypeElems(a.data.spread_expr.operand)) |elems| { + defer self.alloc.free(elems); + for (elems) |ty| { + pack_tys.append(self.alloc, ty) catch {}; + name_parts.appendSlice(self.alloc, "__") catch {}; + name_parts.appendSlice(self.alloc, self.formatTypeName(ty)) catch {}; + } + continue; + } + } const ty = self.resolveTypeWithBindings(a); pack_tys.append(self.alloc, ty) catch {}; name_parts.appendSlice(self.alloc, "__") catch {}; diff --git a/src/parser.zig b/src/parser.zig index bb68541..e094cb7 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -688,6 +688,12 @@ pub const Parser = struct { }; self.advance(); try args.append(self.allocator, try self.createNode(arg_start, .{ .int_literal = .{ .value = value } })); + } else if (self.current.tag == .dot_dot) { + // Pack-spread type arg: `Combined($R, ..sources.T)`. + const sp_start = self.current.loc.start; + self.advance(); // skip '..' + const operand = try self.parseTypeExpr(); + try args.append(self.allocator, try self.createNode(sp_start, .{ .spread_expr = .{ .operand = operand } })); } else { try args.append(self.allocator, try self.parseTypeExpr()); } diff --git a/tests/expected/209-pack-type-arg-spread.exit b/tests/expected/209-pack-type-arg-spread.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/expected/209-pack-type-arg-spread.exit @@ -0,0 +1 @@ +0 diff --git a/tests/expected/209-pack-type-arg-spread.txt b/tests/expected/209-pack-type-arg-spread.txt new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/tests/expected/209-pack-type-arg-spread.txt @@ -0,0 +1 @@ +7