Skip to content

feat(resolution): conformance-aware chained-method resolution (#750)#754

Merged
colbymchenry merged 2 commits into
mainfrom
fix/750-conformance-aware-resolution
Jun 9, 2026
Merged

feat(resolution): conformance-aware chained-method resolution (#750)#754
colbymchenry merged 2 commits into
mainfrom
fix/750-conformance-aware-resolution

Conversation

@colbymchenry

Copy link
Copy Markdown
Owner

Part of #750. A general resolver upgrade that makes chained-call resolution conformance-aware — it benefits the already-shipped Java/Kotlin/C# chained-call fixes and is a prerequisite for Swift.

Problem

The chained-call mechanism (#751/#752/#753) validates the chained method against the exact return type. But a chained method is often inherited from a superclass or declared on an interface/protocol the receiver conforms to — e.g. Either.Right(x).combine(...), where Right is a sealed subclass and combine lives on the parent Either. Those chains found no edge even though the type was known.

Fix

  • resolveMethodOnType now falls back to walking the receiver type's supertypes (a new context.getSupertypes, backed by the resolved implements/extends edges) — transitively, depth-capped — when the method isn't a direct member. Still validated: the edge is created only when a supertype genuinely declares the method, so a wrong inference still yields no edge.
  • Because those edges don't exist during the single-pass resolve, the chained refs that fail are collected in-memory and re-resolved in a second pass (resolveChainedCallsViaConformance, wired into indexAll + sync after edges are built). The batched resolver deletes unresolved refs from the DB, so they're carried in-memory rather than re-read.

Validation

EXTRACTION_VERSION 8 → 9.

🤖 Generated with Claude Code

colbymchenry and others added 2 commits June 9, 2026 01:22
A chained static-factory/fluent call whose method lives on a SUPERTYPE the
receiver conforms to — a protocol-extension method (Swift), an interface default
method, or an inherited superclass method — now resolves. resolveMethodOnType
falls back to walking the return type's implements/extends edges (via the new
context.getSupertypes) when the method isn't a direct member. Because those edges
don't exist during the single-pass resolution, a second pass
(resolveChainedCallsViaConformance) re-resolves the deferred chained refs after
edges are built. Still validated, so a wrong inference yields no edge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@colbymchenry colbymchenry merged commit 48d4654 into main Jun 9, 2026
@colbymchenry colbymchenry deleted the fix/750-conformance-aware-resolution branch June 9, 2026 05:38
colbymchenry added a commit that referenced this pull request Jun 9, 2026
…nsion naming (#750) (#755)

Completes Swift in the #750 chained-call series (after Java #751, Kotlin #752,
C# #753, conformance #754). Two parts:

1. Swift chained-call resolution (the #645/#608 mechanism): capture Swift return
   types (positional, member types -> last segment), encode capitalized-receiver
   chains `Foo.make().draw()` / `Foo(args).draw()`, resolve+validate via the
   shared matchDottedCallChain (+ constructor branch). Fixes the decoy wrong-edge
   bug where a chained method dropped to a bare name and attached to a same-named
   method on an unrelated class.

2. Nested-type extension naming fix: `extension KF.Builder: KFOptionSetter` parsed
   as a class_declaration named `KF.Builder` (dot) — inconsistent with the type's
   own declaration `KF::Builder` (name `Builder`) — so the extension's conformances
   and members were invisible to a chained call on the type. A Swift resolveName
   now names a nested-type extension by its last segment (`Builder`), so its
   `implements`/`extends` edges and methods are found by the supertype walk
   (conformance #754) and the simple-name method match.

Validated: synthetic decoy + args + constructor + absent-method tests; full suite
green; nested-extension repro (`KF.url().onSuccess()` resolves via conformance to
the protocol method). Real-repo A/B vs main (conformance) — Alamofire and
Kingfisher both **0 added / 0 removed, node count unchanged**: NEUTRAL and SAFE.
The prior -168 Kingfisher regression (from the naming inconsistency) is eliminated;
Swift's unique-named fluent methods already resolved by bare name, so the chain
path lands the same edges — the value here is decoy-collision correctness, the
nested-extension naming fix, and consistency with the other four languages.
EXTRACTION_VERSION 9 -> 10.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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