Files
codegraph/__tests__
Colby Mchenry b7e05f3ccd fix(dart): link a chained call only through its receiver's declared types (#750) (#2376)
The Dart extractor keeps one receiver level, so the later links of a call
chain reach the resolver by their bare name (`Provider.autoDispose.family(…)`
→ `family`, `events.map(mapper).transform(…)` → `transform`). They then fell
to name matching and bound to whichever project method shared the name: on
felangel/bloc a Stream's `transform` went to angular_bloc's
`BlocPipe::transform`, and on rrousselGit/riverpod every
`X.autoDispose.family(…)` went to one builder's `family` whatever X was.

A chain link now reaches only the member of what the chain before it
evaluates to, typed from evidence: the head (a type, a constructor call, a
string, `this` / `super`, an import prefix, a local, parameter, field or
getter with a declared type) and each link's declared type (a method's or
getter's return type with the method's own type parameters substituted, a
field's or abstract getter's type, a static constant's initializer). A lookup
nothing declared answers for hands back its one type argument
(`context.read<LoginCubit>()`). Without evidence it links nothing.

Along the way: an annotated extension (`@internal extension X on Y`) is
recognized as one, so its members reach member reads and chains; `super.m()`
reaches the superclass's method instead of the caller itself; an extension
on a type parameter of its own applies to the project's types; a spread's
`...foo()` is a receiver-less call.

Validated before/after with the native kernel: bloc 337 name-only chain
edges on main → 123 kept (now typed), 106 retargeted, 106 removed (68 on a
typed receiver lacking the member), +75 `super.` calls; riverpod 1,254 →
171 kept, 383 retargeted, 696 removed (137 provably wrong), +263. Kernel and
wasm graphs are identical with the fix.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 14:36:56 +00:00
..