← board

bug: overload resolution binds a string arg to an earlier integer-param overload

Resolution (2026-06-23)

Front-end only (overload ranking), no codegen. Root cause: a single-char string literal ('x') types as tyChar, and TypesCompatible(tyInteger, tyChar) is true (both ordinal), so in the general compatible phase the first-declared f(integer) overload matched a char arg and won. ('hello' types as tyString, not ordinal-compatible with integer, so it already resolved correctly — hence the asymmetry.)

Fix: new ranking phase 1c in MatchProcCall (symtab.inc), after the exact phases and before the general compatible phase: a tyChar argument matches a tyString/tyAnsiString parameter (every other arg must be an exact type match). So f('x') binds to f(string) regardless of declaration order, while a genuine f(char) overload still wins via the earlier exact phase, and a sole f(integer) keeps its existing char->integer behavior (phase 2 unchanged).

Verified f(1),f('x'),f('hello') = INT|STR|STR both declaration orders, and h(integer)/h(char) picks the char overload — byte-identical to FPC. Gate: make test (self-host byte-identical — resolution only) + FPC oracle. Closes bug-overload-resolution-by-type.

Symptom

With two same-arity overloads of different parameter type, a string argument selects the integer-parameter overload when it is declared first, instead of the matching string one:

function f(a: integer): string; begin f := 'INT'; end;
function f(a: string):  string; begin f := 'STR'; end;
begin writeln(f(1), '|', f('x')); end.
{ fpc: INT|STR    pxx: INT|INT   <- f('x') wrongly calls f(integer) }

What works / the asymmetry

function f(a: string):  string; begin f := 'STR'; end;
function f(a: integer): string; begin f := 'INT'; end;
begin writeln(f(1), '|', f('x')); end.   { pxx: INT|STR  (correct here) }

So an earlier integer-param overload is wrongly treated as a viable match for a string argument during ranking (first viable wins), even though that same conversion is rejected when the integer overload stands alone.

Expected

Overload resolution selects by argument type independent of declaration order: a string argument must bind to the string-param overload (FPC: INT|STR).

Repro

tools/fpc_diff_probe.sh (overload-by-type).