Skip to content

resolveCallTargets: concrete-receiver bare-name match still runs before type-aware resolveByReceiver dispatch #2025

Description

@carlos-alm

Summary

Issue #1888 fixed the "unfiltered by kind" half of the same-file bare-name lookup bug in resolveCallTargets (src/domain/graph/builder/call-resolver.ts, mirrored in crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs): the lookup is now restricted to CALLABLE_SYMBOL_KINDS (function/method) whenever the call has any receiver (this/self/super or a concrete object), so a coincidentally-named class/interface/struct/etc. in the same file can no longer win.

That fix does not address the other half of #1888's title — "runs before type-aware dispatch" — for calls with a concrete object receiver (obj.method(), as opposed to this/self/super). For those calls, the (now kind-filtered) same-file bare-name lookup still runs before resolveByReceiver's type-aware cascade (typeMap lookup, qualified Type.method, composite pts key, etc.). If an unrelated same-file function or method happens to share the call's bare name, it can still win outright — the kind filter narrows the false-positive surface (no more class/interface matches) but doesn't eliminate it for function/method-kind collisions.

Why this wasn't fixed in #1888

The natural fix — try resolveByReceiver before the bare lookup whenever a concrete receiver is present — was implemented and found to regress tests/integration/issue-1517-computed-prop-resolution.test.ts:

  • helpers.formatDate(...) where helpers = { ['formatDate'](date) {} } (a computed-key object-literal method).
  • The extractor emits two node representations for the same physical method: a bare-name node (formatDate, kind method, per fix(wasm): verify computed-property-name method resolution at call sites #1517's own fix) and a qualified-name node (helpers.formatDate, kind function, from the general object-literal-function extraction pass).
  • The bare lookup finds the correct bare-name node directly. Reordering to try resolveByReceiver first instead finds the other (also arguably valid, but less precise/different) qualified-name node via the composite-pts-key fallback tier, changing the resolved target and breaking the existing, already-passing test's expectation.

Fixing this properly requires either deduplicating/reconciling the two node representations for computed-key object-literal methods, or a more surgical way to prefer resolveByReceiver's result over the bare match only when they'd actually disagree in a way that matters — neither of which is a small, targeted change, and is out of scope for #1888's own kind-filter fix.

Suggested fix direction

  • Investigate why computed-key object-literal methods get two node representations (bare + qualified) in the first place — possibly the real fix is to stop double-emitting rather than to reorder resolution.
  • Alternatively: only prefer resolveByReceiver's result over the bare match when the bare match's file differs from what the receiver's type would resolve to, or some other disambiguation that doesn't regress fix(wasm): verify computed-property-name method resolution at call sites #1517.
  • Needs its own resolution-benchmark regression run given the shared, universal nature of resolveCallTargets.

Repro sketch

// same file
function method() { /* unrelated */ }

class Widget {
  method() { /* the one obj.method() should actually call */ }
}

const obj = new Widget();
obj.method(); // currently may resolve to the unrelated top-level `method`, not `Widget.method`,
              // if the bare lookup finds `method` (kind: function) before resolveByReceiver
              // ever gets a chance to type-check `obj`.

Found while implementing #1888 — confirmed the naive reordering fix regresses #1517; not attempted further there per scope discipline.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions