A bare method call inside its own class ignores its arity
- Type: bug — Track P (
compiler/pasparser_stmt.inc, the implicit-Self call site; helper incompiler/pasparser_lval.inc). - Found inside the candidate-selection group, while measuring whether
[[bug-p-a-shadowed-soft-intrinsic-is-closed-without-consulting-the-arguments]]
still had a live instance. It does not — but a class with a method named
Deleteshadowing the intrinsic turned out to acceptDelete(a, 1, 1)and runDelete(Double)with 0.0. That has nothing to do with intrinsics.
The measurement
fpc 3.2.2 refuses every row; pre-fix pxx compiled all four clean.
| call | signature | pxx ran |
|---|---|---|
Plain(1.5, 2, 3) |
Plain(x: Double) |
x=0.0 — every argument lost |
Plain(1.5, 2) |
Plain(x: Double) |
x=0.0 |
Two(7, 8, 9) |
Two(a, b: Integer) |
a=8 b=9 — Self ate the 7 |
Two(7) |
Two(a, b: Integer) |
a=369098760 — uninitialised |
The last row is why this is not a diagnostics ticket. There is no crash and no message; the callee reads whatever the argument slot held.
Exactly one door of four
| spelling | pre-fix |
|---|---|
Self.Plain(1.5, 2, 3) |
refused |
c.Plain(1.5, 2, 3) |
refused |
Free1(1.5, 2, 3) (free routine) |
refused |
Plain(1.5, 2, 3) bare, inside the class |
accepted |
FindUMethOverloadAhead is a selector — asked which overload, having
already been told this is a method call — so with no arity-viable candidate it
answers with the first name match rather than declining.
FindUMethArityStrict exists precisely so a caller can decline, and its own
header says so; it had one caller, the Write-inside-a-write-member path.
This is the sibling site that was never given the strict question. Same shape
as [[bug-p-a-method-call-with-missing-arguments-is-accepted-and-reads-garbage]],
which fixed the QUALIFIED parenless spelling.
The carve-out is a measured dependency, not caution
Variadic bracket-elision (Desc('a', 1) against
Desc(const a: array of const), feature-writeln-as-library) passes more
explicit arguments than the signature has parameters, on purpose — and it
reaches this site through the very loose fallback being closed. fpc refuses
that source too ("Wrong number of parameters"), so an arity gate derived from
fpc's answer alone would have deleted a pxx extension with no test to notice.
Hence UMethNameCanAbsorbVarRecTail, asked of the NAME over the visible set
rather than of one candidate — the same shape and the same reason as
ParamIsVarRecArray beside it.
Not fixed here, and deliberately
The elided spelling of that extension segfaults at this door while the bracketed one works. Separate defect, separate ticket: [[bug-p-a-bare-variadic-method-call-segfaults-where-the-bracketed-spelling-works]]. Converting a segfault into a diagnostic as a side effect of an arity fix would have hidden it.
Verification
test_p_a_bare_method_call_ignores_arity_fail.pas— four diagnostics, rc=1, no binary.test_p_a_bare_method_call_arity_still_valid.pas— exact arity, trailing defaults, a parameterless method, two overloads, an inherited method and the bracketedarray of const. Byte-identical against the PINNED pre-fix compiler, so the check refuses nothing that was legal.gate.sh quickGREEN, self-host fixedpoint converged.