Repository navigation
fix(resolution): library-method calls on untyped receivers need receiver evidence (Rust, Go, Python, Kotlin, Scala, C#, Java) - #1947
Conversation
f40e1d6 to
5213d7c
Compare
5213d7c to
b0a01fe
Compare
|
Rebased and reworked onto main's new structure. Rust, Kotlin and C# (and static
🤖 Generated with Claude Code |
0340bc7 to
21d5a2c
Compare
|
Rebased onto main. No maintainer PR has covered this one since the last rebase, so the Python, Scala and Java parts are unchanged. I removed the Go part (reading The remaining check uses 🤖 Generated with Claude Code |
21d5a2c to
2dd086b
Compare
…ame-named project methods A member call on a receiver of unknown type reached the lone same-named method for an untyped `recv.m` (instance-method 0.7). Standard-library names collected such calls: on Play ~2,500 Scala `map`/`get`/`foreach` calls and ~1,100 Java test-map `put` calls landed on unrelated project methods, and Python `d.setdefault()` on a same-file class's method. The standard-library method lists that already demand receiver evidence for Rust, Go, Kotlin, C# and VB.NET gain Python, Scala and Java sets: such a call now needs the receiver's own name to name the candidate's type. `cls` joins `self`/`this`/`base` as a receiver that is the calling type itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2dd086b to
92dbd97
Compare
Rebased onto the 2026-09-27 main. #1944 landed as #2032, so this PR now stands on main alone: 5213d7c on top of fa6dd01. It also absorbs #1953, the Java list: that PR only added to the same
library-methods.tsand the same check, so the two would have conflicted as separate PRs. #2028 covers JS/TS built-in names; this PR covers the other languages, so the two don't overlap.Problem
For many member calls, no receiver type reaches the resolver, and the call then binds to the only project method with the same name. There are two paths.
x.f().m(),a.b.m(),x?.m(); Kotlin/Scala chains with a lowercase root; Go chains deeper than two hops; Pythona.b.m(). Exact-match then binds them at 0.9, 0.7 or 0.4.x.m(). These reachmatchMethodCall's name-only strategy 3.Where the method name belongs to the language's standard library, the call is almost always that library method, and the one project method with that name collects every such call:
name.len()/v.iter().all()→ a RustAppLog::len/SpeedProfile::all: about 500 edges in one Rust GUI.conn.Close()→ a GorotatingLogWriter::Close.d.setdefault(k, [])→ a projectsetdefault.Task.Run(...)→ a C#Run.opt.map/get/foreach→ Scala project methods.Precision on
main, from 40 randomly sampled edges per language covering both paths:Fix
The fix is in the resolver only: no extractor or kernel change and no re-index.
library-methods.tsholds per-language lists of standard-library method names for Rust, Go, Python, Kotlin, Scala and C#.self.state.log.clear()→logkeepsAppLog::clear.GpsMode.ON.next().self/this/super/base/clsreceivers and implicit-this calls. Typed receivers resolve before any of these strategies and never reach the check.Measured
Base is #1944. Nothing was gained, node counts are unchanged, and every lost group was checked by hand:
flask.g.setdefault/pop: a one-letter receiver gives no word evidence)Task.Run×16,e.ToString×12)After the fix, 39 of 40 sampled remaining Rust edges are correct. Scala's remaining noise comes from ambiguous project method names (
header,value,apply), which this change doesn't touch.Tests
__tests__/library-method-calls.test.tscovers Rust, Kotlin, Python, Go and C#. Five of its six cases fail on the base. The controls cover:self.setdefault;The full suite passes: 276 files, 4734 tests.
Java (was #1953)
Problem
The list above of standard-library method names. A call with one of those names on an untyped receiver no longer binds to a lone same-named project method unless the receiver's name shares a word with that method's class. Java wasn't on the list, and its name-only matches have the same problem.
data.put(k, v)on a testMap→ a projectRejectingMap::put. That's 1,115 call sites in playframework.s.charAt(i),list.size(),CONSTANT.equals(x)andmView.getResources()bind to whichever project class declares that name.Collections.emptyMap()andString.valueOf(x)underimport java.util.*. The check for imported library classes only knows named andjava.langimports, so wildcard imports slip through.Integer.TYPE.equals(...)andX.KEY.equals(...)get no receiver type, so they bind by name too.On our integration build, which already has the Java receiver typing from #1942, name-only edges with a JDK/Android method name are about 30% correct on playframework's Java and about 40% on decompiled Android SystemUI. These were checked by hand.
Fix
A
javalist inlibrary-methods.ts, 64 names:Object:equals,hashCode,toString,getClass,compareTo;Stringmethods;Optional/Streammethods;getResources,getSystemService,findViewById,postDelayed,removeCallbacks,setVisibility,startActivity.Names that projects commonly declare themselves were left out:
post,of,apply,run,call,start,stop,getId,getContextand similar. Playframework alone declaresapply60 times.JAVA_STD_CLASSES. A call on one of these classes counts as a library call whatever the method name, also when written asjava.lang.X:Objects,Arrays,Collections,Optional,List,Map,Set,UUID,String, the boxed number types,Math,System,Thread. A project class with the same name keeps its edge through the existing receiver-word check.Constant receivers. A Java receiver ending in an ALL_CAPS constant gives no type evidence.
INSTANCEis exempt.Typed resolution at 0.9 is untouched.
Measured
Node counts are unchanged in every pair, and no edges were gained.
ByteString.EMPTY.equals, removed by the constant rule)Five other corpora are unchanged: two Kotlin apps, a Kotlin/C app, a small Java/Kotlin app and a Rust app.
Tests
New Java cases in
__tests__/library-method-calls.test.ts:list.get(0),s.toString(),Objects.hash(a),Collections.emptyMap()underimport java.util.*,Registry.KEY.equals(a).registry.get→Registry::get), a baresize()andthis.get()inside the owning class, and a receiver named after its type (userRegistry.size()).The full suite passes: 276 files, 4734 tests.
🤖 Generated with Claude Code