Skip to content

fix(resolution): resolve awaited TypeScript receivers safely - #1885

Merged
colbymchenry merged 4 commits into
mainfrom
fix/triage-1840
Sep 16, 2026
Merged

colbymchenry merged 4 commits into
mainfrom
fix/triage-1840

Conversation

@colbymchenry

Copy link
Copy Markdown
Owner

Awaiting a function that returns a primitive can currently make calls such as listed.split() resolve to an unrelated project class. This change uses the visible local or imported factory's return type, keeping the real listPaths call and valid Promise<Engine> → Engine.run relationships.

Reuses @maxmilian's regression cases and primitive guard from #1855, with additional scope, import-alias, return-type ownership, shadowing, multiline-signature, ASI, chained-result, and edit/sync controls. Per-file scope data is lazy and bounded; resolver invalidation clears both eligibility and inferred-type caches. Existing member-factory handling remains intact.

Fixes #1840.

Validation on Node 24.16/Linux:

  • Original two-file indexing reproduction fails on main 8f808196 and passes with both native and WASM backends.
  • Full build passes; 354 native tests pass, including the full resolution suite, new controls, prior Rust/store regressions and original #1790 drops every identifier-rooted member call, not just built-in collections — 8 tests red on main #1794 coverage.
  • 134 affected WASM tests plus 12 focused resolution cases pass.
  • The native artifact was freshly built for the preceding Rust fix; this PR does not change kernel source.
  • The complete published tree matches local tested commit 966394c8 (tree d913cf85c85406ee12b39be93909fd9d79348aa4).

Bounded performance check: replayed 207,446 saved JS/TS call references from pinned VS Code platform commit 38246c0 through the actual method matcher. Scope caching reduced the initial implementation's cost. The final sequential pair used 23.10 → 26.05 CPU seconds (21.88 → 24.47 wall seconds); this is helper-only overhead, not a full-index timing or speed claim. Optimized matcher results are identical to the preceding correct implementation.

Limitations: Linux only. A broader all-language WASM resolution run during the preceding Rust validation exited after a Dart timeout; that case passes in isolation. No full-suite or cross-platform verdict is claimed.

Co-authored-by: Max Hsu maxmilian@gmail.com
Co-authored-by: Claude Opus 5 (1M context) noreply@anthropic.com

colbymchenry and others added 4 commits September 16, 2026 07:48
Reuse and extend PR #1855 with scope, import and edit guards.

Co-authored-by: Max Hsu <maxmilian@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@colbymchenry
colbymchenry merged commit d0996a2 into main Sep 16, 2026
bompus added a commit to bompus/codegraph that referenced this pull request Sep 16, 2026
Upstream changes:
- fix(resolution): resolve awaited TypeScript receivers safely (colbymchenry#1885)
- fix(rust): keep self method calls on the correct owner (colbymchenry#1882)
- fix(telemetry): honor opt-out (colbymchenry#1880)

Conflicts:
- CHANGELOG.md (both appended under Fixes; kept fork bullets, added upstream's)
- src/resolution/name-matcher.ts (fork's modular/binding architecture vs
  upstream's awaited-receiver machinery; kept both — awaited caches, lexical
  scope gating and the matchMethodCall fallback slot in alongside
  requireReceiverEvidence, guarded/iteration receivers and bound-call factory
  resolution)

Fork-side reconciliation:
- matchBoundReceiverCall factory path now requires the callee call to end the
  initializer (upstream's tail rule), so `await f().chain()` binds the chain
  result rather than f's return type.
- Added `new Cls().factory()` member-factory handling to the same path —
  upstream resolves the awaited member-factory case via generic name matching
  that the fork's receiver-evidence gate deliberately blocks.
- Re-baselined the fork-owned torture-multilang golden: `self.m()` refs are
  now emitted owner-scoped; `self.area` resolves via qualified-name (0.9)
  instead of bare-name exact-match (0.4), and calls to methods absent from
  Self stay unresolved.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TypeScript: split() on an awaited Promise<string> result resolves to an unrelated class method (v1.6.0)

1 participant