diff --git a/src/ir/lower.zig b/src/ir/lower.zig index e1abdc8..f48603b 100644 --- a/src/ir/lower.zig +++ b/src/ir/lower.zig @@ -8933,33 +8933,56 @@ pub const Lowering = struct { // value into the mangle (NOT a runtime IR param). // - pack param (always last) → consume the remaining call args // as the pack expansion. - var runtime_arg_types = std.ArrayList(TypeId).empty; - defer runtime_arg_types.deinit(self.alloc); var pack_arg_types = std.ArrayList(TypeId).empty; defer pack_arg_types.deinit(self.alloc); var pack_start: usize = call_node.args.len; // Constraint protocol of the pack param (`..xs: P`), if any. The // comptime type-pack `..$args` has no constraint to check. var pack_protocol: ?[]const u8 = null; - var fi: usize = 0; - for (fd.params) |p| { - if (isPackParam(p)) { - pack_start = fi; - if (p.is_pack and p.type_expr.data == .type_expr) { - pack_protocol = p.type_expr.data.type_expr.name; + var pack_is_comptime = false; + { + var fi: usize = 0; + for (fd.params) |p| { + if (isPackParam(p)) { + pack_start = fi; + pack_is_comptime = p.is_comptime; + if (p.is_pack and p.type_expr.data == .type_expr) { + pack_protocol = p.type_expr.data.type_expr.name; + } + break; } - break; + if (fi >= call_node.args.len) break; + fi += 1; } - if (fi >= call_node.args.len) break; - if (!p.is_comptime) { - runtime_arg_types.append(self.alloc, self.inferExprType(call_node.args[fi])) catch return self.builder.constInt(0, .void); - } - // Comptime non-pack: consumed but not added to runtime types. - fi += 1; } - if (pack_start <= call_node.args.len) { - for (call_node.args[pack_start..]) |a| { + + // Lower the runtime prefix args and the pack args up front, taking each + // pack type from the lowered value (`getRefType`) rather than a + // pre-lowering `inferExprType` guess: a lowered value always has a + // concrete type, so a monomorphised pack param can never end up + // `.unresolved` from incomplete static inference. (A comptime `..$args` + // pack still uses `inferExprType` — its args may be type-position.) + var args = std.ArrayList(Ref).empty; + defer args.deinit(self.alloc); + { + var ri: usize = 0; + for (fd.params) |p| { + if (isPackParam(p)) break; + if (ri >= call_node.args.len) break; + if (!p.is_comptime) { + args.append(self.alloc, self.lowerExpr(call_node.args[ri])) catch return self.builder.constInt(0, .void); + } + ri += 1; + } + } + for (call_node.args[pack_start..]) |a| { + if (pack_is_comptime) { + args.append(self.alloc, self.lowerExpr(a)) catch return self.builder.constInt(0, .void); pack_arg_types.append(self.alloc, self.inferExprType(a)) catch return self.builder.constInt(0, .void); + } else { + const r = self.lowerExpr(a); + args.append(self.alloc, r) catch return self.builder.constInt(0, .void); + pack_arg_types.append(self.alloc, self.builder.getRefType(r)) catch return self.builder.constInt(0, .void); } } @@ -9007,23 +9030,6 @@ pub const Lowering = struct { self.monomorphizePackFn(fd, mangled, pack_arg_types.items, call_node); } - // Lower ONLY runtime args (skip comptime non-pack args; their - // values are folded into the mangle, not passed at runtime). - var args = std.ArrayList(Ref).empty; - defer args.deinit(self.alloc); - var ri: usize = 0; - for (fd.params) |p| { - if (isPackParam(p)) break; - if (ri >= call_node.args.len) break; - if (!p.is_comptime) { - args.append(self.alloc, self.lowerExpr(call_node.args[ri])) catch return self.builder.constInt(0, .void); - } - ri += 1; - } - for (call_node.args[pack_start..]) |a| { - args.append(self.alloc, self.lowerExpr(a)) catch return self.builder.constInt(0, .void); - } - const fid = self.resolveFuncByName(mangled) orelse return self.builder.constInt(0, .void); const func = &self.module.functions.items[@intFromEnum(fid)]; const ret_ty = func.ret;