feat(python-scope): nested tuple destructuring for enumerate(d.items())

Two more for-loop typeBinding patterns:

- `for i, (k, v) in enumerate(d.items())` — nested tuple destructuring
  where v is the value of the dict's items() yield.
- `for v in d.values()` — explicit values() form (companion to items).

Both bind the loop var to the dict identifier; the chain-follow
unwraps via the dict-aware stripGeneric to the value type.

Verification:
- Flag-off: 191/191 (identical baseline).
- Flag-on: 5 fail / 186 pass (was 6/185; +1 nested tuple test).
- tsc --noEmit clean.
This commit is contained in:
Gergo Magyar 2026-04-20 12:11:04 +01:00
parent a446751045
commit f226478ee1
2 changed files with 53 additions and 0 deletions

View file

@ -167,6 +167,33 @@ export const PYTHON_SCOPE_QUERY = `
attribute: (identifier) @_items))
(#eq? @_items "items")) @type-binding.alias
;; for i, (k, v) in enumerate(d.items()) nested tuple destructuring.
;; Bind v (last id of the nested tuple) to d (the dict).
(for_statement
left: (pattern_list
(identifier)
(tuple_pattern
(identifier)
(identifier) @type-binding.name))
right: (call
function: (identifier) @_enum
arguments: (argument_list
(call
function: (attribute
object: (identifier) @type-binding.type
attribute: (identifier) @_items))))
(#eq? @_enum "enumerate")
(#eq? @_items "items")) @type-binding.alias
;; for v in d.values() bind v to d (dict-strip yields value type).
(for_statement
left: (identifier) @type-binding.name
right: (call
function: (attribute
object: (identifier) @type-binding.type
attribute: (identifier) @_values))
(#eq? @_values "values")) @type-binding.alias
;; Type bindings (variable annotations: \`u: User\` / \`u: User = x\`)
(assignment
left: (identifier) @type-binding.name

View file

@ -180,6 +180,32 @@
attribute: (identifier) @_items))
(#eq? @_items "items")) @type-binding.alias
; for i, (k, v) in enumerate(d.items()) — nested tuple destructuring.
(for_statement
left: (pattern_list
(identifier)
(tuple_pattern
(identifier)
(identifier) @type-binding.name))
right: (call
function: (identifier) @_enum
arguments: (argument_list
(call
function: (attribute
object: (identifier) @type-binding.type
attribute: (identifier) @_items))))
(#eq? @_enum "enumerate")
(#eq? @_items "items")) @type-binding.alias
; for v in d.values() — bind v to d (dict-strip yields value type).
(for_statement
left: (identifier) @type-binding.name
right: (call
function: (attribute
object: (identifier) @type-binding.type
attribute: (identifier) @_values))
(#eq? @_values "values")) @type-binding.alias
; ─── Type bindings: function return-type annotations ─────────────────────
;
; `def get_user() -> User:` — binds the function's NAME to its return