GitNexus/gitnexus/test
Abhigyan Patwari 65b101407e
fix(rust): type locals from module-qualified factory calls (#3657)
* fix(scope): follow namespace factory return types and record untyped drops

`import mod as rp; x = rp.make(); x.m()` lost the receiver type even when
`make` is declared `-> C`: `x` was bound to the raw dotted name `rp.make`,
and nothing followed a dotted name to a function's return type. The inline
`rp.make().m()` failed the same way in the compound resolver, which read
`ns.f()` only as a construction.

Resolve `ns.f` to `f`'s return annotation when `ns` is a namespace import,
the fact `propagateImportedReturnTypes` already mirrors for a named import.
The post-finalize chain follow uses it for bindings and the compound
resolver for inline calls. Only sites that emitted nothing change: the
full lang-resolution corpus emits the identical 2,838 CALLS/ACCESSES edges.

Record the drops that left `impact` at "exact":
- a plain receiver bound to a namespace function with no usable return type
  (`x = ns.untyped()`);
- an outer call whose `file:line:col` key a resolved inner site already
  claimed (`ns.untyped().m()`, `s.repo.Delete(id)`). Only a duplicate
  capture of the same member hides a drop now.

Receiver baseline: call drops 128 -> 151, reads 44 -> 48, ten shape-arm
cells INVISIBLE-GAP -> VISIBLE-GAP; every new drop has no CALLS edge to its
member (BASELINE.md lists them). The python.factory-qualified accuracy gap
is removed; the python-scope fingerprint and capture golden gain the new
fixture only.

Fixes #3498

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(dart): type locals from prefixed-import factory calls

`import 'mod.dart' as rp; final x = rp.make(); x.m()` gave `x` no type:
local call inference accepted only a bare callee (`Callee()`), and the
prefix-stripping type normalizer would have reduced `rp.make` to `make`.

Bind a local initialized by exactly `prefix.member(...)` (direct or
awaited) to the dotted callee and keep its prefix, so the shared chain
follow types it from the namespace function's return annotation. Only
call-derived bindings keep the prefix; annotated `prefix.Type` spellings
are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(zig): type locals from namespace-module factory calls

`const rp = @import("mod.zig"); const x = rp.make(); x.m()` bound `x` to
the namespace handle `rp` itself: the call-return rule reads a non-value
head as the type being constructed (`Counter.init()`), and import bindings
are not values. The member name was gone before the shared chain follow
could use the new namespace return-type lookup.

For a module-level handle on a lowercase file (a namespace module, by Zig
convention), bind the dotted callee `rp.make` so the shared chain follow
types it from `make`'s return annotation. File-struct handles
(`@import("Page.zig")`, any spelling of the handle) keep naming the
struct, so `Page.init()` is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(bench): rebaseline captures and receiver counts for Dart and Zig

- receiver-resolution: the Dart fixture's untyped factory adds one call
  drop (151 -> 152); every typed form in the Dart and Zig fixtures resolves.
- scope-capture (dart): two existing dart-method-enrichment locals
  initialized by `obj.method()` / `Type.method()` gain a call-derived
  binding, plus the new fixture's captures. A full lang-resolution A/B
  emits the identical edges outside the new fixtures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(rust): type locals from module-qualified factory calls

`mod modx; use crate::modx as rp; let x = rp::make(); x.m()` left `x`
untyped although `make` is declared `-> C`. The call-return rule kept only
the text before the first `::` (the `Foo::new()` idiom), so `x` was bound
to the module `rp` and the function name was lost. `modx::make()` and
`crate::modx::make()` failed the same way, and the inline `rp::make().m()`
failed in the compound resolver, which cannot split a `::` path. With a
`let modx = Other;` in scope, `modx::make()` even typed `x` as `Other` and
emitted a wrong `Other.m` edge.

- Rust keeps the whole callee path when every segment is lower-case: a
  module function, by rustc's lint-enforced casing. `Foo::new()` and
  `Self::new()` still read as the type.
- New `ScopeResolver.resolveQualifiedCallee` hook. The shared chain follow,
  the compound call branch and the drop recorder hand a callee text no
  scope binds to the provider, which returns the callable it names; the
  shared side reads that callable's return annotation by definition
  identity and never splits the path. Rust answers with the module-tree
  walk behind `resolveQualifiedFreeCall`, so a call's type and its CALLS
  edge come from the same resolution.
- A receiver bound to an in-program module function with no return
  annotation (`x = rp::untyped()`) records a `receiver-unresolved` drop,
  as #3498 does for `ns.untyped()`.
- `rp::make()` did not resolve as a call either: the module-name filter
  rejected the alias `rp`, and under Cargo the import binds the module's
  `mod modx;` declaration rather than `modx.rs`. The `use` candidate now
  admits an alias that names a module and reads a module from its
  top-level declaration.

A full lang-resolution A/B against the parent emits identical CALLS and
ACCESSES edges outside the new fixture, except one new correct edge:
`rust-ambiguous` `main -> models::Handler.handle`, typed from
`let h = services::create_handler()`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(bench): rebaseline rust captures and receiver counts

- receiver-resolution: the new rust-qualified-factory-return fixture's two
  untyped sites (`x = rp::untyped(); x.m()` and inline
  `modx::untyped().m()`) are each a call and a callee-position read drop:
  call drops 152 -> 154, reads 48 -> 50, all kinds 220 -> 224. No other
  drop moves in a same-corpus A/B, and shape-arm cells are unchanged.
- scope-capture (rust): corpus growth only. emitRustScopeCaptures is
  untouched, and parking the new fixture reproduces the prior fingerprint
  byte-for-byte; it adds 131 capture groups and 3 fixture entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* perf(scope): reuse qualified call file sets

* docs(scope): clarify finalized type refinement

* fix(rust): scope generic alias parameters

---------

Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 09:05:48 +00:00
..
fixtures fix(rust): type locals from module-qualified factory calls (#3657) 2026-10-22 09:05:48 +00:00
helpers fix(taint): report inline and factory handler flows (#3612) 2026-10-17 20:22:58 +00:00
integration fix(rust): type locals from module-qualified factory calls (#3657) 2026-10-22 09:05:48 +00:00
unit fix(rust): type locals from module-qualified factory calls (#3657) 2026-10-22 09:05:48 +00:00
utils feat(storage): add configurable index storage and content retention tiers (#3060) 2026-09-12 20:31:55 +00:00