fix(lower): resolved author drives variadic packing in bare call [0102c F1]
Attempt-2 fix for the F1 review finding. After `resolveBareCallee` picks a shadowed same-name author's FuncId at a normal call site, the call path still re-fetched the FIRST-WINS function AST by name to drive variadic argument packing. When the resolved (shadow) author's variadic shape differs from the first-wins author's, arguments were packed against the WRONG signature — a fixed-arity shadow packed as if variadic, or a variadic shadow not packed at all — producing IR with the wrong argument count (LLVM verification failure). The `.func` arm now carries the resolved `*FnDecl` alongside its FuncId (`BareCallee.func: ResolvedAuthor`), so `packVariadicCallArgs` reads THE resolved author's signature. The rest of the arm already used the resolved FuncId's IR function (ret/params/ctx/coercion), so the callee now has one source of truth in the whole call lowering — no re-fetch by name after resolution. Default-arg / closure / UFCS / comptime *sites* remain first-wins (fix-0102d); `expandCallDefaults` runs before resolution and is a default site. Regression: examples/0726-modules-flat-same-name-variadic — two flat file imports each author `combine` and `pick` with OPPOSITE variadic shapes (a.sx fixed `combine` / variadic `pick`; b.sx variadic `combine` / fixed `pick`). Each module's bare call must pack against ITS OWN author. Fails on the pre-fix re-lookup (LLVM "Incorrect number of arguments passed to called function" for both `combine.1` and `pick.2`); passes after. Gate: zig build, zig build test (400/400), bash tests/run_examples.sh (463 passed) all green. Matrix 0722-0725/0727 unchanged; single-author / local resolution byte-for-byte unchanged (the `.func` arm never runs for them).
This commit is contained in:
@@ -1438,7 +1438,7 @@ test "lower: shadowed same-name author gets its own FuncId + real body (fix-0102
|
||||
try std.testing.expect(lowering.resolveBareCallee("greet", main_path) == .ambiguous);
|
||||
try std.testing.expect(lowering.resolveBareCallee("greet", a_path) == .none);
|
||||
switch (lowering.resolveBareCallee("greet", b_path)) {
|
||||
.func => |fid| try std.testing.expectEqual(shadow_fid.?, fid),
|
||||
.func => |resolved| try std.testing.expectEqual(shadow_fid.?, resolved.fid),
|
||||
else => return error.TestUnexpectedResult,
|
||||
}
|
||||
// A name no module authors (and no flat import provides) never routes.
|
||||
|
||||
@@ -1521,9 +1521,12 @@ pub const Lowering = struct {
|
||||
|
||||
/// Result of bare-call disambiguation (fix-0102c).
|
||||
pub const BareCallee = union(enum) {
|
||||
/// Bind the call to this specific author's FuncId — the identity-
|
||||
/// addressable body lowered by `bareAuthorFuncId` (fix-0102b).
|
||||
func: FuncId,
|
||||
/// Bind the call to this specific author — its identity-addressable
|
||||
/// FuncId (fix-0102b's `bareAuthorFuncId`) AND its `*FnDecl`. The decl
|
||||
/// travels with the FuncId so every callee-signature decision in the
|
||||
/// call path (variadic packing, …) reads the RESOLVED author, never a
|
||||
/// first-wins re-lookup by name (fix-0102c F1).
|
||||
func: ResolvedAuthor,
|
||||
/// ≥2 distinct flat authors are reachable from the caller and none is
|
||||
/// the caller's own — the bare call can't pick one; require a qualifier.
|
||||
ambiguous,
|
||||
@@ -1532,6 +1535,11 @@ pub const Lowering = struct {
|
||||
none,
|
||||
};
|
||||
|
||||
/// A resolved bare-call author: its FuncId and the `*FnDecl` that defined
|
||||
/// it, kept together so the call path has ONE source of truth for the
|
||||
/// callee (no re-fetch by name after resolution).
|
||||
pub const ResolvedAuthor = struct { fid: FuncId, decl: *const ast.FnDecl };
|
||||
|
||||
/// THE bare-name call resolver (fix-0102c). One canonical traversal over
|
||||
/// fix-0102a's `module_fns` + `flat_import_graph` that routes a bare
|
||||
/// identifier call `name` from `caller_file` to the right same-name author
|
||||
@@ -1561,7 +1569,7 @@ pub const Lowering = struct {
|
||||
if (own_fns.get(name)) |own| {
|
||||
if (winner != null and winner.? == own) return .none;
|
||||
if (!isPlainFreeFn(own)) return .none;
|
||||
return .{ .func = self.bareAuthorFuncId(own, name, caller_file) };
|
||||
return .{ .func = .{ .fid = self.bareAuthorFuncId(own, name, caller_file), .decl = own } };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1584,7 +1592,7 @@ pub const Lowering = struct {
|
||||
const the_path = entry.value_ptr.*;
|
||||
if (winner != null and winner.? == the_one) return .none;
|
||||
if (!isPlainFreeFn(the_one)) return .none;
|
||||
return .{ .func = self.bareAuthorFuncId(the_one, name, the_path) };
|
||||
return .{ .func = .{ .fid = self.bareAuthorFuncId(the_one, name, the_path), .decl = the_one } };
|
||||
}
|
||||
|
||||
/// The FuncId for a resolved bare-call author, ensuring its body is lowered.
|
||||
@@ -7560,13 +7568,15 @@ pub const Lowering = struct {
|
||||
d.addFmt(.err, c.callee.span, "'{s}' is ambiguous; declared by multiple imported modules — qualify the call", .{func_name});
|
||||
return Ref.none;
|
||||
},
|
||||
.func => |fid| {
|
||||
.func => |resolved| {
|
||||
const fid = resolved.fid;
|
||||
const func = &self.module.functions.items[@intFromEnum(fid)];
|
||||
const ret_ty = func.ret;
|
||||
const params = func.params;
|
||||
if (self.program_index.fn_ast_map.get(func_name)) |fd| {
|
||||
self.packVariadicCallArgs(fd, c, &args);
|
||||
}
|
||||
// The RESOLVED author's decl drives variadic
|
||||
// packing — not a first-wins re-lookup by name,
|
||||
// whose variadic shape may differ (fix-0102c F1).
|
||||
self.packVariadicCallArgs(resolved.decl, c, &args);
|
||||
const final_args = self.prependCtxIfNeeded(func, args.items);
|
||||
self.coerceCallArgs(final_args, params);
|
||||
if (func.is_variadic) self.promoteCVariadicArgs(final_args, params.len);
|
||||
|
||||
Reference in New Issue
Block a user