diff options
author | Neil Schemenauer <nascheme@enme.ucalgary.ca> | 2006-08-04 16:20:30 (GMT) |
---|---|---|
committer | Neil Schemenauer <nascheme@enme.ucalgary.ca> | 2006-08-04 16:20:30 (GMT) |
commit | 06ded09d4048bf44ce9b61c82494cf0a0825412c (patch) | |
tree | 5aa766517b8a84d0d4d048dcd3c62f78638da8e0 | |
parent | 45381938e940279df3962f6ebe01efb8375198a3 (diff) | |
download | cpython-06ded09d4048bf44ce9b61c82494cf0a0825412c.zip cpython-06ded09d4048bf44ce9b61c82494cf0a0825412c.tar.gz cpython-06ded09d4048bf44ce9b61c82494cf0a0825412c.tar.bz2 |
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.
-rw-r--r-- | Lib/compiler/pycodegen.py | 39 | ||||
-rw-r--r-- | Lib/test/test_compiler.py | 13 | ||||
-rw-r--r-- | Misc/NEWS | 3 |
3 files changed, 29 insertions, 26 deletions
diff --git a/Lib/compiler/pycodegen.py b/Lib/compiler/pycodegen.py index d5d68aa..e3667b5 100644 --- a/Lib/compiler/pycodegen.py +++ b/Lib/compiler/pycodegen.py @@ -382,16 +382,7 @@ class CodeGenerator: 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 @@ class CodeGenerator: 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 @@ class CodeGenerator: 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') diff --git a/Lib/test/test_compiler.py b/Lib/test/test_compiler.py index 929a12b..9dff71e 100644 --- a/Lib/test/test_compiler.py +++ b/Lib/test/test_compiler.py @@ -104,6 +104,19 @@ class CompilerTest(unittest.TestCase): 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) ############################################################################### @@ -28,6 +28,9 @@ Library - 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 ----------------- |