Skip to content

bug: resolveExactGlobalMatch (bare-call global fallback) lacks cross-language guard #2023

Description

@carlos-alm

Summary

tests/unit/call-resolver.test.ts — describe block resolveByMethodOrGlobal — cross-language global fallback rejection (#1783) — has a failing test on fix/issue-1884-computed-string-literal-keys-not-unwrapped-in (confirmed at commit fdedff87, no local modifications to src/):

FAIL tests/unit/call-resolver.test.ts > resolveByMethodOrGlobal — cross-language global fallback rejection (#1783) > does not resolve a bare call to a same-directory, same-named symbol in a different language
AssertionError: expected [ { id: 1, file: 'tracer/loader-hooks.mjs', kind: 'function' } ] to deeply equal []

Repro

const jsExport = { id: 1, file: 'tracer/loader-hooks.mjs', kind: 'function' };
const lookup = makeLookup({ load: [jsExport] });
const result = resolveByMethodOrGlobal(
  lookup,
  { name: 'load', receiver: null },
  'tracer/ruby-tracer.rb',
  new Map(),
);
expect(result).toEqual([]); // actually returns [jsExport]

A Ruby caller's bare load() call incorrectly resolves to a same-directory JavaScript load export purely because it's the single highest-confidence same-directory candidate — there is no static relationship between the two files/languages.

Root cause

resolveByGlobal's cascade (src/domain/graph/resolver/strategy.ts) is:

  1. resolveViaAccessorThisDispatch
  2. resolveExactGlobalMatchlookup.byName(call.name) filtered/ranked only by computeConfidence (directory proximity), with no language-family check at all
  3. resolveViaSameClassSibling — this one does guard bare calls via isModuleScopedLanguage(relPath) (the codegraph exports: false-positive cross-language consumer attribution via name-based fallback matching #1783 fix)

Because step 2 returns a non-empty, unambiguous (single highest-confidence) result first, step 3's language-scoped guard is never reached — the #1783 fix only protects the same-class-sibling fallback tier, not the exact-global-match tier that runs before it.

This is the third instance of this general class of bug found in this resolver:

Suggested fix

Apply an isSameLanguageFamily (or equivalent) check to resolveExactGlobalMatch's candidate filter in src/domain/graph/resolver/strategy.ts, mirroring the guard already used elsewhere in this same file, so a same-directory but cross-language same-named symbol never satisfies a bare call.

Found while

Validating the fix for issue #1887 (native engine skips Object.defineProperty accessor post-pass) — confirmed unrelated to that change; failure reproduces on a clean worktree of the base branch with no src/ modifications.

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