From 7d1e23ecc66cd6570110e9f78015f480ad14c2a0 Mon Sep 17 00:00:00 2001 From: agra Date: Fri, 12 Jun 2026 00:40:00 +0300 Subject: [PATCH] =?UTF-8?q?issues:=20file=200123=20=E2=80=94=20wrong=20arg?= =?UTF-8?q?=20counts=20to=20fixed-arity=20fns=20reach=20LLVM=20emission?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- issues/0123-call-arity-unchecked.md | 82 +++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 issues/0123-call-arity-unchecked.md diff --git a/issues/0123-call-arity-unchecked.md b/issues/0123-call-arity-unchecked.md new file mode 100644 index 0000000..4399fdb --- /dev/null +++ b/issues/0123-call-arity-unchecked.md @@ -0,0 +1,82 @@ +# 0123 — wrong arg counts to fixed-arity fns reach LLVM emission + +## Symptom + +Calling a fixed-arity function with the wrong number of arguments is +not rejected by the frontend — the mismatched argument list flows all +the way to LLVM emission, which fails verification instead of a +source-located diagnostic. + +- **Observed**: `LLVM verification failed: Incorrect number of + arguments passed to called function!` plus the raw IR call line — + no file/line/snippet, no callee name in user terms. +- **Expected**: a compile error at the call site naming the callee + and its declared arity (matching the style of existing + diagnostics, e.g. the "unresolved ..." errors with source + snippets). + +Both directions are broken, on every plain dispatch path probed: + +- too MANY args, bare call: `concat("a", "b", "c")` (std's `concat` + takes 2 strings) → LLVM verifier failure. +- too FEW args, bare call: `add2(1)` with `add2 :: (a: s64, b: s64)` + → same. +- methods / ufcs dot-calls: same shape, receiver included. Worse: + a trailing-default param on a plain struct method or a ufcs fn is + never filled on the dot-call path (`p.scaled()` with + `scaled :: (self: Point, k: s64 = 2)` emits a 1-arg call to a + 2-param fn — bare calls fill defaults via `expandCallDefaults`, + the method/ufcs sites never run `appendDefaultArgs`). + +Legitimate flexible shapes must keep working: slice variadics +(`..xs: []T` — no upper bound), comptime/protocol packs (`..$args` / +`..xs: P` — own dispatch), default-valued params (incl. +`loc: Source_Location = #caller_location`), generic `$T` fns +(explicit vs inferred type args make the count flexible), `#foreign` +C variadics, `#compiler` / `#builtin` bodies. + +## Reproduction + +```sx +#import "modules/std.sx"; + +main :: () -> s32 { + s := concat("a", "b", "c"); // concat takes (a: string, b: string) + out(s); + return 0; +} +``` + +Observed at master b3b78e2: compiles past resolution, dies at LLVM +verification with the verifier message above. + +## Investigation prompt + +Call argument binding never compares the supplied arg count against +the callee's declared parameter list. Suspected area: the plain +direct-dispatch sites in `src/ir/lower/call.zig` (`lowerCall`) — the +bare-identifier selected-author and lazy-lower legs, the +namespace-qualified legs, the qualified struct-method leg, and the +ufcs leg. All of them run `packVariadicCallArgs` / +`coerceCallArgs` and emit `builder.call` without an arity check; +`coerceCallArgs` iterates `@min(args.len, params.len)` so a mismatch +sails through to the emitter. + +The fix likely needs a shared `checkCallArity(fd, name, supplied, +has_receiver, span)` helper consulted at each plain dispatch site, +computing min (params without trailing defaults) / max +(`fd.params.len`, unbounded when a variadic param exists) from the +AST decl and emitting via `self.diagnostics.addFmt(.err, span, ...)` +on violation. Pack (`isPackFn`), comptime (`hasComptimeParams`), +generic (`type_params.len > 0`), `#compiler`, and `#builtin` callees +bind args through their own dispatch and must be exempt. The +method/ufcs sites also need `appendDefaultArgs` (the generic +instance-method leg already runs it) so trailing defaults fill +before the count is meaningful. + +Verification: the repro errors with a source-located diagnostic +naming `concat` and its 2-arg signature; too-few errors likewise; +variadic / pack / default / ufcs / generic calls keep compiling +(`print`, `format`, `List.append`, `#caller_location` defaults). +`zig build && zig build test`, `bash tests/run_examples.sh` all +green; pin the repro as a diagnostics example per CLAUDE.md.