← board

Method default parameters land on the WRONG slot (silent wrong values)

Symptom

A method implementation that repeats its declared defaults had every default written to the previous parameter's slot:

type TB = class procedure M(a: Integer = 1; b: Integer = 2); end;
procedure TB.M(a: Integer = 1; b: Integer = 2);
begin writeln('a=', a, ' b=', b); end;
...
o.M;        { printed a=2 b=2 — must be a=1 b=2 }

No error, no warning — just wrong values. Reproduced on the shipping pinned binary, so this was live, not a regression from the work that found it.

Root cause

ParseSubroutine injects the implicit Self at param 0 for a method impl and shifts the staging arrays up by one — pnames, ptypes, ptypesRec, ptypesPtrElemTk/Rec, ptypesProcSig, parr, pbyref, pNDims, pDynDepth, pDimLo/Span — but not pdefault / pdefaultval. Those stayed at the declared (unshifted) indices, so committing them wrote each default one slot low.

It stayed latent because the class declaration already registered the correct (shifted) defaults; the impl pass then overwrote them with the misaligned copy. A same-typed neighbour therefore just silently took the wrong constant.

Fix

Shift the default arrays with the rest of the params, and zero slot 0 (Self). The same commit adds string-literal defaults, whose new pdefaultisstr/soff/slen arrays shift alongside — the mismatch is what surfaced the bug: a string default misaligned onto an ordinal slot segfaulted instead of merely lying.

Regression

test/test_method_default_param_b246.pas (in make test): covers ordinal defaults, a defaulted call, a partially-defaulted call, and a string default that is not the last parameter.

Gate

make test green + self-host byte-identical. Both held.

Log