fix cross-closure analysis for names redefined inside of a closure function
authorStefan Behnel <stefan_ml@behnel.de>
Sat, 29 Dec 2012 15:28:06 +0000 (16:28 +0100)
committerStefan Behnel <stefan_ml@behnel.de>
Sat, 29 Dec 2012 15:28:06 +0000 (16:28 +0100)
Cython/Compiler/FlowControl.py
Cython/Compiler/Optimize.py
tests/run/closure_inlining.pyx

index 749a488..47d2c55 100644 (file)
@@ -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):
index 481816d..815aeb1 100644 (file)
@@ -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(
index 5786949..8a0e387 100644 (file)
@@ -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()