← board

bug: an overloaded method's IMPLEMENTATION does not always match back to its DECLARATION

What

When a method body is parsed, the binder tries FindUMethByProc(ci, procIdx) — i.e. "which method-table entry was this exact proc registered under at declaration time?". For some overloads that lookup MISSES, meaning the implementation header created a proc that is not the one the declaration registered for that signature.

Before b315 the code then fell back to a NAME match (the first entry of that name) and OVERWROTE its proc — clobbering a different overload. That is what broke TJSONArray.Insert(0): ten two-arg Insert bodies each landed on the one-arg entry.

b315 makes the fallback refuse to bind across a different arity, so nothing is destroyed. But the underlying mismatch remains, and it still costs:

Where to look

compiler/parser.inc, the method-body header path (~line 19700, mmi := FindUMethByProc(...)) and whatever resolves an implementation header procedure TFoo.Bar(...) to its declared proc. The question to answer first: for fpjson's Insert overloads, WHICH ones miss, and why — a parameter type that compares unequal between decl and impl is the obvious suspect (fpjson's set includes UnicodeString next to String, QWord, Int64, NativeInt and TJSONFloat, so an alias that resolves to the same TTypeKind in one place and not the other would do it). Dump the decl-time and impl-time param TypeKinds for each overload and diff them; do not theorise.

Guard

test/test_method_overload_arity_rebind_b315.pas covers the arity case. A same-arity case (two overloads differing only in parameter TYPE, implemented out of order) would pin this one — worth writing as the first step.

RESOLVED 2026-07-13 (b321, commit b2b672b7)

Root cause found via fpjson's suite: the class-method DECL registration was rec-blind (FindProcOverload, no ProcParamRecId stored), so two same-arity overloads whose params differ only in CLASS IDENTITY shared one proc slot and each impl body clobbered the other's — Add(TJSONData(x)) inside Add(AnObject: TJSONObject) re-dispatched to ITSELF (stack overflow). Decl registration now uses FindProcOverloadRec + stores ProcParamRecId; the overload RANKING also became class-aware (exact class 0, ancestor up-cast 2, unrelated impossible). Pinned: test/test_overload_class_identity_b321.pas.

Log