Commit c1c378a1 authored by Vitja Makarov's avatar Vitja Makarov

DefNode: Move assignemnt synthesis to AnaylyseDeclarations

parent 519a19a9
...@@ -632,13 +632,7 @@ class ControlFlowAnalysis(CythonTransform): ...@@ -632,13 +632,7 @@ class ControlFlowAnalysis(CythonTransform):
return node return node
def visit_DefNode(self, node): def visit_DefNode(self, node):
## XXX: no target name node here
node.used = True node.used = True
entry = node.entry
if entry.is_anonymous:
entry = self.env.lookup(node.name)
if entry:
self.flow.mark_assignment(node, object_expr_not_none, entry)
return self.visit_FuncDefNode(node) return self.visit_FuncDefNode(node)
def visit_GeneratorBodyDefNode(self, node): def visit_GeneratorBodyDefNode(self, node):
......
...@@ -1308,7 +1308,6 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1308,7 +1308,6 @@ class FuncDefNode(StatNode, BlockNode):
# with fused argument types with a FusedCFuncDefNode # with fused argument types with a FusedCFuncDefNode
py_func = None py_func = None
assmt = None
needs_closure = False needs_closure = False
needs_outer_scope = False needs_outer_scope = False
pymethdef_required = False pymethdef_required = False
...@@ -1818,9 +1817,6 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1818,9 +1817,6 @@ class FuncDefNode(StatNode, BlockNode):
for arg in self.args: for arg in self.args:
if not arg.is_dynamic: if not arg.is_dynamic:
arg.generate_assignment_code(code) arg.generate_assignment_code(code)
# For Python class methods, create and store function object
if self.assmt:
self.assmt.generate_execution_code(code)
# #
# Special code for the __getbuffer__ function # Special code for the __getbuffer__ function
...@@ -2648,8 +2644,6 @@ class DefNode(FuncDefNode): ...@@ -2648,8 +2644,6 @@ class DefNode(FuncDefNode):
# The following subnode is constructed internally # The following subnode is constructed internally
# when the def statement is inside a Python class definition. # when the def statement is inside a Python class definition.
# #
# assmt AssignmentNode Function construction/assignment
#
# fused_py_func DefNode The original fused cpdef DefNode # fused_py_func DefNode The original fused cpdef DefNode
# (in case this is a specialization) # (in case this is a specialization)
# specialized_cpdefs [DefNode] list of specialized cpdef DefNodes # specialized_cpdefs [DefNode] list of specialized cpdef DefNodes
...@@ -2660,7 +2654,6 @@ class DefNode(FuncDefNode): ...@@ -2660,7 +2654,6 @@ class DefNode(FuncDefNode):
child_attrs = ["args", "star_arg", "starstar_arg", "body", "decorators"] child_attrs = ["args", "star_arg", "starstar_arg", "body", "decorators"]
lambda_name = None lambda_name = None
assmt = None
reqd_kw_flags_cname = "0" reqd_kw_flags_cname = "0"
is_wrapper = 0 is_wrapper = 0
no_assignment_synthesis = 0 no_assignment_synthesis = 0
...@@ -3020,14 +3013,13 @@ class DefNode(FuncDefNode): ...@@ -3020,14 +3013,13 @@ class DefNode(FuncDefNode):
self.local_scope.directives = env.directives self.local_scope.directives = env.directives
self.analyse_default_values(env) self.analyse_default_values(env)
if self.needs_assignment_synthesis(env): if not self.needs_assignment_synthesis(env) and self.decorators:
# Shouldn't we be doing this at the module level too?
self.synthesize_assignment_node(env)
elif self.decorators:
for decorator in self.decorators[::-1]: for decorator in self.decorators[::-1]:
decorator.decorator.analyse_expressions(env) decorator.decorator.analyse_expressions(env)
def needs_assignment_synthesis(self, env, code=None): def needs_assignment_synthesis(self, env, code=None):
if self.is_wrapper:
return False
if self.specialized_cpdefs or self.is_staticmethod: if self.specialized_cpdefs or self.is_staticmethod:
return True return True
if self.no_assignment_synthesis: if self.no_assignment_synthesis:
...@@ -3042,48 +3034,6 @@ class DefNode(FuncDefNode): ...@@ -3042,48 +3034,6 @@ class DefNode(FuncDefNode):
return code.globalstate.directives['binding'] return code.globalstate.directives['binding']
return env.is_py_class_scope or env.is_closure_scope return env.is_py_class_scope or env.is_closure_scope
def synthesize_assignment_node(self, env):
import ExprNodes
if self.fused_py_func:
return
genv = env
while genv.is_py_class_scope or genv.is_c_class_scope:
genv = genv.outer_scope
if genv.is_closure_scope:
rhs = self.py_cfunc_node = ExprNodes.InnerFunctionNode(
self.pos, def_node=self,
pymethdef_cname=self.entry.pymethdef_cname,
code_object=ExprNodes.CodeObjectNode(self))
else:
rhs = ExprNodes.PyCFunctionNode(
self.pos,
def_node=self,
pymethdef_cname=self.entry.pymethdef_cname,
binding=env.directives['binding'],
specialized_cpdefs=self.specialized_cpdefs,
code_object=ExprNodes.CodeObjectNode(self))
if env.is_py_class_scope:
rhs.binding = True
self.is_cyfunction = rhs.binding
if self.decorators:
for decorator in self.decorators[::-1]:
rhs = ExprNodes.SimpleCallNode(
decorator.pos,
function = decorator.decorator,
args = [rhs])
self.assmt = SingleAssignmentNode(self.pos,
lhs = ExprNodes.NameNode(self.pos, name = self.name),
rhs = rhs)
self.assmt.analyse_declarations(env)
self.assmt.analyse_expressions(env)
def error_value(self): def error_value(self):
return self.entry.signature.error_value return self.entry.signature.error_value
......
...@@ -1493,6 +1493,9 @@ if VALUE is not None: ...@@ -1493,6 +1493,9 @@ if VALUE is not None:
if node.py_func: if node.py_func:
node.stats.insert(0, node.py_func) node.stats.insert(0, node.py_func)
if node.py_func and node.py_func.needs_assignment_synthesis(env):
node = [node, self._synthesize_assignment(node.py_func, env)]
else: else:
node.body.analyse_declarations(lenv) node.body.analyse_declarations(lenv)
...@@ -1514,6 +1517,54 @@ if VALUE is not None: ...@@ -1514,6 +1517,54 @@ if VALUE is not None:
self.seen_vars_stack.pop() self.seen_vars_stack.pop()
return node return node
def visit_DefNode(self, node):
node = self.visit_FuncDefNode(node)
env = self.env_stack[-1]
if (not isinstance(node, Nodes.DefNode) or
node.fused_py_func or node.is_generator_body or
not node.needs_assignment_synthesis(env)):
return node
return [node, self._synthesize_assignment(node, env)]
def _synthesize_assignment(self, node, env):
# Synthesize assignment node and put it right after defnode
genv = env
while genv.is_py_class_scope or genv.is_c_class_scope:
genv = genv.outer_scope
if genv.is_closure_scope:
rhs = node.py_cfunc_node = ExprNodes.InnerFunctionNode(
node.pos, def_node=node,
pymethdef_cname=node.entry.pymethdef_cname,
code_object=ExprNodes.CodeObjectNode(node))
else:
rhs = ExprNodes.PyCFunctionNode(
node.pos,
def_node=node,
pymethdef_cname=node.entry.pymethdef_cname,
binding=self.current_directives.get('binding'),
specialized_cpdefs=node.specialized_cpdefs,
code_object=ExprNodes.CodeObjectNode(node))
if env.is_py_class_scope:
rhs.binding = True
node.is_cyfunction = rhs.binding
if node.decorators:
for decorator in node.decorators[::-1]:
rhs = ExprNodes.SimpleCallNode(
decorator.pos,
function = decorator.decorator,
args = [rhs])
assmt = Nodes.SingleAssignmentNode(
node.pos,
lhs=ExprNodes.NameNode(node.pos,name=node.name),
rhs=rhs)
assmt.analyse_declarations(env)
return assmt
def visit_ScopedExprNode(self, node): def visit_ScopedExprNode(self, node):
env = self.env_stack[-1] env = self.env_stack[-1]
node.analyse_declarations(env) node.analyse_declarations(env)
...@@ -1645,11 +1696,13 @@ if VALUE is not None: ...@@ -1645,11 +1696,13 @@ if VALUE is not None:
return None return None
def visit_CnameDecoratorNode(self, node): def visit_CnameDecoratorNode(self, node):
self.visitchildren(node) child_node = self.visit(node.node)
if not child_node:
if not node.node:
return None return None
if type(child_node) is list: # Assignment synthesized
node.child_node = child_node[0]
return [node] + child_node[1:]
node.node = child_node
return node return node
def create_Property(self, entry): def create_Property(self, entry):
...@@ -2065,9 +2118,6 @@ class CreateClosureClasses(CythonTransform): ...@@ -2065,9 +2118,6 @@ class CreateClosureClasses(CythonTransform):
return from_closure, in_closure return from_closure, in_closure
def create_class_from_scope(self, node, target_module_scope, inner_node=None): def create_class_from_scope(self, node, target_module_scope, inner_node=None):
# skip generator body
if node.is_generator_body:
return
# move local variables into closure # move local variables into closure
if node.is_generator: if node.is_generator:
for entry in node.local_scope.entries.values(): for entry in node.local_scope.entries.values():
...@@ -2160,6 +2210,10 @@ class CreateClosureClasses(CythonTransform): ...@@ -2160,6 +2210,10 @@ class CreateClosureClasses(CythonTransform):
self.path.pop() self.path.pop()
return node return node
def visit_GeneratorBodyDefNode(self, node):
self.visitchildren(node)
return node
def visit_CFuncDefNode(self, node): def visit_CFuncDefNode(self, node):
self.visitchildren(node) self.visitchildren(node)
return node return node
......
...@@ -273,6 +273,8 @@ class CythonTransform(VisitorTransform): ...@@ -273,6 +273,8 @@ class CythonTransform(VisitorTransform):
import ModuleNode import ModuleNode
if isinstance(node, ModuleNode.ModuleNode): if isinstance(node, ModuleNode.ModuleNode):
self.current_directives = node.directives self.current_directives = node.directives
else: # XXX: is default directives better?
self.current_directives = {}
return super(CythonTransform, self).__call__(node) return super(CythonTransform, self).__call__(node)
def visit_CompilerDirectivesNode(self, node): def visit_CompilerDirectivesNode(self, node):
......
...@@ -406,10 +406,10 @@ cdef object some_float_value(): ...@@ -406,10 +406,10 @@ cdef object some_float_value():
return 2.0 return 2.0
@cython.test_fail_if_path_exists('//NameNode[@type.is_pyobject = True]')
@cython.test_assert_path_exists('//NameNode[@type.is_pyobject]',
'//NameNode[@type.is_pyobject = False]')
@infer_types(None) @infer_types(None)
@cython.test_fail_if_path_exists('//DefNode//NameNode[@type.is_pyobject = True]')
@cython.test_assert_path_exists('//DefNode//NameNode[@type.is_pyobject]',
'//DefNode//NameNode[@type.is_pyobject = False]')
def double_loop(): def double_loop():
""" """
>>> double_loop() == 1.0 * 10 >>> double_loop() == 1.0 * 10
......
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