Commit 61e4baf6 authored by Stefan Behnel's avatar Stefan Behnel

reimplement cross-closure type inference using a dedicated LocalEntry class...

reimplement cross-closure type inference using a dedicated LocalEntry class for entry copies in closures to keep closure knowledge in one place
parent 5fdb48d4
...@@ -161,15 +161,15 @@ class ControlFlow(object): ...@@ -161,15 +161,15 @@ class ControlFlow(object):
self.block.positions.add(node.pos[:2]) self.block.positions.add(node.pos[:2])
def mark_assignment(self, lhs, rhs, entry): def mark_assignment(self, lhs, rhs, entry):
if self.block: entry = entry.defining_entry
if not self.is_tracked(entry): if self.block and self.is_tracked(entry):
return
assignment = NameAssignment(lhs, rhs, entry) assignment = NameAssignment(lhs, rhs, entry)
self.block.stats.append(assignment) self.block.stats.append(assignment)
self.block.gen[entry] = assignment self.block.gen[entry] = assignment
self.entries.add(entry) self.entries.add(entry)
def mark_argument(self, lhs, rhs, entry): def mark_argument(self, lhs, rhs, entry):
entry = entry.defining_entry
if self.block and self.is_tracked(entry): if self.block and self.is_tracked(entry):
assignment = Argument(lhs, rhs, entry) assignment = Argument(lhs, rhs, entry)
self.block.stats.append(assignment) self.block.stats.append(assignment)
...@@ -177,6 +177,7 @@ class ControlFlow(object): ...@@ -177,6 +177,7 @@ class ControlFlow(object):
self.entries.add(entry) self.entries.add(entry)
def mark_deletion(self, node, entry): def mark_deletion(self, node, entry):
entry = entry.defining_entry
if self.block and self.is_tracked(entry): if self.block and self.is_tracked(entry):
assignment = NameDeletion(node, entry) assignment = NameDeletion(node, entry)
self.block.stats.append(assignment) self.block.stats.append(assignment)
...@@ -184,6 +185,7 @@ class ControlFlow(object): ...@@ -184,6 +185,7 @@ class ControlFlow(object):
self.entries.add(entry) self.entries.add(entry)
def mark_reference(self, node, entry): def mark_reference(self, node, entry):
entry = entry.defining_entry
if self.block and self.is_tracked(entry): if self.block and self.is_tracked(entry):
self.block.stats.append(NameReference(node, entry)) self.block.stats.append(NameReference(node, entry))
# Local variable is definitely bound after this reference # Local variable is definitely bound after this reference
......
...@@ -198,9 +198,10 @@ class Entry(object): ...@@ -198,9 +198,10 @@ class Entry(object):
self.cf_assignments = [] self.cf_assignments = []
self.cf_references = [] self.cf_references = []
self.inner_entries = [] self.inner_entries = []
self.defining_entry = self
def __repr__(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): def redeclared(self, pos):
error(pos, "'%s' does not match previous declaration" % self.name) error(pos, "'%s' does not match previous declaration" % self.name)
...@@ -210,20 +211,36 @@ class Entry(object): ...@@ -210,20 +211,36 @@ class Entry(object):
return [self] + self.overloaded_alternatives return [self] + self.overloaded_alternatives
def all_entries(self): def all_entries(self):
""" return [self] + self.inner_entries
Returns all entries for this entry, including the equivalent ones
in other closures.
"""
if self.from_closure:
return self.outer_entry.all_entries()
entries = []
def collect_inner_entries(entry): class InnerEntry(Entry):
entries.append(entry) """
for e in entry.inner_entries: An entry in a closure scope that represents the real outer Entry.
collect_inner_entries(e) """
collect_inner_entries(self) from_closure = True
return entries
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): class Scope(object):
...@@ -1534,15 +1551,9 @@ class LocalScope(Scope): ...@@ -1534,15 +1551,9 @@ class LocalScope(Scope):
# The actual c fragment for the different scopes differs # The actual c fragment for the different scopes differs
# on the outside and inside, so we make a new entry # on the outside and inside, so we make a new entry
entry.in_closure = True entry.in_closure = True
# Would it be better to declare_var here? inner_entry = InnerEntry(entry, self)
inner_entry = Entry(entry.name, entry.cname, entry.type, entry.pos)
inner_entry.scope = self
inner_entry.is_variable = True 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 self.entries[name] = inner_entry
entry.inner_entries.append(inner_entry)
return inner_entry return inner_entry
return entry return entry
......
...@@ -360,11 +360,9 @@ class SimpleAssignmentTypeInferer(object): ...@@ -360,11 +360,9 @@ class SimpleAssignmentTypeInferer(object):
ready_to_infer = [] ready_to_infer = []
for name, entry in scope.entries.items(): for name, entry in scope.entries.items():
if entry.type is unspecified_type: if entry.type is unspecified_type:
entries = entry.all_entries()
all = set() all = set()
for e in entries: for assmt in entry.cf_assignments:
for assmt in e.cf_assignments: all.update(assmt.type_dependencies(entry.scope))
all.update(assmt.type_dependencies(e.scope))
if all: if all:
dependancies_by_entry[entry] = all dependancies_by_entry[entry] = all
for dep in all: for dep in all:
...@@ -390,8 +388,7 @@ class SimpleAssignmentTypeInferer(object): ...@@ -390,8 +388,7 @@ class SimpleAssignmentTypeInferer(object):
entry = ready_to_infer.pop() entry = ready_to_infer.pop()
types = [ types = [
assmt.rhs.infer_type(scope) assmt.rhs.infer_type(scope)
for e in entry.all_entries() for assmt in entry.cf_assignments
for assmt in e.cf_assignments
] ]
if types and Utils.all(types): if types and Utils.all(types):
entry_type = spanning_type(types, entry.might_overflow, entry.pos) entry_type = spanning_type(types, entry.might_overflow, entry.pos)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment