← board

Measured 2026-09-06, compiler 66e848666e3c

IFoo = interface function M(a: LongInt): LongInt; end;
TFoo = class(TInterfacedObject, IFoo)
  function M: LongInt;        { no parameter — fpc: "No matching implementation" }
end;
var f: IFoo;  f := TFoo.Create;  writeln(f.M(1));

pxx compiles it and prints 7 — the 0-argument body reached through a 1-argument slot. The extra argument is simply left in place; on this target it happens not to disturb anything, which is what makes it silent rather than a crash. The sibling defect bug-p-a-write-call-inside-a-method-named-write-binds-to-the-member-whatever-its-arity records the other end of the same hazard: i386, arm32 and aarch64 do refuse a call-argument-count mismatch, x86-64 has no such guard. So the same source is plausibly a hard error on three targets and a wrong answer on the one everybody measures on.

Why it survived

FindUMethForSig's fallback is not an oversight — it is argued for, so that "a class whose implementation differs only cosmetically binds exactly as it did before". The argument is fine; what fails is the referral. It says the refusal belongs to the IMT builder, and the IMT builder's only refusal is

if mmi < 0 then Error('class does not implement interface method: ' + imName);

which cannot fire, because the fallback guarantees mmi >= 0 whenever any method of the name exists. The check is unreachable exactly when it is needed — the fallback that defers to it is also what disarms it.

Shape of a fix

Have FindUMethForSig report whether it matched a SIGNATURE or fell back to a name, and let the IMT builder refuse the fallback case (that is the site the existing comment already nominates). Do not add the check on the method-resolution-clause path alone: a clause is sugar for the same binding, so a check there would make function IFoo.M = Impl; stricter than the plain same-named M it desugars to, which is a second inconsistency rather than a fix.

Worth checking in the same pass whether the cosmetic-difference cases the fallback was written for are still reachable once arity is required — the comment's example is a differing type spelling, not a differing arity, and requiring equal arity may cost nothing it was protecting.

Log