fixhunt

ruff PLR1736: fix changes program behavior

fix-changes-behaviorlabelled safereal · highduplicate
Findings / 2026-10-17T21-04-33-755Z-llwi-ruff-PLR1736 / r1-p002ruff 0.17.16 → 5 lines2026-10-17 21:04 UTC

Hypothesis Nemotron 3 Super predicted to fire fired 1×

Fix captures list value at loop start; original uses rebound value, causing divergence when list is reassigned in outer scope during iteration.

Program

before
1lst = [10, 20]
2for i, x in enumerate(lst):
3 print(f'Before: lst[{i}]={lst[i]}, x={x}')
4 if i == 0:
5 lst = [99, 88] # Rebinding in outer scope
after
1lst = [10, 20]
2for i, x in enumerate(lst):
3 print(f'Before: lst[{i}]={x}, x={x}')
4 if i == 0:
5 lst = [99, 88] # Rebinding in outer scope

Output

stdout beforeexit 0
Before: lst[0]=10, x=10
Before: lst[1]=88, x=20
stdout afterexit 0
Before: lst[0]=10, x=10
Before: lst[1]=20, x=20
fired
1 before · 0 after
runs
each version twice, same file name, no network

Judge Nemotron 3 Ultra advisory real · high

The fix replaces `lst[i]` with the loop variable `x`, assuming the list is not mutated during iteration. However, the program rebinds `lst` to a new list `[99, 88]` when `i == 0`, so on the next iteration `lst[1]` reads from the new list (88) while `x` still yields the original element (20). This changes the program's observable output and is a silent wrong result in plausible code.

Explanation Nemotron 3 Super unverified

The original loop iterates over `enumerate(lst)`, where each iteration evaluates `lst` to get its current value; when `lst` is rebound inside the loop (to `[99, 88]`), subsequent iterations use that new list, so on the second iteration `lst[1]` yields `88`. The fix replaces `lst[i]` with `x`, which captures the element from the *original* enumeration snapshot taken at loop start (`[10, 20]`). Since `x` never changes per iteration, it always reflects the initial list’s values, ignoring the rebinding of `lst`. Thus the printed second element differs: `88` vs `20`. This change alters behavior because it decouples the index lookup from the dynamically updated list.

Reproduce

file
prog.py (the before program)
minimized program
r1-p002.py
evidence sheet
r1-p002.md
regression fixture
r1-p002.py the minimized program with a header stating the observed change, for the tool's test suite
python3 prog.py
ruff check --preview --isolated --select PLR1736 --fix prog.py
python3 prog.py

Upstream search GitHub issues Tavily Nemotron 3 Super + Ultra

PLR1736 fix · PLR1736 f-string list indexing · enumerate loop variable substitution · list rebinding during iteration

Details

program
Mutable local rebound in outer scope
hazard
Fix captures list value at loop start; original uses rebound value, causing divergence when list is reassigned in outer scope during iteration.
oracle
stdout before: Before: lst[0]=10, x=10 Before: lst[1]=88, x=20 stdout after: Before: lst[0]=10, x=10 Before: lst[1]=20, x=20
run
2026-10-17T21-04-33-755Z-llwi-ruff-PLR1736
generated program (6 lines) and the fix's diff
1lst = [10, 20]
2for i, x in enumerate(lst):
3 print(f'Before: lst[{i}]={lst[i]}, x={x}')
4 if i == 0:
5 lst = [99, 88] # Rebinding in outer scope
6 print(f'After: lst[{i}]={lst[i]}, x={x}')
--- orig.py	2026-10-17 17:04:47.037870536 -0400
+++ fixed.py	2026-10-17 17:04:47.205872429 -0400
@@ -1,6 +1,6 @@
 lst = [10, 20]
 for i, x in enumerate(lst):
-    print(f'Before: lst[{i}]={lst[i]}, x={x}')
+    print(f'Before: lst[{i}]={x}, x={x}')
     if i == 0:
         lst = [99, 88]  # Rebinding in outer scope
     print(f'After:  lst[{i}]={lst[i]}, x={x}')
rule documentation given to the models
# unnecessary-list-index-lookup (PLR1736)

Derived from the **Pylint** linter.

Fix is always available.

## What it does
Checks for index-based list accesses during `enumerate` iterations.

## Why is this bad?
When iterating over a list with `enumerate`, the current item is already
available alongside its index. Using the index to look up the item is
unnecessary.

## Example
```python
letters = ["a", "b", "c"]

for index, letter in enumerate(letters):
    print(letters[index])
```

Use instead:
```python
letters = ["a", "b", "c"]

for index, letter in enumerate(letters):
    print(letter)
```