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