← board

An Integer argument binds the fixed-ARRAY overload, not the Integer one

{$mode objfpc}
type TArr = array[0..2] of Integer;
function Sum(const a: TArr): Integer; overload; begin Sum := a[0]+a[1]+a[2]; end;
function Sum(x: Integer): Integer;    overload; begin Sum := x*10; end;
begin WriteLn(Sum(7)); end.

FPC prints 70. pxx refuses:

error: by-reference argument must be a variable

The diagnostic names the by-ref check, which is the SYMPTOM: overload resolution has already bound Sum(7) to the ARRAY overload, and the by-ref check then correctly observes that an integer literal is not an lvalue. The bug is one step earlier.

Likely mechanism (not yet confirmed — measure before believing it)

Procs[].Params[i].TypeKind for a fixed-array parameter carries the ELEMENT kind (the same conflation that made function F: TArr look like an Integer result — bug-a-set-and-array-function-results-come-back-empty), so to the matcher const a: TArr and x: Integer present the SAME parameter type and the array one wins by declaration order. If so, the fix belongs in the single side channel into MatchProcCall* (see project_overload_resolution_single_side_channel_entry): the matcher needs Params[i].IsArray to disqualify a scalar argument, not a new argTypes value.

Check the sibling shapes in the same pass — a SET parameter and a frozen string[N] parameter are the other two whose Params[].TypeKind is not the whole story.

Gate

The program above printing 70, plus the array overload still selected for a real TArr argument and for a TArr-returning call result (test/test_aggregate_function_results.pas's arr as arg row); self-host byte-identical.

Resolution (2026-08-11)

Worse than the ticket recorded: only the LITERAL form is refused. Sum(n) with n: Integer compiles and segfaults — an identifier satisfies the by-ref check, so the array overload is entered and reads three elements off a 4-byte variable.

Fixed in the matcher, via the existing per-argument side channel rather than through argTypes (which cannot carry it — a fixed array's element kind IS its argTypes entry): a new MatchArgScalar[j], filled beside MatchArgRec in MatchCallDelphiProcAddr, marks an argument whose scalar-ness is CERTAIN (an ordinal/float literal, an arithmetic expression, a non-array variable, or a scalar-returning call). MatchArgRecMismatch — already consulted by every match phase — disqualifies an array parameter for such an argument. array of const (tyRecord/tyVariant element) and untyped parameters are excluded, and anything whose shape is not certain stays unmarked and matches exactly as before.

Verified against fpc -O1: array variable, fixed-array-returning call, scalar variable, literal and float all pick what FPC picks; open-array and array of const overloads, SetLengthd dynamic arrays and Format unaffected. Family sweep of all 132 test/*.pas matching overload|array|param, HEAD vs pinned: no regression — the only three diffs are tests pinned cannot build.

New test/test_overload_array_vs_scalar.pas.

One divergence surfaced that this bug had been hiding — Sum(n + 1) binds a Double overload where FPC binds Integer. Pre-existing on pinned, filed as bug-a-an-integer-binop-argument-binds-a-double-overload.

Log