fix(lang-kotlin): overload target-id selection by parameter types (#1761) (#1777)

Same-arity Kotlin class-method overloads collapsed onto whichever node
was registered first. `lookup("alice")` resolved to `lookup(Int)` —
not because the picker chose wrong, but because `resolveDefGraphId`
fell through to the simple-name fallback after its parameter-typed key
lookup missed.

Root cause: `populateKotlinOwners` (which calls
`populateClassOwnedMembers`) assigned `ownerId` and qualified names to
class-owned function defs but left `def.type === 'Function'`. The
graph parsing-processor, in contrast, emits a `Method` node label for
class members. `resolveDefGraphId`'s parameter-typed key lookup is
gated on `def.type === 'Method'` (graph-bridge/ids.ts:108-116), so it
was skipped for every Kotlin class method. With the type-keyed lookup
skipped, the resolver fell through to `simpleKey`, which is
first-wins by registration order — and the Int overload always
registered first in these fixtures.

Fix: `populateKotlinOwners` now upgrades `def.type` from `Function`
to `Method` after `populateClassOwnedMembers` assigns `ownerId`. This
aligns the scope-resolution model with the graph's node labels so
parameter-typed key registration and lookup operate in the same
keyspace.

Picker logic in `pickImplicitThisOverload` / `narrowOverloadCandidates`
was already correct — verified by trace: it narrowed `lookup("alice")`
to the `[String]` def. Only the graph-id lookup was broken.

Verification (REGISTRY_PRIMARY_KOTLIN=1):
- Forced-mode: 21 -> 18 failing of 175 (3 fewer; tests 1620, 1659,
  1692 in `test/integration/resolvers/kotlin.test.ts` now green).
- Default-mode Kotlin: 175/175 unchanged.
- Full resolver suite: 2216/2216 unchanged.
- Remaining 18 failures are tracked by sibling sub-issues
  (#1758, #1759, #1760, #1762, #1763).

Does NOT add Kotlin to MIGRATED_LANGUAGES per parent #1746 flip criteria.

Closes #1761. Refs #1746.

Co-authored-by: Test <test@example.com>
This commit is contained in:
Gergő Magyar 2026-05-22 09:22:53 +01:00 • committed by GitHub
parent 6892482d70
commit 355f429c85

View file

@ -4,6 +4,29 @@ import { isClassLike, populateClassOwnedMembers } from '../../scope-resolution/s
export function populateKotlinOwners(parsed: ParsedFile): void {
populateClassOwnedMembers(parsed);
populateCompanionMembersOnEnclosingClass(parsed);
upgradeClassOwnedFunctionsToMethods(parsed);
}
/**
* Align scope-resolution `def.type` with the graph's node-label
* conventions: a `Function` def that lives inside a class body becomes
* a `Method`. The Kotlin extractor labels every `function_declaration`
* as `Function`, but the graph parsing-processor emits a `Method`
* graph-node label for class members. Without this realignment,
* `resolveDefGraphId`'s parameter-typed key lookup (gated on
* `def.type === 'Method'`) falls through to the simple-name fallback
* for class methods, collapsing same-name same-arity overloads onto
* the first-registered node (#1761).
*
* Only Method-bearing types are touched. Methods have a class owner
* (set by `populateClassOwnedMembers`) and a class-qualified name.
*/
function upgradeClassOwnedFunctionsToMethods(parsed: ParsedFile): void {
for (const def of parsed.localDefs) {
if (def.type !== 'Function') continue;
if (def.ownerId === undefined) continue;
(def as { type: SymbolDefinition['type'] }).type = 'Method';
}
}
function populateCompanionMembersOnEnclosingClass(parsed: ParsedFile): void {