[Python-checkins] r51109 - in python/trunk: Lib/compiler/pycodegen.py Lib/test/test_compiler.py Misc/NEWS

neil.schemenauer python-checkins at python.org
Fri Aug 4 18:20:31 CEST 2006


Author: neil.schemenauer
Date: Fri Aug  4 18:20:30 2006
New Revision: 51109

Modified:
   python/trunk/Lib/compiler/pycodegen.py
   python/trunk/Lib/test/test_compiler.py
   python/trunk/Misc/NEWS
Log:
Fix the 'compiler' package to generate correct code for MAKE_CLOSURE.
In the 2.5 development cycle, MAKE_CLOSURE as changed to take free
variables as a tuple rather than as individual items on the stack.
Closes patch #1534084.


Modified: python/trunk/Lib/compiler/pycodegen.py
==============================================================================
--- python/trunk/Lib/compiler/pycodegen.py	(original)
+++ python/trunk/Lib/compiler/pycodegen.py	Fri Aug  4 18:20:30 2006
@@ -382,16 +382,7 @@
         self.set_lineno(node)
         for default in node.defaults:
             self.visit(default)
-        frees = gen.scope.get_free_vars()
-        if frees:
-            for name in frees:
-                self.emit('LOAD_CLOSURE', name)
-            self.emit('LOAD_CONST', gen)
-            self.emit('MAKE_CLOSURE', len(node.defaults))
-        else:
-            self.emit('LOAD_CONST', gen)
-            self.emit('MAKE_FUNCTION', len(node.defaults))
-
+        self._makeClosure(gen, len(node.defaults))
         for i in range(ndecorators):
             self.emit('CALL_FUNCTION', 1)
 
@@ -405,14 +396,7 @@
         for base in node.bases:
             self.visit(base)
         self.emit('BUILD_TUPLE', len(node.bases))
-        frees = gen.scope.get_free_vars()
-        for name in frees:
-            self.emit('LOAD_CLOSURE', name)
-        self.emit('LOAD_CONST', gen)
-        if frees:
-            self.emit('MAKE_CLOSURE', 0)
-        else:
-            self.emit('MAKE_FUNCTION', 0)
+        self._makeClosure(gen, 0)
         self.emit('CALL_FUNCTION', 0)
         self.emit('BUILD_CLASS')
         self.storeName(node.name)
@@ -644,22 +628,25 @@
         self.newBlock()
         self.emit('POP_TOP')
 
-    def visitGenExpr(self, node):
-        gen = GenExprCodeGenerator(node, self.scopes, self.class_name,
-                                   self.get_module())
-        walk(node.code, gen)
-        gen.finish()
-        self.set_lineno(node)
+    def _makeClosure(self, gen, args):
         frees = gen.scope.get_free_vars()
         if frees:
             for name in frees:
                 self.emit('LOAD_CLOSURE', name)
+            self.emit('BUILD_TUPLE', len(frees))
             self.emit('LOAD_CONST', gen)
-            self.emit('MAKE_CLOSURE', 0)
+            self.emit('MAKE_CLOSURE', args)
         else:
             self.emit('LOAD_CONST', gen)
-            self.emit('MAKE_FUNCTION', 0)
+            self.emit('MAKE_FUNCTION', args)
 
+    def visitGenExpr(self, node):
+        gen = GenExprCodeGenerator(node, self.scopes, self.class_name,
+                                   self.get_module())
+        walk(node.code, gen)
+        gen.finish()
+        self.set_lineno(node)
+        self._makeClosure(gen, 0)
         # precomputation of outmost iterable
         self.visit(node.code.quals[0].iter)
         self.emit('GET_ITER')

Modified: python/trunk/Lib/test/test_compiler.py
==============================================================================
--- python/trunk/Lib/test/test_compiler.py	(original)
+++ python/trunk/Lib/test/test_compiler.py	Fri Aug  4 18:20:30 2006
@@ -104,6 +104,19 @@
         self.assertEquals(flatten([1, [2]]), [1, 2])
         self.assertEquals(flatten((1, (2,))), [1, 2])
 
+    def testNestedScope(self):
+        c = compiler.compile('def g():\n'
+                             '    a = 1\n'
+                             '    def f(): return a + 2\n'
+                             '    return f()\n'
+                             'result = g()',
+                             '<string>',
+                             'exec')
+        dct = {}
+        exec c in dct
+        self.assertEquals(dct.get('result'), 3)
+
+        
 NOLINENO = (compiler.ast.Module, compiler.ast.Stmt, compiler.ast.Discard)
 
 ###############################################################################

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Fri Aug  4 18:20:30 2006
@@ -28,6 +28,9 @@
 - Bug #1531405, format_exception no longer raises an exception if
   str(exception) raised an exception.
 
+- Fix a bug in the ``compiler`` package that caused invalid code to be
+  generated for nested functions.
+
 
 Extension Modules
 -----------------


More information about the Python-checkins mailing list