Commit 8e7a120b authored by Stefan Behnel's avatar Stefan Behnel

merge

parents d3b253b8 b80966c6
...@@ -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
...@@ -534,6 +536,8 @@ def check_definitions(flow, compiler_directives): ...@@ -534,6 +536,8 @@ def check_definitions(flow, compiler_directives):
node.cf_is_null = True node.cf_is_null = True
if node.allow_null or entry.from_closure or entry.is_pyclass_attr: if node.allow_null or entry.from_closure or entry.is_pyclass_attr:
pass # Can be uninitialized here pass # Can be uninitialized here
elif entry.in_closure:
pass # not smart enough to get this right
elif node.cf_is_null: elif node.cf_is_null:
if (entry.type.is_pyobject or entry.type.is_unspecified or if (entry.type.is_pyobject or entry.type.is_unspecified or
entry.error_on_uninitialized): entry.error_on_uninitialized):
......
...@@ -1657,9 +1657,20 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): ...@@ -1657,9 +1657,20 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform):
return node return node
return kwargs return kwargs
class InlineDefNodeCalls(Visitor.CythonTransform): class InlineDefNodeCalls(Visitor.EnvTransform):
visit_Node = Visitor.VisitorTransform.recurse_to_children visit_Node = Visitor.VisitorTransform.recurse_to_children
def get_constant_value_node(self, name_node):
if not name_node.cf_state or not name_node.cf_state.is_single:
# no single assignment in the current scope
return None
entry = self.current_env().lookup(name_node.name)
if not entry or (not entry.cf_assignments
or len(entry.cf_assignments) != 1):
# not just a single assignment in all closures
return None
return name_node.cf_state.one().rhs
def visit_SimpleCallNode(self, node): def visit_SimpleCallNode(self, node):
self.visitchildren(node) self.visitchildren(node)
if not self.current_directives.get('optimize.inline_defnode_calls'): if not self.current_directives.get('optimize.inline_defnode_calls'):
...@@ -1667,10 +1678,7 @@ class InlineDefNodeCalls(Visitor.CythonTransform): ...@@ -1667,10 +1678,7 @@ class InlineDefNodeCalls(Visitor.CythonTransform):
function_name = node.function function_name = node.function
if not function_name.is_name: if not function_name.is_name:
return node return node
if (function_name.cf_state is None # global scope function = self.get_constant_value_node(function_name)
or not function_name.cf_state.is_single):
return node
function = function_name.cf_state.one().rhs
if not isinstance(function, ExprNodes.PyCFunctionNode): if not isinstance(function, ExprNodes.PyCFunctionNode):
return node return node
inlined = ExprNodes.InlinedDefNodeCallNode( inlined = ExprNodes.InlinedDefNodeCallNode(
......
...@@ -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)
......
...@@ -106,3 +106,25 @@ def test_sideeffect_call_order(): ...@@ -106,3 +106,25 @@ def test_sideeffect_call_order():
pass pass
call(1, sideeffect(2), 3, sideeffect(4), sideeffect(5)) call(1, sideeffect(2), 3, sideeffect(4), sideeffect(5))
return L 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()
...@@ -14,7 +14,7 @@ def test_outer_inner_double(): ...@@ -14,7 +14,7 @@ def test_outer_inner_double():
nonlocal x nonlocal x
x = 2.0 x = 2.0
inner() inner()
assert x == 2.0 assert x == 2.0, str(x)
return cython.typeof(x) return cython.typeof(x)
......
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