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

Reply via email to