Skip to content

fix: add Python enumerate() for-loop support with nested tuple patterns#356

Merged
magyargergo merged 1 commit into
abhigyanpatwari:mainfrom
cnighut:feat/enumerate-support
Mar 18, 2026
Merged

fix: add Python enumerate() for-loop support with nested tuple patterns#356
magyargergo merged 1 commit into
abhigyanpatwari:mainfrom
cnighut:feat/enumerate-support

Conversation

@cnighut

@cnighut cnighut commented Mar 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add support for enumerate() in Python for-loops with proper type resolution
  • Handle nested tuple patterns: for i, (k, v) in enumerate(d.items())
  • Handle parenthesized tuples: for (k, v) in enumerate(users)

Changes

  • Extract extractMethodCall() helper to deduplicate method call parsing
  • Extract collectPatternIdentifiers() to recursively collect identifiers from patterns
  • Add unit tests for TypeEnv bindings
  • Add integration tests verifying CALLS edges in the graph

Test plan

  • Unit tests pass (npm test -- -t "enumerate")
  • Integration tests pass (npm run test:integration -- -t "enumerate")
  • All Python tests pass (npm test -- -t "Python")

- Handle `for i, k, v in enumerate(d.items())` — flat pattern
- Handle `for i, (k, v) in enumerate(d.items())` — nested tuple_pattern
- Handle `for (k, v) in enumerate(users)` — parenthesized tuple as top-level

Extract helper functions for cleaner code:
- `extractMethodCall()` — deduplicate method call parsing
- `collectPatternIdentifiers()` — recursively collect identifiers from patterns

Add unit tests for TypeEnv and integration tests verifying CALLS edges.

Made-with: Cursor
@vercel

vercel Bot commented Mar 18, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the NexusCore Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions

Copy link
Copy Markdown
Contributor

CI Report

All checks passed

Pipeline Status

Stage Status Details
✅ Typecheck success tsc --noEmit
✅ Unit Tests success 3 platforms
✅ Integration success 3 OS x 4 groups = 12 jobs

Test Results

Suite Tests Passed Failed Skipped Duration
Unit 1571 1516 0 1 8s
Integration 1207 1185 0 19 52s
Total 2778 2701 0 20 60s

✅ All 2701 tests passed

20 test(s) skipped — expand for details

Integration:

  • hooks e2e ('Plugin') > directory without .gitnexus > ignores PostToolUse when no .gitnexus directory exists
  • hooks e2e ('Plugin') > directory without .gitnexus > ignores PreToolUse when no .gitnexus directory exists
  • Python match/case as-pattern type binding > resolves u.save() to User#save via match/case as-pattern binding
  • Python match/case as-pattern type binding > does NOT resolve u.save() to Repo#save (negative disambiguation)
  • Swift constructor-inferred type resolution > detects User and Repo classes, both with save methods
  • Swift constructor-inferred type resolution > resolves user.save() to Models/User.swift via constructor-inferred type
  • Swift constructor-inferred type resolution > resolves repo.save() to Models/Repo.swift via constructor-inferred type
  • Swift constructor-inferred type resolution > emits exactly 2 save() CALLS edges (one per receiver type)
  • Swift self resolution > detects User and Repo classes, each with a save function
  • Swift self resolution > resolves self.save() inside User.process to User.save, not Repo.save
  • Swift parent resolution > detects BaseModel and User classes plus Serializable protocol
  • Swift parent resolution > emits EXTENDS edge: User → BaseModel
  • Swift parent resolution > emits IMPLEMENTS edge: User → Serializable (protocol conformance)
  • Swift cross-file User.init() inference > resolves user.save() via User.init(name:) inference
  • Swift cross-file User.init() inference > resolves user.greet() via User.init(name:) inference
  • Swift return type inference > detects User class and getUser function
  • Swift return type inference > detects save function on User (Swift class methods are Function nodes)
  • Swift return type inference > resolves user.save() to User#save via return type of getUser() -> User
  • Swift return-type inference via function return type > resolves user.save() to User#save via return type of getUser()
  • Swift return-type inference via function return type > user.save() does NOT resolve to Repo#save
  • Swift return-type inference via function return type > resolves repo.save() to Repo#save via return type of getRepo()

Unit:

  • buildTypeEnv > for-loop element type inference (Tier 1c) — Java > does not infer type when iterable has no annotation
  • buildTypeEnv > previously-skipped limitations (now resolved) > TS destructured for-of: for (const [k, v] of entries) — last-child heuristic
  • buildTypeEnv > previously-skipped limitations (now resolved) > Python tuple unpacking: for key, value in dict.items() — call iterable + pattern_list
  • buildTypeEnv > previously-skipped limitations (now resolved) > Python enumerate(dict.items()): for i, k, v — skips int index, binds value var to User
  • buildTypeEnv > previously-skipped limitations (now resolved) > Python enumerate(dict.items()) with nested tuple: for i, (k, v) — binds v to User
  • buildTypeEnv > previously-skipped limitations (now resolved) > Python enumerate with parenthesized tuple: for (k, v) in enumerate(users) — binds v to User
  • buildTypeEnv > previously-skipped limitations (now resolved) > TS instanceof narrowing: if (x instanceof User) — first-writer-wins, not block-scoped
  • buildTypeEnv > previously-skipped limitations (now resolved) > Rust for with .iter(): for user in users.iter() — call_expression iterable
  • buildTypeEnv > method-aware type arg selection (.keys() vs .values()) > TS for-of map.values() resolves to value type (User)
  • buildTypeEnv > method-aware type arg selection (.keys() vs .values()) > TS for-of map.keys() resolves to key type (string)
  • buildTypeEnv > method-aware type arg selection (.keys() vs .values()) > Python for key in data.keys() resolves to key type (str)
  • buildTypeEnv > method-aware type arg selection (.keys() vs .values()) > Python for user in data.values() resolves to value type (User)
  • buildTypeEnv > method-aware type arg selection (.keys() vs .values()) > Rust for key in map.keys() resolves to key type (String)
  • buildTypeEnv > method-aware type arg selection (.keys() vs .values()) > Rust for user in map.values() resolves to value type (User)
  • buildTypeEnv > container descriptor-aware type arg selection > HashMap.keys() resolves to key type (String) via descriptor
  • buildTypeEnv > container descriptor-aware type arg selection > HashMap.values() resolves to value type (User) via descriptor
  • buildTypeEnv > container descriptor-aware type arg selection > Vec.iter() resolves to element type (User) — arity 1 always returns last
  • buildTypeEnv > container descriptor-aware type arg selection > unknown container falls back to last-arg heuristic
  • buildTypeEnv > for-loop Phase 2 enhancements > TS object destructuring skip: for (const { id, name } of users) — no binding produced
  • buildTypeEnv > for-loop Phase 2 enhancements > TS member access: for (const user of this.users) with users: User[] param — resolves
  • buildTypeEnv > for-loop Phase 2 enhancements > Python member access: for user in self.users with users: List[User] param — resolves
  • buildTypeEnv > for-loop Phase 2 enhancements > C++ structured bindings: for (auto& [key, value] : map) with map<string, User> param — binds value
  • buildTypeEnv > for-loop Phase 2 enhancements > C++ structured bindings: exact App.cpp fixture — binds user and repo
  • buildTypeEnv > known limitations (documented skip tests) > Ruby block parameter: users.each { |user| } — closure param inference, different feature
  • buildTypeEnv > Kotlin when/is pattern binding (Phase 6) > when (x) { is User -> } binds x to User
  • buildTypeEnv > Kotlin when/is pattern binding (Phase 6) > when (x) { is User -> ...; is Admin -> ... } — last arm overwrites (allowPatternBindingOverwrite)
  • buildTypeEnv > Kotlin when/is pattern binding (Phase 6) > when (x) { else -> } — no type check, no pattern binding produced
  • buildTypeEnv > Kotlin for-loop HashMap.values resolution (Phase 6) > for (user in data.values) binds user to User via HashMap<String, User>
  • buildTypeEnv > Kotlin for-loop HashMap.values resolution (Phase 6) > for (user in users) binds user to User via List param
  • buildTypeEnv > Java switch pattern variable (Phase 6) > switch (obj) { case User u -> } binds u to User
  • buildTypeEnv > Java switch pattern variable (Phase 6) > switch (obj) { case User u -> ...; case Admin a -> ... } — both bind
  • buildTypeEnv > Java switch pattern variable (Phase 6) > switch (x) { case 42 -> ... } — no pattern variable, no binding
  • buildTypeEnv > Java switch pattern variable (Phase 6) > obj instanceof User user — regression: still works after type_pattern addition
  • buildTypeEnv > new container descriptors (Phase 6.1) > Collection resolves element type via descriptor (arity 1)
  • buildTypeEnv > new container descriptors (Phase 6.1) > MutableMap<String, User>.values() resolves to User via descriptor (arity 2)
  • buildTypeEnv > new container descriptors (Phase 6.1) > MutableList resolves element type via descriptor
  • buildTypeEnv > new container descriptors (Phase 6.1) > SortedSet resolves element type via descriptor (C#)
  • buildTypeEnv > new container descriptors (Phase 6.1) > Stream resolves element type via descriptor (Java)
  • buildTypeEnv > C# recursive_pattern binding (Phase 6.1) > obj is User { Name: "Alice" } u — binds u to User
  • buildTypeEnv > C# recursive_pattern binding (Phase 6.1) > switch expression with recursive_pattern — binds r to Repo
  • buildTypeEnv > C# recursive_pattern binding (Phase 6.1) > recursive_pattern without designation — no pattern binding produced
  • buildTypeEnv > C# await foreach (Phase 6.1) > await foreach (var user in users) — same node type as foreach, resolves element type
  • buildTypeEnv > C# await foreach (Phase 6.1) > foreach (var user in this.data.Values) — nested member access with container property
  • buildTypeEnv > TypeScript class field declaration (Phase 6.1) > class field with array type — for-loop resolves element type via declarationTypeNodes
  • buildTypeEnv > TypeScript class field declaration (Phase 6.1) > class field with generic type annotation — binds field name to base type
  • buildTypeEnv > PHP foreach $this->property (Phase 7.4 — Strategy C) > resolves loop variable from @var User[] property without @param workaround
  • buildTypeEnv > PHP foreach $this->property (Phase 7.4 — Strategy C) > does not bind from unknown $this->property (conservative)
  • buildTypeEnv > PHP foreach $this->property (Phase 7.4 — Strategy C) > multi-class file: resolves correct property for each class
  • buildTypeEnv > match arm scoping — first-writer-wins regression > Rust: first match arm binding wins, later arms do not overwrite
  • buildTypeEnv > performance optimizations — coverage for new code paths > fastStripNullable: passes through simple identifier without stripping
  • buildTypeEnv > performance optimizations — coverage for new code paths > fastStripNullable: strips nullable union type via full stripNullable
  • buildTypeEnv > performance optimizations — coverage for new code paths > fastStripNullable: rejects bare nullable keyword
  • buildTypeEnv > performance optimizations — coverage for new code paths > fastStripNullable: strips optional type suffix
  • buildTypeEnv > performance optimizations — coverage for new code paths > SKIP_SUBTREE_TYPES: string literal subtrees do not affect type extraction
  • buildTypeEnv > performance optimizations — coverage for new code paths > interestingNodeTypes: non-declaration nodes skip extractTypeBinding

Code Coverage

Combined (Unit + Integration)

Metric Coverage Covered Base Delta Status
Statements 61.73% 7001/11341 47.27% 📈 +14.5 🟢 ████████████░░░░░░░░
Branches 55.77% 4799/8604 42.26% 📈 +13.5 🟢 ███████████░░░░░░░░░
Functions 61.01% 601/985 46.38% 📈 +14.6 🟢 ████████████░░░░░░░░
Lines 63.7% 6257/9822 48.88% 📈 +14.8 🟢 ████████████░░░░░░░░
Coverage breakdown by test suite

Unit Tests

Metric Coverage Covered Base Delta Status
Statements 47.38% 5374/11341 47.27% 📈 +0.1 🟢 █████████░░░░░░░░░░░
Branches 42.36% 3645/8604 42.26% 📈 +0.1 🟢 ████████░░░░░░░░░░░░
Functions 46.49% 458/985 46.38% 📈 +0.1 🟢 █████████░░░░░░░░░░░
Lines 49.01% 4814/9822 48.88% 📈 +0.1 🟢 █████████░░░░░░░░░░░

Integration Tests

Metric Coverage Covered Base Delta Status
Statements 47.05% 5337/11341 47.27% 📉 -0.2 🔴 █████████░░░░░░░░░░░
Branches 44.29% 3811/8604 42.26% 📈 +2.0 🟢 ████████░░░░░░░░░░░░
Functions 44.56% 439/985 46.38% 📉 -1.8 🔴 ████████░░░░░░░░░░░░
Lines 48.19% 4734/9822 48.88% 📉 -0.7 🔴 █████████░░░░░░░░░░░

📋 View full run · Generated by CI

@cnighut cnighut changed the title feat: add Python enumerate() for-loop support with nested tuple patterns fix: add Python enumerate() for-loop support with nested tuple patterns Mar 18, 2026
Repository owner deleted a comment from claude Bot Mar 18, 2026
@magyargergo magyargergo merged commit aa1bab5 into abhigyanpatwari:main Mar 18, 2026
21 of 22 checks passed
motolese pushed a commit to motolese/datamoto-gitnexus that referenced this pull request Apr 23, 2026
…rns (abhigyanpatwari#356)

- Handle `for i, k, v in enumerate(d.items())` — flat pattern
- Handle `for i, (k, v) in enumerate(d.items())` — nested tuple_pattern
- Handle `for (k, v) in enumerate(users)` — parenthesized tuple as top-level

Extract helper functions for cleaner code:
- `extractMethodCall()` — deduplicate method call parsing
- `collectPatternIdentifiers()` — recursively collect identifiers from patterns

Add unit tests for TypeEnv and integration tests verifying CALLS edges.

Made-with: Cursor

Co-authored-by: chirag-nighut <chiragnighut@gmail.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.

2 participants