Skip to content

feat(kernel): port the remaining upstream resolution drift - #587

Merged
bompus merged 2 commits into
fork/consolidatedfrom
fix/upstream-drift-batch3
Oct 30, 2026
Merged

bompus merged 2 commits into
fork/consolidatedfrom
fix/upstream-drift-batch3

Conversation

@bompus

@bompus bompus commented Oct 30, 2026 •

Copy link
Copy Markdown
Owner

Ports the resolution behaviour upstream added after the last merged batch (#586, pinned through 8e854d11): browser-host calls (colbymchenry#2907), enclosing-class member calls, Go receiver typing through parameters, func-typed fields and call results (colbymchenry#2543, colbymchenry#2581), library-method names on untyped receivers, and same-module copies. One commit, 19 files, +2,096/−44.

What changed

  • Browser host globals (JS/TS): window.open(), localStorage.getItem(), location.reload(), a worker's self.postMessage() link no project method unless the file binds or imports the name. The rule reads whether the file mentions the name only as a receiver or after typeof; the collapsed-object path returns a tri-state (found / the browser's / not ours) so window.localStorage.getItem() declines while window.App.init() still resolves; an unbound self is the global object in both receiver readers.
  • Enclosing-class members: render(), this.render(), super.render() bind to the caller's own class along Python's C3 order, Java's nested-type headers and Scala's siblings.
  • Go receiver typing: parameters, func-typed fields (get func() A → the call is A), call results, range elements, and package shadowing (shadowPkg(store *Holder) makes store.New() the method, not the package).
  • Library-method names: a std name on an untyped receiver (m.getOrElse, data.put, size) declines unless the receiver's own words name the type; a typed field, this., or a receiver named for the owner keeps it.
  • Visibility: isVisibleAcrossFiles guards the name strategies only, as upstream does (index.ts:1867), so a typed store action and an imported component value are not treated as unexported module bindings; every language's own privacy still applies.

Gaps the port's tests found

  • tree-sitter-cpp writes d.operator+=(c) as a call on the receiver with the operator name in an ERROR sibling, so no argument list was read and operator+=(int) took a call operator+=(const Counter&) fits. The operator_name node is matched instead, comments in the access included.
  • go_field_type kept only a func-typed field's first token (func()), losing its result.
  • Go result typing read a package function even when a parameter of the package's name shadowed it.
  • A Python local was read by the strict scope rule alone, so store = A(); store = B(); store.get() resolved to nothing; the invocation-time binding decides now, with the fix(python): calls like reg.get() on a typed local or parameter reach the class's method colbymchenry/codegraph#2821 refusals (branch/loop/with bindings, outside-project bases) intact.
  • Python inherited members were walked breadth-first, so Adapter(Left, Right) with Left(Root) reached Right's method before Root's; the walk is depth-first along the header and *bases expands its module-level tuple.

Checks

  • vitest run: 11,142 passed, 11 failed, 44 skipped (934 files). All 11 failures reproduce on pristine origin/fork/consolidated (a7e5714b): 8 in js-builtin-method-calls, plus library-receiver-calls (fetch Response), route-inline-handler-calls, sync-typed-local-member-retry. The branch adds none.
  • The port's own suites: 78/78 (browser-host-globals, enclosing-class-member-call, three Go files, library-method-calls, same-module-copy-resolution), and the Python suites the receiver change touches (python-self-call-not-import 61/61, receiver-scope-lookup 69/69, python-typed-builtin-method-calls 26/26).
  • Golden dumps: torture-multilang re-baselined for one Java edge, confidence 0.4 → 0.9 (refName: norm, target unchanged) because the enclosing-class lookup now reads the bare norm() call inside Point.compareTo.
  • npm test's check:kernel-rules gate fails on pascal_scope.rs on origin too (fixed separately by fix(kernel): unblock npm test on the default branch #584); the suite above is vitest run directly.

README rows

Checked the "About this fork" tables and the benchmark rows: none move. Resolution correctness only, no command, language, framework, config key or measured README number changes.

