feat(python-scope): for-loop call-iterable typeBinding

Adds `(for_statement left: (identifier) right: (call function:
(identifier)))` to the typeBinding capture set. Combined with Unit 3's
return-type capture and the cross-file return-type propagation pass,
this makes `for u in get_users(): u.save()` resolve to `User.save`
even when `get_users` is imported from another module.

Captured as `@type-binding.alias` (rawName = function identifier,
without parens) so the existing chain-follow walks the alias to the
function's return-type binding without any new code path.

Verification:
- Flag-off: 191/191 (identical baseline).
- Flag-on: 12 fail / 179 pass (was 16/175; +4 for-loop call-iterable
  tests across get_users / get_repos fixtures).
- tsc --noEmit clean.
This commit is contained in:
Gergo Magyar 2026-04-20 10:25:32 +01:00
parent 38df89d03e
commit 6d220cfc85
2 changed files with 20 additions and 0 deletions

View file

@ -108,6 +108,17 @@ export const PYTHON_SCOPE_QUERY = `
left: (identifier) @type-binding.name
right: (identifier) @type-binding.type) @type-binding.alias
;; For-loop iterable of a free-call result:
;; def get_users() -> list[User]: ...
;; for u in get_users(): # u: get_users → User via chain follow
;; u.save()
;; Captures the call's function identifier as the rawName. With
;; \`propagateImportedReturnTypes\`, this works cross-file too.
(for_statement
left: (identifier) @type-binding.name
right: (call
function: (identifier) @type-binding.type)) @type-binding.alias
;; Type bindings (variable annotations: \`u: User\` / \`u: User = x\`)
(assignment
left: (identifier) @type-binding.name

View file

@ -125,6 +125,15 @@
left: (identifier) @type-binding.name
type: (type) @type-binding.type) @type-binding.annotation
; For-loop iterable of a free-call result: `for u in get_users()` —
; binds `u → get_users` so the chain post-pass follows it through
; `get_users`'s return-type annotation (cross-file via
; `propagateImportedReturnTypes`).
(for_statement
left: (identifier) @type-binding.name
right: (call
function: (identifier) @type-binding.type)) @type-binding.alias
; ─── Type bindings: function return-type annotations ─────────────────────
;
; `def get_user() -> User:` — binds the function's NAME to its return