reimplement cross-closure type inference using a dedicated LocalEntry class for entry...
authorStefan Behnel <stefan_ml@behnel.de>
Wed, 26 Dec 2012 11:30:30 +0000 (12:30 +0100)
committerStefan Behnel <stefan_ml@behnel.de>
Wed, 26 Dec 2012 11:30:30 +0000 (12:30 +0100)
Cython/Compiler/FlowControl.py
Cython/Compiler/Symtab.py
Cython/Compiler/TypeInference.py

index 9afd5bb..749a488 100644 (file)
@@ -161,15 +161,15 @@ class ControlFlow(object):
             self.block.positions.add(node.pos[:2])
 
     def mark_assignment(self, lhs, rhs, entry):
-        if self.block:
-            if not self.is_tracked(entry):
-                return
+        entry = entry.defining_entry
+        if self.block and self.is_tracked(entry):
             assignment = NameAssignment(lhs, rhs, entry)
             self.block.stats.append(assignment)
             self.block.gen[entry] = assignment
             self.entries.add(entry)
 
     def mark_argument(self, lhs, rhs, entry):
+        entry = entry.defining_entry
         if self.block and self.is_tracked(entry):
             assignment = Argument(lhs, rhs, entry)
             self.block.stats.append(assignment)
@@ -177,6 +177,7 @@ class ControlFlow(object):
             self.entries.add(entry)
 
     def mark_deletion(self, node, entry):
+        entry = entry.defining_entry
         if self.block and self.is_tracked(entry):
             assignment = NameDeletion(node, entry)
             self.block.stats.append(assignment)
@@ -184,6 +185,7 @@ class ControlFlow(object):
             self.entries.add(entry)
 
     def mark_reference(self, node, entry):
+        entry = entry.defining_entry
         if self.block and self.is_tracked(entry):
             self.block.stats.append(NameReference(node, entry))
             # Local variable is definitely bound after this reference
index a0d907c..4413e9a 100644 (file)
@@ -198,9 +198,10 @@ class Entry(object):
         self.cf_assignments = []
         self.cf_references = []
         self.inner_entries = []
+        self.defining_entry = self
 
     def __repr__(self):
-        return "Entry(name=%s, type=%s)" % (self.name, self.type)
+        return "%s(name=%s, type=%s)" % (type(self).__name__, self.name, self.type)
 
     def redeclared(self, pos):
         error(pos, "'%s' does not match previous declaration" % self.name)
@@ -210,20 +211,36 @@ class Entry(object):
         return [self] + self.overloaded_alternatives
 
     def all_entries(self):
-        """
-        Returns all entries for this entry, including the equivalent ones
-        in other closures.
-        """
-        if self.from_closure:
-            return self.outer_entry.all_entries()
+        return [self] + self.inner_entries
 
-        entries = []
-        def collect_inner_entries(entry):
-            entries.append(entry)
-            for e in entry.inner_entries:
-                collect_inner_entries(e)
-        collect_inner_entries(self)
-        return entries
+
+class InnerEntry(Entry):
+    """
+    An entry in a closure scope that represents the real outer Entry.
+    """
+    from_closure = True
+
+    def __init__(self, outer_entry, scope):
+        Entry.__init__(self, outer_entry.name,
+                       outer_entry.cname,
+                       outer_entry.type,
+                       outer_entry.pos)
+        self.outer_entry = outer_entry
+        self.scope = scope
+
+        # share state with (outermost) defining entry
+        outermost_entry = outer_entry
+        while outermost_entry.outer_entry:
+            outermost_entry = outermost_entry.outer_entry
+        self.defining_entry = outermost_entry
+        self.inner_entries = outermost_entry.inner_entries
+        self.cf_assignments = outermost_entry.cf_assignments
+        self.cf_references = outermost_entry.cf_references
+        self.overloaded_alternatives = outermost_entry.overloaded_alternatives
+        self.inner_entries.append(self)
+
+    def __getattr__(self, name):
+        return getattr(self.defining_entry, name)
 
 
 class Scope(object):
@@ -1534,15 +1551,9 @@ class LocalScope(Scope):
                 # The actual c fragment for the different scopes differs
                 # on the outside and inside, so we make a new entry
                 entry.in_closure = True
-                # Would it be better to declare_var here?
-                inner_entry = Entry(entry.name, entry.cname, entry.type, entry.pos)
-                inner_entry.scope = self
+                inner_entry = InnerEntry(entry, self)
                 inner_entry.is_variable = True
-                inner_entry.outer_entry = entry
-                inner_entry.from_closure = True
-                inner_entry.is_declared_generic = entry.is_declared_generic
                 self.entries[name] = inner_entry
-                entry.inner_entries.append(inner_entry)
                 return inner_entry
         return entry
 
index 4164802..1f1693a 100644 (file)
@@ -360,11 +360,9 @@ class SimpleAssignmentTypeInferer(object):
         ready_to_infer = []
         for name, entry in scope.entries.items():
             if entry.type is unspecified_type:
-                entries = entry.all_entries()
                 all = set()
-                for e in entries:
-                    for assmt in e.cf_assignments:
-                        all.update(assmt.type_dependencies(e.scope))
+                for assmt in entry.cf_assignments:
+                    all.update(assmt.type_dependencies(entry.scope))
                 if all:
                     dependancies_by_entry[entry] = all
                     for dep in all:
@@ -390,8 +388,7 @@ class SimpleAssignmentTypeInferer(object):
                 entry = ready_to_infer.pop()
                 types = [
                     assmt.rhs.infer_type(scope)
-                    for e in entry.all_entries()
-                    for assmt in e.cf_assignments
+                    for assmt in entry.cf_assignments
                     ]
                 if types and Utils.all(types):
                     entry_type = spanning_type(types, entry.might_overflow, entry.pos)