mirror of https://github.com/python/cpython.git
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.
This commit is contained in:
parent
45381938e9
commit
06ded09d40
|
@ -382,16 +382,7 @@ def _visitFuncOrLambda(self, node, isLambda=0):
|
||||||
self.set_lineno(node)
|
self.set_lineno(node)
|
||||||
for default in node.defaults:
|
for default in node.defaults:
|
||||||
self.visit(default)
|
self.visit(default)
|
||||||
frees = gen.scope.get_free_vars()
|
self._makeClosure(gen, len(node.defaults))
|
||||||
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))
|
|
||||||
|
|
||||||
for i in range(ndecorators):
|
for i in range(ndecorators):
|
||||||
self.emit('CALL_FUNCTION', 1)
|
self.emit('CALL_FUNCTION', 1)
|
||||||
|
|
||||||
|
@ -405,14 +396,7 @@ def visitClass(self, node):
|
||||||
for base in node.bases:
|
for base in node.bases:
|
||||||
self.visit(base)
|
self.visit(base)
|
||||||
self.emit('BUILD_TUPLE', len(node.bases))
|
self.emit('BUILD_TUPLE', len(node.bases))
|
||||||
frees = gen.scope.get_free_vars()
|
self._makeClosure(gen, 0)
|
||||||
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.emit('CALL_FUNCTION', 0)
|
self.emit('CALL_FUNCTION', 0)
|
||||||
self.emit('BUILD_CLASS')
|
self.emit('BUILD_CLASS')
|
||||||
self.storeName(node.name)
|
self.storeName(node.name)
|
||||||
|
@ -644,22 +628,25 @@ def visitListCompIf(self, node, branch):
|
||||||
self.newBlock()
|
self.newBlock()
|
||||||
self.emit('POP_TOP')
|
self.emit('POP_TOP')
|
||||||
|
|
||||||
|
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', args)
|
||||||
|
else:
|
||||||
|
self.emit('LOAD_CONST', gen)
|
||||||
|
self.emit('MAKE_FUNCTION', args)
|
||||||
|
|
||||||
def visitGenExpr(self, node):
|
def visitGenExpr(self, node):
|
||||||
gen = GenExprCodeGenerator(node, self.scopes, self.class_name,
|
gen = GenExprCodeGenerator(node, self.scopes, self.class_name,
|
||||||
self.get_module())
|
self.get_module())
|
||||||
walk(node.code, gen)
|
walk(node.code, gen)
|
||||||
gen.finish()
|
gen.finish()
|
||||||
self.set_lineno(node)
|
self.set_lineno(node)
|
||||||
frees = gen.scope.get_free_vars()
|
self._makeClosure(gen, 0)
|
||||||
if frees:
|
|
||||||
for name in frees:
|
|
||||||
self.emit('LOAD_CLOSURE', name)
|
|
||||||
self.emit('LOAD_CONST', gen)
|
|
||||||
self.emit('MAKE_CLOSURE', 0)
|
|
||||||
else:
|
|
||||||
self.emit('LOAD_CONST', gen)
|
|
||||||
self.emit('MAKE_FUNCTION', 0)
|
|
||||||
|
|
||||||
# precomputation of outmost iterable
|
# precomputation of outmost iterable
|
||||||
self.visit(node.code.quals[0].iter)
|
self.visit(node.code.quals[0].iter)
|
||||||
self.emit('GET_ITER')
|
self.emit('GET_ITER')
|
||||||
|
|
|
@ -104,6 +104,19 @@ def testFlatten(self):
|
||||||
self.assertEquals(flatten([1, [2]]), [1, 2])
|
self.assertEquals(flatten([1, [2]]), [1, 2])
|
||||||
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)
|
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
|
- Bug #1531405, format_exception no longer raises an exception if
|
||||||
str(exception) raised an exception.
|
str(exception) raised an exception.
|
||||||
|
|
||||||
|
- Fix a bug in the ``compiler`` package that caused invalid code to be
|
||||||
|
generated for nested functions.
|
||||||
|
|
||||||
|
|
||||||
Extension Modules
|
Extension Modules
|
||||||
-----------------
|
-----------------
|
||||||
|
|
Loading…
Reference in New Issue