Repository navigation
fix(scala): resolve Outer.Inner(...) to the Scala type, never another language's constructor - #1951
danusha2345 wants to merge 2 commits into
Conversation
f291409 to
ebec4b1
Compare
|
Rebased onto main. The 🤖 Generated with Claude Code |
61f9b26 to
8924138
Compare
62774d0 to
a59afd3
Compare
e680b3b to
cdc4ee5
Compare
…ymchenry#1921, colbymchenry#1935, colbymchenry#1955, colbymchenry#1957, colbymchenry#1965, colbymchenry#2575, colbymchenry#2595, colbymchenry#2597, colbymchenry#2603–colbymchenry#2608, colbymchenry#2611 landed upstream) Conflicts: files owned by the foreign PRs now in main (colbymchenry#1921's Python import resolver and tests, colbymchenry#1935's class-strategy method) take main's version; our colbymchenry#1954/colbymchenry#1942/colbymchenry#1945/colbymchenry#1939/colbymchenry#1715/colbymchenry#1951/colbymchenry#2308 hunks sit beside main's new Rust and Python blocks as in the rebased PR branches; java.rs keeps the integration's `constant_declaration` fields under main's initializer walk; three CHANGELOG lines the merged PRs had already contributed are deduplicated, and the method blocks the merge duplicated in queries.ts and extraction/index.ts (the resolution-edge queries and the sync resurrection helpers, present once on main) are kept once. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
cdc4ee5 to
ec23f4b
Compare
… guessed Java constructor A Scala `Outer.Inner(args)` call (case-class / companion apply) misses the qualified-name lookup — Scala nodes are named `Outer::Inner`, the ref `Outer.Inner` — and fell through to matchMethodCall's Strategy 3. With no Scala method of that name, Strategy 3 widens to every language and picks by receiver-word overlap, so `WebSocket.Accepted(...)` or `ApplicationLoader.Context(...)` landed on a same-worded Java constructor (`play.mvc::WebSocket::Accepted::Accepted`). A second route to the same target: in `def f(): T = T.Inner(x)` the local-declaration pattern reads the return annotation as `T`'s type (`Inner`), and resolveMethodOnType hands back the Java `Inner::Inner` constructor. - Before Strategy 3, a Scala call with a capitalized member resolves to the Scala type `Outer::Inner` when it is unambiguous (every match in one file — class + companion — or one in the call site's file). The calls->class edge is stored as `instantiates`, like a bare `Foo(x)` apply. - The typed-receiver path no longer hands a Scala ref another language's constructor; a Java class is constructed from Scala via the import / `new` paths, not this guess. Real Java static / instance methods are still offered. (Strategy 3's cross-language pick of that constructor is already ruled out on main.) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a module Upstream colbymchenry#2029 indexes a Scala `object` as kind `module`, so the Outer.Inner(...) apply lookup, which accepted only class/trait, stopped resolving a call to a nested object that defines `apply` and left it without an edge. Accept a Scala `module` too, and rank it after a class or trait of the same name so a case class still wins over its companion object whatever the declaration order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ec23f4b to
bc58308
Compare
…object it builds Scala qualified names carry no package (Outer::Inner), so a call written Outer.Inner(args), a case-class or companion apply, found no type by its written name. It fell through to the name strategies, and under a return type annotation (def f(): WebSocket = WebSocket.Accepted(flow)) the local-declaration reader took WebSocket for the receiver's type and handed over an unrelated Java constructor, Other::Accepted::Accepted. Before the receiver-word strategy, a Scala call whose member is capitalized now resolves to the Scala type Outer::Inner when that is unambiguous: every match in one file (a class and its companion), or one in the call's own file; a class or trait wins over a same-named object. It is recorded as instantiates for a class, as a call for an object. The typed-receiver path no longer hands a Scala call another language's constructor. Real Java static methods are still reached from Scala. Validation: - resolution.test.ts: 5 cases, 4 red on main; the fifth (a Scala call to a real Java static) passes on both and guards the Java side. - A/B against main 81559dc (with #1950 and #1936): scalachess +77/-0, http4s +371/-1 (the one a retarget from a wrong defaults::Host to the Origin.Host case class), playframework +291/-1 (the one a retarget: Writeable's HttpEntity.Strict(...) from the Java play.http constructor to the Scala case class), play-samples +2 (two case-class applies #1950 unlinked from Java constructors); CMAK, click and gin identical. Every addition is a Scala case-class or object apply; sampled all right (Uci.Move, Header.Raw, H2Frame.Data, RemoteNode.Ip, ApplicationLoader.Context, Request.Connection over headers.Connection). - Cost (http4s, median of 3 interleaved fresh indexes, on main 69af19a): wall 8.6 s on main vs 7.8 s, process CPU 27.5 s vs 26.2 s, within noise. The A/B gave the same edges on both bases. Original PR #1951 by @danusha2345. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @danusha2345! This landed as #2924 with you as the commit author, unchanged apart from the CHANGELOG wording. On playframework it now links 291 Scala case-class applies like |
Problem
A Scala call to a nested case class or companion,
RemoteNode.Obfuscated("x"), can resolve to a Java class's explicit constructor. Scala nodes are namedOuter::Inner, so the qualified-name lookup misses a reference writtenOuter.Inner, and the call falls through two paths:play.mvc::WebSocket::Accepted::Accepted.def f(): T = T.Inner(x), the Scala local-declaration pattern reads the return annotation as the receiver's type, and the lookup returns the JavaInner::Innerconstructor.Fix
Outer::Innerwhen that's unambiguous: all matches in one file (class plus companion), or one in the caller's own file. It's recorded asinstantiates.Measured on playframework
ApplicationLoader.Context(...)→ the Java constructor while the ScalaContextis imported.instantiatesgained, all to Scala nested case classes (RemoteNode.Obfuscated/Ip/Unknown,NodePort.*,HttpChunk.*,ServerProvider.Context…). The call text matches in all 101, checked by script, and 30+ were checked against their imports by hand.Known limits, unchanged from
main:new JavaFoo(...)doesn't resolve to the Java class.JFoo(x)withoutnew) now stays unlinked rather than guessed.Tests
Three new cases in
__tests__/resolution.test.tsfail onmain. The control, a Scala → Java staticWebSocket.fromString, passes before and after. The full suite passes.🤖 Generated with Claude Code