You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Assertion rewriting reorders an operand when a later call rebinds its name #14820
The rewriter hoists sub-expressions into statements, but leaves a plain name as a bare load evaluated when the enclosing expression is assembled — that is, after the statements belonging to the operands that follow it. If one of those rebinds the name, the earlier operand sees a value Python would never have given it.
Python evaluates the left operand first, so this compares 0 == 0 and passes. Rewritten, it compares 99 == 0 and fails. Same with nonlocal, and in argument position:
#14447 fixes this class for the walrus operator, via a visit_operand() helper that freezes an operand into a temporary when a later operand rebinds its name. The detection is _walrus_targets(), which scans for ast.NamedExpr — so a function that rebinds through global/nonlocal is invisible to it.
The conservative fix is to freeze a bare name whenever anything later can execute arbitrary code (Call, Await, NamedExpr) rather than only when a walrus targets it. It is cheaper than it sounds: an operand that is already hoisted needs no freeze, so assert len(items) == expected is unchanged; only the bare-name-followed-by-a-call shape gains one assignment.
Tested on main (f306da747), Python 3.12. Related: #14445, #14819.
Activity
fix(rewrite): freeze operands against any later side effect (pytest-d…
fix(rewrite): freeze operands against any later side effect (pytest-d…
fix(rewrite): freeze operands against any later side effect (pytest-d…
fix(rewrite): freeze operands against any later side effect (pytest-d…
fix(rewrite): freeze operands against any later side effect (pytest-d…
fix(rewrite): freeze operands against any later side effect (pytest-d…
fix(rewrite): freeze operands against any later side effect (pytest-d…
fix(rewrite): freeze operands against any later side effect (pytest-d…