Ports the behaviours upstream added after the pinned 8e854d1: calls on
browser host objects (colbymchenry#2907), enclosing-class member calls, Go receiver
typing through parameters, func-typed fields and call results (colbymchenry#2543,
colbymchenry#2581), library-method names on untyped receivers, and same-module copies.

The port's own tests found five gaps, fixed here:

- tree-sitter-cpp strands an explicit operator's name in an `ERROR`
  sibling (`d.operator+=(c)`), so the argument list was never read and
  the first overload won; the operator's `operator_name` node is matched
  instead, comments inside the access included.
- a func-typed Go field (`get func() A`) was typed by its first token;
  the whole type is kept and the call takes the func's result.
- Go result typing read a package's function even when a parameter of
  the package's name shadowed it.
- a typed-local receiver kept only the strict scope read, so a rebinding
  (`store = A(); store = B()`) resolved to nothing; the invocation-time
  binding decides, with the colbymchenry#2821 refusals intact.
- Python inherited members followed breadth-first edge order, so
  `Adapter(Left, Right)` with `Left(Root)` reached Right's method before
  Root's; the walk is depth-first along the header, and `*bases` expands
  its module-level tuple.

`isVisibleAcrossFiles` guards name picks only, as upstream does; a typed
store action or an imported component value is no unexported-module
pick. JS/TS browser host globals are read as the browser's own unless
the file binds the name.

Golden dumps: `torture-multilang` re-baselined for one Java edge, whose
confidence rises 0.4 -> 0.9 because `var x = Method()` now types the
receiver; the target is unchanged.
@coderabbitai

coderabbitai Bot commented Oct 30, 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.

- Browser host scan: the `typeof` lookbehind now starts on a character
  boundary (a non-ASCII byte could panic the slice), and a lexical binding
  of the name at the call keeps the name the file's own, which a `${…}`
  interpolation's blanked contents cannot hide.
- Python inherited members: `inherited_through` reads Python's C3 order
  (each class's own member, not its subtree's) and `python_c3` linearizes
  `python_bases`, `*bases` included. The header-position sort in
  `python_mro` is reverted: it could match the subclass's own name first
  (`class Model(Mixin, parent.Model)`).
- A func-typed Go field stops at `;` and a struct tag, so
  `get func() *A; other *B` is `func() *A`.
- The generic-parameter exception is limited to `Recv`/`RecvMsg` on a
  binding that is still a parameter, so `s.Header()` does not enable name
  matching for a project `Resp.Get`.
- `*bases` is read from the module-level tuple written before the class,
  not an earlier function's local.
- python_types.rs: the conditional-binding guard's regex had a literal
  backspace instead of `\b`; the chosen conditional binding is now
  refused when the evidence conflicts.

Tests: a non-ASCII receiver line, a template interpolation's `document`
parameter, a same-line second Go field with a struct tag, a diamond C3
case, and `class Model(Mixin, parent.Model)`.
@bompus

bompus commented Oct 30, 2026

Copy link
Copy Markdown
Owner Author

Review round (GPT-6.1 Sol, xhigh) returned fix-then-ship with seven findings, all fixed in 028cdba8, each with a regression test.

  • P1 Unicode panic: the typeof lookbehind starts on a character boundary now. Test: π before window.open().
  • P2 C3 order: inherited_through reads Python's C3 order and each class's own member, so a diamond (Left(Root), Right(Root), both Root and Right defining the name) reaches Right's. Test: the diamond.
  • P2 base sorting: the header-position sort in python_mro is reverted; it could match the subclass's own name first (class Model(Mixin, parent.Model)). Test: that header.
  • P2 func field: stops at ; and a struct tag. Test: get func() *A; other *B \json:"other"`→A::Run`.
  • P2 generic exception: limited to Recv/RecvMsg on a binding that is still a parameter.
  • P2 template interpolation: a lexical binding of the name at the call keeps it the file's own; a ${…} interpolation's blanked contents cannot hide the parameter. Test: ${((document: Model) => document.save())(model)} → Model::save.
  • P2 splat base scope: *bases is read from the module-level tuple written before the class.

Also fixed the pre-existing defect the review found: python_types.rs had a literal backspace instead of regex \b in the conditional-binding guard; the chosen conditional binding is now refused when the evidence conflicts.

The golden explanation is corrected too: TortureRecord.java:24 calls bare norm() inside Point.compareTo, so the enclosing-class lookup explains the 0.4 → 0.9 confidence, not a var initializer.

Full suite after the fixes: 11,146 passed, 11 failed — the same 11 that reproduce on pristine origin.

@bompus
bompus merged commit 4d3ddde into fork/consolidated Oct 30, 2026
6 of 7 checks passed
@bompus
bompus deleted the fix/upstream-drift-batch3 branch October 30, 2026 03:27
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