Skip to content

fix(kernel): port upstream's remaining JS binding/ambient resolution debt + explore fixes - #585

Merged
bompus merged 3 commits into
fork/consolidatedfrom
fix/kernel-port-debt
Oct 29, 2026
Merged

bompus merged 3 commits into
fork/consolidatedfrom
fix/kernel-port-debt

Conversation

@bompus

@bompus bompus commented Oct 29, 2026 •

Copy link
Copy Markdown
Owner

Summary

Ports upstream resolution behavior into the kernel for the failure batches that #582's landing exposed, plus one perf fix found while profiling:

  • js-receiver-binding-scope (TS: react-dom root.render() links to a class component's render() when root is declared outside colbymchenry/codegraph#2589): an uninformative bound receiver — an unannotated parameter or a new C() whose C binds no class — now falls through to the name strategies instead of staying terminal. js_param_unannotated checks name: at the binding's own position so { root }: { root: any } falls through while store: any still claims (fork claim model preserved). untyped_local_call_type keeps const r = createRoot(el) typed. Strategy 3 gains the is_react_lifecycle_method filter for render/lifecycle methods on extends (React.)?(Pure)?Component classes.
  • dynamic-import-binding (TypeScript: functions imported from node: built-ins resolve to same-named project functions colbymchenry/codegraph#2491): js_out_of_repo_binding — the narrowest in-scope import-kind binding row (block-scoped await import/require bindings win over file-wide statics) decides the name's module. When bound out-of-repo, inner_scope_shadows keeps only same-file declarations nested inside a function/method as candidates; non-calls refs get the early-null gate.
  • ambient-module-imports: post-resolution ambient gate — a node inside declare module 'x' is reached only through an import of x (ambient_specifier_of + reaches_ambient_module), fixing html.ts's out-of-repo re-export linking typings/vscode.d.ts.
  • java-records: MEMBER_TYPE_NON_TYPES ported verbatim (adds permits, throws, ~30 keywords) so permits Circle, Square no longer types receivers.
  • function-ref: fn_ref outcome channel so paren-less Pascal method pointers keep fnRef: true edge metadata.
  • explore/substring: name-substring index honors the fork's explicit (length, kind, rowid) order instead of simulating SQLite's plan (plan-detection machinery removed); covering tests longer than WHOLE_TEST_MAX_LINES emit header + statement ranges so requested source reaches the evidence.
  • perf(kernel): the Go typed-receiver path ran the same ancestor declaration walks 3–4× per ref (import-shadow check, asserted-type scan, local-decl walk). resolve_go_cross_package now reuses the qualifier's shadow check, and two memos share local_decl_at/go_asserted_local_type results per (file, name, site). kernel-prof on gin: calls|go nonbare ~261 → ~206 ms (−21%).
  • Fixed the ui-package failure locally — a stray pnpm install overlay had installed svelte 5.57.3 vs the locked 5.56.10 (only_child skew); npm ci restored the locked layout. No code change.

Test plan

  • Debt sweep: ui-package 18/18, js-receiver-binding-scope 3/3, dynamic-import-binding 6/6, java-records 10/10, explore-requested-source 23/23, ambient-module-imports 27/27, explore-long-query 13/13, function-ref 44/44 — 144/144
  • Regression: bindings-receiver + phase2b + name/import/golden suites ~400 tests green; golden dumps unchanged
  • Precision: vite 8/8 held, svelte 1/1, jq clean, gin 3/3 held with identical edges (reports committed)
  • Go suites after the perf change: 47 files / 459 tests green
  • Typecheck + kernel build (fnm exec + cargo on PATH)

README rows checked

No README table rows move: these ports make the fork match upstream behavior, and no quoted numbers change. The upstream merge-point claim is unchanged (still through 69af19ac); the new upstream behavior rows these ports close were already claimed as merged debt items. The gin perf delta is per-ref kernel time, not an index-wall-clock row the README quotes.

…esolution debt

Three pre-existing resolver suites go green:

- js-receiver-binding-scope (colbymchenry#2589): a bound receiver whose binding says
  nothing falls through to the name strategies — an unannotated parameter
  (`(root)`, `{ root }: { root: any }`) or a `new C()` whose C is no class.
  Annotated params (`store: any`) and typed/call-result declarations stay
  terminal under the claim model. Strategy 3 now also filters React
  lifecycle methods on Component-derived classes for non-this receivers.
- dynamic-import-binding (colbymchenry#2491): isOutOfRepoBinding + innerScopeShadows —
  the narrowest in-scope import binding (block-scoped dynamic rows win over
  file-wide statics) decides the name's module; when it's outside the repo
  only same-file declarations nested in a function still shadow it.
- ambient-module-imports: the resolveOne ambient gate — a declaration
  inside `declare module 'x'` is reached only through an import of `x`,
  never by bare name from a file that reaches no `x`.

Also in the batch: MEMBER_TYPE_NON_TYPES verbatim (Java `permits`/`throws`),
and a `fn_ref` outcome channel so paren-less Pascal method pointers keep
their fnRef edge metadata.

Precision: vite 8/8, svelte 1/1, jq clean; golden dumps unchanged.
…long covering-test ranges

- name-substring-index: the fork (#258) made result order explicit —
  (length, kind, rowid) — and reshaped idx_nodes_kind for it. Keep
  upstream's memoized substring index but order its hits by that contract
  instead of simulating whichever plan SQLite picked; the plan-detection
  machinery goes with it.
- explore-source-ranges/tools: a covering test longer than
  WHOLE_TEST_MAX_LINES emitted its whole span and truncated before the
  requested call+assertion. Long callbacks now emit their header plus the
  statement ranges, and sourceMinimums reserves every no-nodeId range of a
  covering test, not just the first.
@coderabbitai

coderabbitai Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

The Go receiver path re-ran the same ancestor scans at the same site:
go_written_qualifier and resolve_go_cross_package each shadow-checked the
import root with a full local_at walk; go_asserted_local_type ran twice per
ref (once in go_asserted_member, again inside go_named_local_written); and
go_named_local_written repeated the local_declaration_in ancestor walk
go_local_declaration_at had just done for the same name+site.

- resolve_go_cross_package skips its is_shadowed_import when
  go_ref_qualifier already proved the receiver is the written qualifier
- go_local_decl_memo (keyed file+name+site byte) shares the local_decl_at
  walk — its value keeps the target identifier's byte range so
  go_named_local_written re-derives the node instead of re-walking
- go_asserted_type_memo dedupes the asserted-type scan

kernel-prof on the gin corpus, calls|go nonbare refs: ~261 -> ~206 ms
(-21%), bound_receiver_claim 208 -> ~165 ms. Precision identical
(8417 edges, 3/3 held); golden dumps and all 459 Go tests green.
@bompus
bompus merged commit 889bbbd into fork/consolidated Oct 29, 2026
7 checks passed
@bompus
bompus deleted the fix/kernel-port-debt branch October 29, 2026 21:47
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.

1 participant