Repository navigation
fix(resolution): resolve a call to the caller's own class member before ranking same-file namesakes - #1952
fix(resolution): resolve a call to the caller's own class member before ranking same-file namesakes#1952danusha2345 wants to merge 3 commits into
Conversation
6db9949 to
08f14e6
Compare
|
Rebased onto main and narrowed. Main now confines a bare call to what is in scope for Kotlin, C#, Swift, Dart, Ruby and PHP (#2172, #2151, #2170, #2145, #2147, #2142) and Java via #2126, so 13 of the 20 cases pass there and are dropped with their language branches. What remains, all failing on main: Scala and C++ bare calls, Python 🤖 Generated with Claude Code |
c2e1cca to
defc548
Compare
4bd180a to
158b37a
Compare
…o the argument-fit pick (colbymchenry#1952 follow-up for colbymchenry#2612) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
158b37a to
2dbc55a
Compare
|
Rebased onto |
a3c14f0 to
021e954
Compare
…he name strategies; colbymchenry#1938/colbymchenry#1954 tests follow upstream's colbymchenry#2684/colbymchenry#2664 The same changes went into the rebased PR branches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7ccdd75 to
7776ad1
Compare
|
Rebased on
Full suite on 16a8e77 with the native kernel ( |
…per call in a class expression is not the enclosing class's member The merge took main's colbymchenry#2831 for the conflicting Rust hunks but 167 lines of the closed colbymchenry#2625 (rustWrittenReceiverType) auto-merged beside them and ruled out main's own `Sink::flush` case; removed. With main's js-super-calls (colbymchenry#2818), colbymchenry#1952's enclosing-scope pick read a class expression's `super.run()` as the enclosing class's and sent it to its parent: a call written on `super` now skips the pick (the same change goes to PR colbymchenry#1952). js-class-expressions pins the 0.9 strong match colbymchenry#1952 gives `this.run()` in a class expression. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A receiver-less call in Java / Scala / C++, and a `this.` / `self.` / `super.` call in TypeScript / JavaScript / Python (which the extractor emits under the bare name) fell through to findBestMatch whenever the language's scoping filter left several same-named members standing, and its same-file line-distance term handed the call to whichever one sat nearest: `RegName.toString()`'s `render()` went to a longer sibling class's `render`, `super.render()` to nothing or the overriding method itself, a nested `Builder` to another `Builder`'s supertype. matchByExactName now first walks the caller's qualified-name scopes innermost-out: a member the caller's own class declares, then one it inherits (resolved extends/implements edges, limited to the supertypes the declaration's header names), then — for a bare call only — the classes it is nested in, stopping before an outer class when an unindexed supertype could declare the name. The receiver is read back from the call line. A match scores 0.9; anything else keeps the existing ranking. Kotlin, C#, Swift, Dart, Ruby and PHP are left to their own in-reach filters, which already settle these calls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y their arguments, in every language The enclosing-scope pick returned the first same-file overload of the caller's own member, so Scala's `this.++(1, 2)` landed on `++(o: Vec)` where main's argument fit chooses `++(n: Int, m: Int)` (the operator-method-names case colbymchenry#2769 added). The C++-only fall-through is now the rule for every language: when the owner declares the name more than once, the ranking below picks among those overloads only. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ing class's member main's js-super-calls (colbymchenry#2818) resolves `super.run()` through the class's extends edges and declines a call it cannot place in a class member — one in a class expression's method, which the index records from the enclosing method. The enclosing-scope pick then read that call as the enclosing class's `run` and sent it to its parent: `Holder::make -> Base::run`, where the `super` is `Other` (main's colbymchenry#2497 test). A call written on `super` now skips the pick and takes the strategies after it, as on main. `this.run()` inside a class expression is that class's own member, so js-class-expressions now pins the 0.9 strong match this branch gives it instead of main's 0.4 proximity guess — the same edge, by evidence. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
7776ad1 to
3016687
Compare
…mchenry#2876; 11 landed PRs yield to main; EXTRACTION_VERSION 55) Main landed eleven of our PRs as our own commits with the maintainer's additions (colbymchenry#2847, colbymchenry#2848, colbymchenry#2850, colbymchenry#2851, colbymchenry#2853, colbymchenry#2854, colbymchenry#2855, colbymchenry#2856, colbymchenry#2868, colbymchenry#2874, colbymchenry#2875), the traversal half of colbymchenry#2839 (colbymchenry#2860) and the trail hardening of colbymchenry#1667 (colbymchenry#2869). Where the integration carried our original version, main's wins: play.ts, routes.ts, the tsjs kernel extractor, import-resolver's PHP alias lookup, isDecisiveSameFileMatch, matchNewReceiverCall and the tests of those PRs. Kept beside main: colbymchenry#1952's enclosing-scope member pick, colbymchenry#1936's closest-copy confidence, colbymchenry#2258's Kotlin imported-type block, colbymchenry#1875's commitHdlProfile on indexFiles and hdlAccess, colbymchenry#1583's impact budget (the type-hierarchy walk itself is main's), colbymchenry#1736's C #if tests. 22 changelog bullets of closed PRs removed where main has its own wording. EXTRACTION_VERSION 55: Rust receiver chains (colbymchenry#2846), `new C().m` shapes (colbymchenry#2854), Java records (colbymchenry#2868), Go method exportedness (colbymchenry#2857), generic supertypes (colbymchenry#2856). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…s member, or what it inherits Root cause: a bare call in Java or Scala, and a `self.`/`this.` call in Python, TypeScript and JavaScript, reaches matchByExactName as a bare name. With several same-named methods in reach, findBestMatch ranked them by file and line distance, so a sibling class's method declared nearer the call won over the caller's own class's or the one it inherits; above the 500 candidate ceiling the call was dropped. Fix (contributor): matchEnclosingScopeMember runs before the ranking. It reads the receiver back from the call line (bare, self/this, super) and walks the caller's scopes innermost-out: the own class, then what it inherits, then, for a bare call, the classes it is nested in. A member found there is the answer (0.9), and its overloads are ranked among themselves. A super call in a JS class expression is left to js-super-calls (PR 2497). Ours: - Inherited members first come from the declaration's own resolved supertypes (getSupertypeNodes), in the order its header lists them, a class further up before an interface that only declares the member; the PR's walk by name stays as the fallback when those edges reach nothing (an `extends` the index resolved to a namesake, as Minestom's Player to a nested EntityStatuses.LivingEntity). By name alone, Django's spatialite, oracle and mysql GIS editors reached the postgresql backend's DatabaseSchemaEditor.execute and _delete_index_sql (0.9), a class with two bases took either one's member (BaseDeleteView(DeletionMixin, FormMixin) got FormMixin.get_success_url), and SystemUI's RotationContextButton got RotationButton's declaration instead of ButtonDispatcher.getCurrentView. - Only `super`, `this`/`self` and Python's `cls` name the receiver. The PR also read `parent.`/`base.` as super and `cls.`/`static.` as self, but Java's extractor drops a receiver variable of those names too: protobuf's `parent.getFullName()` on an EnumDescriptor went to GenericDescriptor. - C++ is left to matchCppImplicitThisCall (PR 2479), which already looks members up in the class, its bases and its enclosing classes. The PR's C++ branch added the caller's own file's namespace functions, which beat the overload the arguments fit: fmt's 3-argument `copy<Char>(b, e, out)` calls went to format.h's 2-argument copy (0.9). - Tests for each, and the CHANGELOG bullet in the house format. Validation: enclosing-class-member-call.test.ts has 12 cases: 6 fail against main's resolver, and all 5 of ours fail against the PR as written. Kernel A/B against main 7cceba5 on 15 repos (leveldb, fmt, gin and serilog byte-identical). Every changed site was judged by a hierarchy oracle (own class, then bases depth-first in header order, classes before interfaces, enclosing classes for a bare call) or by hand. About 7,400 links moved from a wrong method to the right one (protobuf 3,208, vscode base+editor 1,383, Play 806, django 766, netbox 316, SystemUI 314, spring-ai 312), and about 9,100 right links rose from 0.7 to 0.9. One site got worse (http4s `object RespPrelude { case class RespPrelude }`), and no C++ site changed. CPU, median of 3 interleaved runs: kestra 154.9 s on main vs 152.8 s, vscode base+editor 79.9 s vs 82.6 s (within the rounds' spread). On a vendored-theme stand-in of 1,500 classes, the walk links the 4,500 calls main drops at the 500-candidate ceiling, for +2.2 s (JS) and +1.8 s (Python). Full suite on 3df1cc64 (main 31ec908): 768 files passed, 6 skipped; 9,160 tests passed, 0 failed, 85 skipped. Original PR #1952 by @danusha2345. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @danusha2345, this landed as #2950 with you as the commit author. Resolving a call through the caller's own class before the line-distance ranking pays off widely: across 15 repos it moved about 7,400 links to the right method, among them Django test cases'
It ships in the next release. |
…mchenry#2972; 10 landed PRs yield to main; EXTRACTION_VERSION 56) Main landed ten more of our PRs as our own commits with the maintainer's additions (colbymchenry#2923 ← colbymchenry#1936, colbymchenry#2924 ← colbymchenry#1951, colbymchenry#2925 ← colbymchenry#1939, colbymchenry#2930 ← colbymchenry#2921, colbymchenry#2940 ← colbymchenry#1736, colbymchenry#2942 ← colbymchenry#1947, colbymchenry#2950 ← colbymchenry#1952, colbymchenry#2961 ← colbymchenry#1954, colbymchenry#2965 ← colbymchenry#1942, colbymchenry#2972 ← colbymchenry#1933) and the module-path half of colbymchenry#2308 (colbymchenry#2955). Where the integration carried our version, main's wins: the enclosing-scope member pick and its tests, the Go and Java receiver typers, the delegating-call self-loop rule, the duplicated-module copy confidence, the C #if collapse, the module-path resolution of Rust paths, the trail/path hardening in utils.ts. Kept beside main: colbymchenry#1875's Verilog hooks and status fields, colbymchenry#2839's implementations command, colbymchenry#1923, colbymchenry#2922, colbymchenry#2258, colbymchenry#1761, colbymchenry#1583, the bare-call half of colbymchenry#2308 (rust-use-bindings.ts). CHANGELOG is main's plus the open PRs' bullets. EXTRACTION_VERSION 56: the C #if group handling (colbymchenry#2940) and the kernel change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Problem
A call to a member of the caller's own class is resolved as if it were ambiguous. This covers a bare call, which means
this.m()in Java, Kotlin, C#, Scala, Swift, C++, Dart and Ruby, and an explicitthis./self./$this->/super.call. The extractor drops those receivers, so all of them reach the resolver as the bare name.findBestMatchthen breaks ties between same-file candidates by line distance. Nothing asks which class the caller is in, so a sibling class's same-named method wins at 0.4 when it's closer:render()insideRegName.toString()resolves toIPv4.render.super.onCreate()becomes a self-loop.gcs()insideModeX::rungoes toCopter::gcsinstead ofMode::gcs.I reproduced it on
mainfor Java, Kotlin, C#, Scala, Swift, C++ (inline and out-of-line members), Dart, Ruby, PHP$this->, Pythonself.and TypeScriptthis..Fix
matchEnclosingScopeMemberruns inmatchByExactNamebefore the ambiguity ceiling andfindBestMatch. It reads the receiver back from the call line: bare, a self-receiver, orsuper. It then walks the caller's scopes from the inside out and returns the first match at 0.9, the same confidence as a typed match:Guards:
super.skips its own class and never lands on an interface or abstract declaration.Viewor an anonymous class, since that parent might declare the name.When nothing matches, the existing ranking applies. A class member now wins over a same-named top-level function, which follows the Kotlin, C++ and Swift scoping rules.
Measured (
mainba3c21e vs this branch; node counts unchanged everywhere)parent::__constructself-loops ×3,$this->fixlinks)ResultExtractors::status,FutureAwaits::await,BaseController::Action(previously unresolved or an unrelated spec at 0.4)super.x()self-loops and inheritedgetContext/getChildCountthat went to unrelated classesAbout 350 changed edges were checked by hand, and none has a wrong target. Indexing time is within noise: SystemUI took 42.7 s and 59.0 s on
mainand 47.5 s and 61.3 s with this branch, on a loaded machine.It composes with #1938 and #1936: this path returns before theirs, and all tests pass together.
Known limits:
with(x) { render() }, the lambda receiver should win, but the enclosing class is picked. Onmainthis was a proximity guess anyway.Tests
The new
__tests__/enclosing-class-member-call.test.tshas 20 cases:main: the 12 language cases, a Java inner class calling its outer class, an inherited member,super.render(), and same-named nestedBuildertypes.super.never landing on an interface, and Kotlin member vs top-level function.The full suite passes: 275 files, 4736 tests.
🤖 Generated with Claude Code