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

merge

parents d3b253b8 b80966c6
......@@ -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
......@@ -534,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):
......
......@@ -1657,9 +1657,20 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform):
return node
return kwargs
class InlineDefNodeCalls(Visitor.CythonTransform):
class InlineDefNodeCalls(Visitor.EnvTransform):
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):
self.visitchildren(node)
if not self.current_directives.get('optimize.inline_defnode_calls'):
......@@ -1667,10 +1678,7 @@ class InlineDefNodeCalls(Visitor.CythonTransform):
function_name = node.function
if not function_name.is_name:
return node
if (function_name.cf_state is None # global scope
or not function_name.cf_state.is_single):
return node
function = function_name.cf_state.one().rhs
function = self.get_constant_value_node(function_name)
if not isinstance(function, ExprNodes.PyCFunctionNode):
return node
inlined = ExprNodes.InlinedDefNodeCallNode(
......
......@@ -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
......
......@@ -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)
......
......@@ -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()
......@@ -14,7 +14,7 @@ def test_outer_inner_double():
nonlocal x
x = 2.0
inner()
assert x == 2.0
assert x == 2.0, str(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