From 5690000c82e452be38054cca2e5c09a2b5541387 Mon Sep 17 00:00:00 2001 From: Stefan Behnel <stefan_ml@behnel.de> Date: Sat, 29 Dec 2012 16:28:06 +0100 Subject: [PATCH] fix cross-closure analysis for names redefined inside of a closure function --- Cython/Compiler/FlowControl.py | 2 ++ Cython/Compiler/Optimize.py | 11 ++++++----- tests/run/closure_inlining.pyx | 22 ++++++++++++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/Cython/Compiler/FlowControl.py b/Cython/Compiler/FlowControl.py index 749a48851..47d2c55f8 100644 --- a/Cython/Compiler/FlowControl.py +++ b/Cython/Compiler/FlowControl.py @@ -536,6 +536,8 @@ def check_definitions(flow, compiler_directives): node.cf_is_null = True if node.allow_null or entry.from_closure or entry.is_pyclass_attr: pass # Can be uninitialized here + elif entry.in_closure: + pass # not smart enough to get this right elif node.cf_is_null: if (entry.type.is_pyobject or entry.type.is_unspecified or entry.error_on_uninitialized): diff --git a/Cython/Compiler/Optimize.py b/Cython/Compiler/Optimize.py index 481816dc8..815aeb17d 100644 --- a/Cython/Compiler/Optimize.py +++ b/Cython/Compiler/Optimize.py @@ -1657,7 +1657,7 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): return node return kwargs -class InlineDefNodeCalls(Visitor.CythonTransform): +class InlineDefNodeCalls(Visitor.EnvTransform): visit_Node = Visitor.VisitorTransform.recurse_to_children def visit_SimpleCallNode(self, node): @@ -1665,12 +1665,13 @@ class InlineDefNodeCalls(Visitor.CythonTransform): if not self.current_directives.get('optimize.inline_defnode_calls'): return node function_name = node.function - if not function_name.is_name: + if not function_name.is_name or function_name.cf_state is None: return node - if (function_name.cf_state is None # global scope - or not function_name.cf_state.is_single): + entry = self.current_env().lookup(function_name.name) + if not entry or (not entry.cf_assignments + or len(entry.cf_assignments) != 1): return node - function = function_name.cf_state.one().rhs + function = entry.cf_assignments[0].rhs if not isinstance(function, ExprNodes.PyCFunctionNode): return node inlined = ExprNodes.InlinedDefNodeCallNode( diff --git a/tests/run/closure_inlining.pyx b/tests/run/closure_inlining.pyx index 578694952..8a0e38722 100644 --- a/tests/run/closure_inlining.pyx +++ b/tests/run/closure_inlining.pyx @@ -106,3 +106,25 @@ def test_sideeffect_call_order(): pass call(1, sideeffect(2), 3, sideeffect(4), sideeffect(5)) return L + + +def test_redef(redefine): + """ + >>> test_redef(False) + 1 + >>> test_redef(True) + 2 + """ + def inner(): + return 1 + def inner2(): + return 2 + def redef(): + nonlocal inner + inner = inner2 + if redefine: + redef() + assert inner == inner2 + else: + assert inner != inner2 + return inner() -- 2.30.9