Author: Armin Rigo <[email protected]>
Branch:
Changeset: r75544:bbb6a5825c32
Date: 2015-01-26 23:21 +0100
http://bitbucket.org/pypy/pypy/changeset/bbb6a5825c32/
Log: Issue #1928 resolved
A missing detail about the logic of locals2fast when we compare it
with CPython's.
Thanks Krono for having found a test case that we could use!
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -524,9 +524,10 @@
# cellvars are values exported to inner scopes
# freevars are values coming from outer scopes
- freevarnames = list(self.pycode.co_cellvars)
+ # (see locals2fast for why CO_OPTIMIZED)
+ freevarnames = self.pycode.co_cellvars
if self.pycode.co_flags & consts.CO_OPTIMIZED:
- freevarnames.extend(self.pycode.co_freevars)
+ freevarnames = freevarnames + self.pycode.co_freevars
for i in range(len(freevarnames)):
name = freevarnames[i]
cell = self.cells[i]
@@ -555,7 +556,16 @@
self.setfastscope(new_fastlocals_w)
- freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars
+ freevarnames = self.pycode.co_cellvars
+ if self.pycode.co_flags & consts.CO_OPTIMIZED:
+ freevarnames = freevarnames + self.pycode.co_freevars
+ # If the namespace is unoptimized, then one of the
+ # following cases applies:
+ # 1. It does not contain free variables, because it
+ # uses import * or is a top-level namespace.
+ # 2. It is a class namespace.
+ # We don't want to accidentally copy free variables
+ # into the locals dict used by the class.
for i in range(len(freevarnames)):
name = freevarnames[i]
cell = self.cells[i]
diff --git a/pypy/interpreter/test/test_pyframe.py
b/pypy/interpreter/test/test_pyframe.py
--- a/pypy/interpreter/test/test_pyframe.py
+++ b/pypy/interpreter/test/test_pyframe.py
@@ -516,3 +516,21 @@
assert seen == [(1, f, firstline + 6, 'line', None),
(1, f, firstline + 7, 'line', None),
(1, f, firstline + 8, 'line', None)]
+
+ def test_locals2fast_freevar_bug(self):
+ import sys
+ def f(n):
+ class A(object):
+ def g(self):
+ return n
+ n = 42
+ return A()
+ res = f(10).g()
+ assert res == 10
+ #
+ def trace(*args):
+ return trace
+ sys.settrace(trace)
+ res = f(10).g()
+ sys.settrace(None)
+ assert res == 10
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit