Commit f9c385e0 authored by Stefan Behnel's avatar Stefan Behnel

refactor analyse_types() and friends to work more like a transform by...

refactor analyse_types() and friends to work more like a transform by returning the node or a replacement
parent 927e1a4d
......@@ -346,18 +346,18 @@ class ExprNode(Node):
# Convenience routine performing both the Type
# Analysis and Temp Allocation phases for a whole
# expression.
self.analyse_types(env)
return self.analyse_types(env)
def analyse_target_expression(self, env, rhs):
# Convenience routine performing both the Type
# Analysis and Temp Allocation phases for the LHS of
# an assignment.
self.analyse_target_types(env)
return self.analyse_target_types(env)
def analyse_boolean_expression(self, env):
# Analyse expression and coerce to a boolean.
self.analyse_types(env)
bool = self.coerce_to_boolean(env)
node = self.analyse_types(env)
bool = node.coerce_to_boolean(env)
return bool
def analyse_temp_boolean_expression(self, env):
......@@ -368,8 +368,8 @@ class ExprNode(Node):
# afterwards. By forcing the result into a temporary,
# we ensure that all disposal has been done by the
# time we get the result.
self.analyse_types(env)
return self.coerce_to_boolean(env).coerce_to_simple(env)
node = self.analyse_types(env)
return node.coerce_to_boolean(env).coerce_to_simple(env)
# --------------- Type Inference -----------------
......@@ -418,7 +418,7 @@ class ExprNode(Node):
self.not_implemented("analyse_types")
def analyse_target_types(self, env):
self.analyse_types(env)
return self.analyse_types(env)
def nogil_check(self, env):
# By default, any expression based on Python objects is
......@@ -809,7 +809,7 @@ class PyConstNode(AtomicExprNode):
return False
def analyse_types(self, env):
pass
return self
def calculate_result_code(self):
return self.value
......@@ -864,7 +864,7 @@ class ConstNode(AtomicExprNode):
return False
def analyse_types(self, env):
pass # Types are held in class variables
return self # Types are held in class variables
def check_const(self):
return True
......@@ -1071,7 +1071,7 @@ class BytesNode(ConstNode):
pos = (self.pos[0], self.pos[1], self.pos[2]-7)
declaration = TreeFragment(u"sizeof(%s)" % self.value, name=pos[0].filename, initial_pos=pos)
sizeof_node = declaration.root.stats[0].expr
sizeof_node.analyse_types(env)
sizeof_node = sizeof_node.analyse_types(env)
if isinstance(sizeof_node, SizeofTypeNode):
return sizeof_node.arg_type
......@@ -1255,6 +1255,7 @@ class LongNode(AtomicExprNode):
def analyse_types(self, env):
self.is_temp = 1
return self
def may_be_none(self):
return False
......@@ -1285,6 +1286,7 @@ class ImagNode(AtomicExprNode):
def analyse_types(self, env):
self.type.create_declaration_utility_code(env)
return self
def may_be_none(self):
return False
......@@ -1347,6 +1349,7 @@ class NewExprNode(AtomicExprNode):
def analyse_types(self, env):
if self.type is None:
self.infer_type(env)
return self
def may_be_none(self):
return False
......@@ -1500,7 +1503,7 @@ class NameNode(AtomicExprNode):
self.entry = env.declare_builtin(self.name, self.pos)
if not self.entry:
self.type = PyrexTypes.error_type
return
return self
entry = self.entry
if entry:
entry.used = 1
......@@ -1508,6 +1511,7 @@ class NameNode(AtomicExprNode):
import Buffer
Buffer.used_buffer_aux_vars(entry)
self.analyse_rvalue_entry(env)
return self
def analyse_target_types(self, env):
self.analyse_entry(env)
......@@ -1530,6 +1534,7 @@ class NameNode(AtomicExprNode):
if self.entry.type.is_buffer:
import Buffer
Buffer.used_buffer_aux_vars(self.entry)
return self
def analyse_rvalue_entry(self, env):
#print "NameNode.analyse_rvalue_entry:", self.name ###
......@@ -1917,9 +1922,10 @@ class BackquoteNode(ExprNode):
subexprs = ['arg']
def analyse_types(self, env):
self.arg.analyse_types(env)
self.arg = self.arg.analyse_types(env)
self.arg = self.arg.coerce_to_pyobject(env)
self.is_temp = 1
return self
gil_message = "Backquote expression"
......@@ -1963,13 +1969,14 @@ class ImportNode(ExprNode):
self.level = -1
else:
self.level = 0
self.module_name.analyse_types(env)
self.module_name = self.module_name.coerce_to_pyobject(env)
module_name = self.module_name.analyse_types(env)
self.module_name = module_name.coerce_to_pyobject(env)
if self.name_list:
self.name_list.analyse_types(env)
self.name_list.coerce_to_pyobject(env)
name_list = self.name_list.analyse_types(env)
self.name_list = name_list.coerce_to_pyobject(env)
self.is_temp = 1
env.use_utility_code(UtilityCode.load_cached("Import", "ImportExport.c"))
return self
gil_message = "Python import"
......@@ -2004,7 +2011,7 @@ class IteratorNode(ExprNode):
subexprs = ['sequence']
def analyse_types(self, env):
self.sequence.analyse_types(env)
self.sequence = self.sequence.analyse_types(env)
if (self.sequence.type.is_array or self.sequence.type.is_ptr) and \
not self.sequence.type.is_string:
# C array iteration will be transformed later on
......@@ -2017,6 +2024,7 @@ class IteratorNode(ExprNode):
self.sequence.type is tuple_type:
self.sequence = self.sequence.as_none_safe_node("'NoneType' object is not iterable")
self.is_temp = 1
return self
gil_message = "Iterating over Python object"
......@@ -2276,6 +2284,7 @@ class NextNode(AtomicExprNode):
def analyse_types(self, env):
self.type = self.infer_type(env, self.iterator.type)
self.is_temp = 1
return self
def generate_result_code(self, code):
self.iterator.generate_iter_next_result_code(self.result(), code)
......@@ -2291,9 +2300,10 @@ class WithExitCallNode(ExprNode):
subexprs = ['args']
def analyse_types(self, env):
self.args.analyse_types(env)
self.args = self.args.analyse_types(env)
self.type = PyrexTypes.c_bint_type
self.is_temp = True
return self
def generate_result_code(self, code):
if isinstance(self.args, TupleNode):
......@@ -2335,7 +2345,7 @@ class ExcValueNode(AtomicExprNode):
pass
def analyse_types(self, env):
pass
return self
class TempNode(ExprNode):
......@@ -2357,7 +2367,7 @@ class TempNode(ExprNode):
self.is_temp = 1
def analyse_types(self, env):
return self.type
return self
def analyse_target_declaration(self, env):
pass
......@@ -2401,7 +2411,7 @@ class RawCNameExprNode(ExprNode):
self.cname = cname
def analyse_types(self, env):
return self.type
return self
def set_cname(self, cname):
self.cname = cname
......@@ -2433,7 +2443,7 @@ class ParallelThreadsAvailableNode(AtomicExprNode):
def analyse_types(self, env):
self.is_temp = True
# env.add_include_file("omp.h")
return self.type
return self
def generate_result_code(self, code):
code.putln("#ifdef _OPENMP")
......@@ -2458,7 +2468,7 @@ class ParallelThreadIdNode(AtomicExprNode): #, Nodes.ParallelNode):
def analyse_types(self, env):
self.is_temp = True
# env.add_include_file("omp.h")
return self.type
return self
def generate_result_code(self, code):
code.putln("#ifdef _OPENMP")
......@@ -2623,6 +2633,7 @@ class IndexNode(ExprNode):
def analyse_types(self, env):
self.analyse_base_and_index_types(env, getting = 1)
return self
def analyse_target_types(self, env):
self.analyse_base_and_index_types(env, setting = 1)
......@@ -2630,6 +2641,7 @@ class IndexNode(ExprNode):
error(self.pos, "Assignment to const dereference")
if not self.is_lvalue():
error(self.pos, "Assignment to non-lvalue of type '%s'" % self.type)
return self
def analyse_base_and_index_types(self, env, getting = 0, setting = 0, analyse_base = True):
# Note: This might be cleaned up by having IndexNode
......@@ -2649,7 +2661,7 @@ class IndexNode(ExprNode):
self.memslice_index = False
if analyse_base:
self.base.analyse_types(env)
self.base = self.base.analyse_types(env)
if self.base.type.is_error:
# Do not visit child tree if base is undeclared to avoid confusing
......@@ -2710,7 +2722,7 @@ class IndexNode(ExprNode):
axis_idx = 0
for i, index in enumerate(indices[:]):
index.analyse_types(env)
index = index.analyse_types(env)
if not index.is_none:
access, packing = self.base.type.axes[axis_idx]
axis_idx += 1
......@@ -2764,7 +2776,7 @@ class IndexNode(ExprNode):
buffer_access = True
skip_child_analysis = True
for x in indices:
x.analyse_types(env)
x = x.analyse_types(env)
if not x.type.is_int:
buffer_access = False
......@@ -2833,9 +2845,10 @@ class IndexNode(ExprNode):
fused_index_operation = base_type.is_cfunction and base_type.is_fused
if not fused_index_operation:
if isinstance(self.index, TupleNode):
self.index.analyse_types(env, skip_children=skip_child_analysis)
self.index = self.index.analyse_types(
env, skip_children=skip_child_analysis)
elif not skip_child_analysis:
self.index.analyse_types(env)
self.index = self.index.analyse_types(env)
self.original_index_type = self.index.type
if base_type.is_unicode_char:
......@@ -2955,7 +2968,7 @@ class IndexNode(ExprNode):
specific_types = [False]
if not Utils.all(specific_types):
self.index.analyse_types(env)
self.index = self.index.analyse_types(env)
if not self.base.entry.as_variable:
error(self.pos, "Can only index fused functions with types")
......@@ -3402,13 +3415,14 @@ class SliceIndexNode(ExprNode):
pass
def analyse_target_types(self, env):
self.analyse_types(env, getting=False)
node = self.analyse_types(env, getting=False)
# when assigning, we must accept any Python type
if self.type.is_pyobject:
self.type = py_object_type
if node.type.is_pyobject:
node.type = py_object_type
return node
def analyse_types(self, env, getting=True):
self.base.analyse_types(env)
self.base = self.base.analyse_types(env)
if self.base.type.is_memoryviewslice:
# Gross hack here! But we do not know the type until this point,
......@@ -3427,12 +3441,12 @@ class SliceIndexNode(ExprNode):
getting=getting,
setting=not getting,
analyse_base=False)
return
return self
if self.start:
self.start.analyse_types(env)
self.start = self.start.analyse_types(env)
if self.stop:
self.stop.analyse_types(env)
self.stop = self.stop.analyse_types(env)
base_type = self.base.type
if base_type.is_string or base_type.is_cpp_string:
self.type = bytes_type
......@@ -3455,6 +3469,7 @@ class SliceIndexNode(ExprNode):
if self.stop:
self.stop = self.stop.coerce_to(c_int, env)
self.is_temp = 1
return self
nogil_check = Node.gil_error
gil_message = "Slicing Python object"
......@@ -3637,15 +3652,16 @@ class SliceNode(ExprNode):
self.compile_time_value_error(e)
def analyse_types(self, env):
self.start.analyse_types(env)
self.stop.analyse_types(env)
self.step.analyse_types(env)
self.start = self.start.coerce_to_pyobject(env)
self.stop = self.stop.coerce_to_pyobject(env)
self.step = self.step.coerce_to_pyobject(env)
start = self.start.analyse_types(env)
stop = self.stop.analyse_types(env)
step = self.step.analyse_types(env)
self.start = start.coerce_to_pyobject(env)
self.stop = stop.coerce_to_pyobject(env)
self.step = step.coerce_to_pyobject(env)
if self.start.is_literal and self.stop.is_literal and self.step.is_literal:
self.is_literal = True
self.is_temp = False
return self
gil_message = "Constructing Python slice object"
......@@ -3737,12 +3753,11 @@ class CallNode(ExprNode):
items += kwds.key_value_pairs
self.key_value_pairs = items
self.__class__ = DictNode
self.analyse_types(env)
self.analyse_types(env) # FIXME
self.coerce_to(type, env)
return True
elif type and type.is_cpp_class:
for arg in self.args:
arg.analyse_types(env)
self.args = [ arg.analyse_types(env) for arg in self.args ]
constructor = type.scope.lookup("<init>")
self.function = RawCNameExprNode(self.function.pos, constructor.type)
self.function.entry = constructor
......@@ -3811,13 +3826,13 @@ class SimpleCallNode(CallNode):
def analyse_types(self, env):
if self.analyse_as_type_constructor(env):
return
return self
if self.analysed:
return
return self
self.analysed = True
self.function.is_called = 1
self.function = self.function.analyse_types(env)
function = self.function
function.is_called = 1
self.function.analyse_types(env)
if function.is_attribute and function.entry and function.entry.is_cmethod:
# Take ownership of the object from which the attribute
......@@ -3828,7 +3843,7 @@ class SimpleCallNode(CallNode):
func_type = self.function_type()
if func_type.is_pyobject:
self.arg_tuple = TupleNode(self.pos, args = self.args)
self.arg_tuple.analyse_types(env)
self.arg_tuple = self.arg_tuple.analyse_types(env)
self.args = None
if func_type is Builtin.type_type and function.is_name and \
function.entry and \
......@@ -3854,8 +3869,7 @@ class SimpleCallNode(CallNode):
self.type = py_object_type
self.is_temp = 1
else:
for arg in self.args:
arg.analyse_types(env)
self.args = [ arg.analyse_types(env) for arg in self.args ]
if self.self and func_type.args:
# Coerce 'self' to the type expected by the method.
......@@ -3874,6 +3888,7 @@ class SimpleCallNode(CallNode):
# Insert coerced 'self' argument into argument list.
self.args.insert(0, self.coerced_self)
self.analyse_c_function_call(env)
return self
def function_type(self):
# Return the type of the function being called, coercing a function
......@@ -4176,11 +4191,9 @@ class InlinedDefNodeCallNode(CallNode):
return True
def analyse_types(self, env):
self.function_name.analyse_types(env)
for arg in self.args:
arg.analyse_types(env)
self.function_name = self.function_name.analyse_types(env)
self.args = [ arg.analyse_types(env) for arg in self.args ]
func_type = self.function.def_node
actual_nargs = len(self.args)
......@@ -4232,6 +4245,7 @@ class InlinedDefNodeCallNode(CallNode):
if i > 0:
warning(arg.pos, "Argument evaluation order in C function call is undefined and may not be as expected", 0)
break
return self
def generate_result_code(self, code):
arg_code = [self.function_name.py_result()]
......@@ -4259,7 +4273,7 @@ class PythonCapiFunctionNode(ExprNode):
type=func_type, utility_code=utility_code)
def analyse_types(self, env):
pass
return self
def generate_result_code(self, code):
if self.utility_code:
......@@ -4323,12 +4337,12 @@ class GeneralCallNode(CallNode):
def analyse_types(self, env):
if self.analyse_as_type_constructor(env):
return
self.function.analyse_types(env)
return self
self.function = self.function.analyse_types(env)
if not self.function.type.is_pyobject:
if self.function.type.is_error:
self.type = error_type
return
return self
if hasattr(self.function, 'entry'):
self.map_keywords_to_posargs()
if not self.is_simple_call:
......@@ -4340,8 +4354,8 @@ class GeneralCallNode(CallNode):
else:
self.function = self.function.coerce_to_pyobject(env)
if self.keyword_args:
self.keyword_args.analyse_types(env)
self.positional_args.analyse_types(env)
self.keyword_args = self.keyword_args.analyse_types(env)
self.positional_args = self.positional_args.analyse_types(env)
self.positional_args = \
self.positional_args.coerce_to_pyobject(env)
function = self.function
......@@ -4354,6 +4368,7 @@ class GeneralCallNode(CallNode):
else:
self.type = py_object_type
self.is_temp = 1
return self
def map_keywords_to_posargs(self):
if not isinstance(self.positional_args, TupleNode):
......@@ -4457,10 +4472,11 @@ class AsTupleNode(ExprNode):
self.compile_time_value_error(e)
def analyse_types(self, env):
self.arg.analyse_types(env)
self.arg = self.arg.analyse_types(env)
self.arg = self.arg.coerce_to_pyobject(env)
self.type = tuple_type
self.is_temp = 1
return self
def may_be_none(self):
return False
......@@ -4565,11 +4581,12 @@ class AttributeNode(ExprNode):
pass
def analyse_target_types(self, env):
self.analyse_types(env, target = 1)
if self.type.is_const:
node = self.analyse_types(env, target = 1)
if node.type.is_const:
error(self.pos, "Assignment to const attribute '%s'" % self.attribute)
if not self.is_lvalue():
if not node.is_lvalue():
error(self.pos, "Assignment to non-lvalue of type '%s'" % self.type)
return node
def analyse_types(self, env, target = 0):
self.initialized_check = env.directives['initializedcheck']
......@@ -4585,6 +4602,7 @@ class AttributeNode(ExprNode):
# may be mutated in a namenode now :)
if self.is_attribute:
self.wrap_obj_in_nonecheck(env)
return self
def analyse_as_cimported_attribute(self, env, target):
# Try to interpret this as a reference to an imported
......@@ -4597,7 +4615,7 @@ class AttributeNode(ExprNode):
if entry and (
entry.is_cglobal or entry.is_cfunction
or entry.is_type or entry.is_const):
self.mutate_into_name_node(env, entry, target)
self.mutate_into_name_node(env, entry, target) # FIXME
entry.used = 1
return 1
return 0
......@@ -4619,7 +4637,7 @@ class AttributeNode(ExprNode):
ubcm_entry.is_cfunction = 1
ubcm_entry.func_cname = entry.func_cname
ubcm_entry.is_unbound_cmethod = 1
self.mutate_into_name_node(env, ubcm_entry, None)
self.mutate_into_name_node(env, ubcm_entry, None) # FIXME
return 1
return 0
......@@ -4662,12 +4680,12 @@ class AttributeNode(ExprNode):
del self.obj
del self.attribute
if target:
NameNode.analyse_target_types(self, env)
NameNode.analyse_target_types(self, env) # FIXME
else:
NameNode.analyse_rvalue_entry(self, env)
def analyse_as_ordinary_attribute(self, env, target):
self.obj.analyse_types(env)
self.obj = self.obj.analyse_types(env)
self.analyse_attribute(env)
if self.entry and self.entry.is_cmethod and not self.is_called:
# error(self.pos, "C method can only be called")
......@@ -4988,15 +5006,17 @@ class StarredTargetNode(ExprNode):
def analyse_types(self, env):
error(self.pos, "can use starred expression only as assignment target")
self.target.analyse_types(env)
self.target = self.target.analyse_types(env)
self.type = self.target.type
return self
def analyse_target_declaration(self, env):
self.target.analyse_target_declaration(env)
def analyse_target_types(self, env):
self.target.analyse_target_types(env)
self.target = self.target.analyse_target_types(env)
self.type = self.target.type
return self
def calculate_result_code(self):
return ""
......@@ -5045,14 +5065,15 @@ class SequenceNode(ExprNode):
def analyse_types(self, env, skip_children=False):
for i in range(len(self.args)):
arg = self.args[i]
if not skip_children: arg.analyse_types(env)
if not skip_children: arg = arg.analyse_types(env)
self.args[i] = arg.coerce_to_pyobject(env)
if self.mult_factor:
self.mult_factor.analyse_types(env)
self.mult_factor = self.mult_factor.analyse_types(env)
if not self.mult_factor.type.is_int:
self.mult_factor = self.mult_factor.coerce_to_pyobject(env)
self.is_temp = 1
# not setting self.type here, subtypes do this
return self
def may_be_none(self):
return False
......@@ -5063,8 +5084,8 @@ class SequenceNode(ExprNode):
self.unpacked_items = []
self.coerced_unpacked_items = []
self.any_coerced_items = False
for arg in self.args:
arg.analyse_target_types(env)
for i, arg in enumerate(self.args):
arg = self.args[i] = arg.analyse_target_types(env)
if arg.is_starred:
if not arg.type.assignable_from(Builtin.list_type):
error(arg.pos,
......@@ -5078,6 +5099,7 @@ class SequenceNode(ExprNode):
self.unpacked_items.append(unpacked_item)
self.coerced_unpacked_items.append(coerced_unpacked_item)
self.type = py_object_type
return self
def generate_result_code(self, code):
self.generate_operation_code(code)
......@@ -5468,23 +5490,25 @@ class TupleNode(SequenceNode):
def analyse_types(self, env, skip_children=False):
if len(self.args) == 0:
self.is_temp = False
self.is_literal = True
node = self
node.is_temp = False
node.is_literal = True
else:
SequenceNode.analyse_types(self, env, skip_children)
for child in self.args:
node = SequenceNode.analyse_types(self, env, skip_children)
for child in node.args:
if not child.is_literal:
break
else:
if not self.mult_factor or self.mult_factor.is_literal and \
isinstance(self.mult_factor.constant_result, (int, long)):
self.is_temp = False
self.is_literal = True
if not node.mult_factor or node.mult_factor.is_literal and \
isinstance(node.mult_factor.constant_result, (int, long)):
node.is_temp = False
node.is_literal = True
else:
if not self.mult_factor.type.is_pyobject:
self.mult_factor = self.mult_factor.coerce_to_pyobject(env)
self.is_temp = True
self.is_partly_literal = True
if not node.mult_factor.type.is_pyobject:
node.mult_factor = node.mult_factor.coerce_to_pyobject(env)
node.is_temp = True
node.is_partly_literal = True
return node
def is_simple(self):
# either temp or constant => always simple
......@@ -5558,15 +5582,16 @@ class ListNode(SequenceNode):
return list_type
def analyse_expressions(self, env):
SequenceNode.analyse_expressions(self, env)
self.coerce_to_pyobject(env)
node = SequenceNode.analyse_expressions(self, env)
return node.coerce_to_pyobject(env)
def analyse_types(self, env):
hold_errors()
self.original_args = list(self.args)
SequenceNode.analyse_types(self, env)
self.obj_conversion_errors = held_errors()
node = SequenceNode.analyse_types(self, env)
node.obj_conversion_errors = held_errors()
release_errors(ignore=True)
return node
def coerce_to(self, dst_type, env):
if dst_type.is_pyobject:
......@@ -5680,11 +5705,11 @@ class ScopedExprNode(ExprNode):
def analyse_types(self, env):
# no recursion here, the children will be analysed separately below
pass
return self
def analyse_scoped_expressions(self, env):
# this is called with the expr_scope as env
pass
return self
def generate_evaluation_code(self, code):
# set up local variables and free their references on exit
......@@ -5749,14 +5774,16 @@ class ComprehensionNode(ScopedExprNode):
self.loop.analyse_declarations(env)
def analyse_types(self, env):
self.target.analyse_expressions(env)
self.target = self.target.analyse_expressions(env)
self.type = self.target.type
if not self.has_local_scope:
self.loop.analyse_expressions(env)
self.loop = self.loop.analyse_expressions(env)
return self
def analyse_scoped_expressions(self, env):
if self.has_local_scope:
self.loop.analyse_expressions(env)
self.loop = self.loop.analyse_expressions(env)
return self
def may_be_none(self):
return False
......@@ -5783,9 +5810,10 @@ class ComprehensionAppendNode(Node):
type = PyrexTypes.c_int_type
def analyse_expressions(self, env):
self.expr.analyse_expressions(env)
self.expr = self.expr.analyse_expressions(env)
if not self.expr.type.is_pyobject:
self.expr = self.expr.coerce_to_pyobject(env)
return self
def generate_execution_code(self, code):
if self.target.type is list_type:
......@@ -5816,12 +5844,13 @@ class DictComprehensionAppendNode(ComprehensionAppendNode):
child_attrs = ['key_expr', 'value_expr']
def analyse_expressions(self, env):
self.key_expr.analyse_expressions(env)
self.key_expr = self.key_expr.analyse_expressions(env)
if not self.key_expr.type.is_pyobject:
self.key_expr = self.key_expr.coerce_to_pyobject(env)
self.value_expr.analyse_expressions(env)
self.value_expr = self.value_expr.analyse_expressions(env)
if not self.value_expr.type.is_pyobject:
self.value_expr = self.value_expr.coerce_to_pyobject(env)
return self
def generate_execution_code(self, code):
self.key_expr.generate_evaluation_code(code)
......@@ -5874,14 +5903,16 @@ class InlinedGeneratorExpressionNode(ScopedExprNode):
def analyse_types(self, env):
if not self.has_local_scope:
self.loop_analysed = True
self.loop.analyse_expressions(env)
self.loop = self.loop.analyse_expressions(env)
self.type = self.result_node.type
self.is_temp = True
return self
def analyse_scoped_expressions(self, env):
self.loop_analysed = True
if self.has_local_scope:
self.loop.analyse_expressions(env)
self.loop = self.loop.analyse_expressions(env)
return self
def coerce_to(self, dst_type, env):
if self.orig_func == 'sum' and dst_type.is_numeric and not self.loop_analysed:
......@@ -5911,10 +5942,11 @@ class SetNode(ExprNode):
def analyse_types(self, env):
for i in range(len(self.args)):
arg = self.args[i]
arg.analyse_types(env)
arg = arg.analyse_types(env)
self.args[i] = arg.coerce_to_pyobject(env)
self.type = set_type
self.is_temp = 1
return self
def may_be_none(self):
return False
......@@ -5989,10 +6021,11 @@ class DictNode(ExprNode):
def analyse_types(self, env):
hold_errors()
for item in self.key_value_pairs:
item.analyse_types(env)
self.key_value_pairs = [ item.analyse_types(env)
for item in self.key_value_pairs ]
self.obj_conversion_errors = held_errors()
release_errors(ignore=True)
return self
def may_be_none(self):
return False
......@@ -6086,10 +6119,11 @@ class DictItemNode(ExprNode):
self.key.constant_result, self.value.constant_result)
def analyse_types(self, env):
self.key.analyse_types(env)
self.value.analyse_types(env)
self.key = self.key.analyse_types(env)
self.value = self.value.analyse_types(env)
self.key = self.key.coerce_to_pyobject(env)
self.value = self.value.coerce_to_pyobject(env)
return self
def generate_evaluation_code(self, code):
self.key.generate_evaluation_code(code)
......@@ -6141,15 +6175,16 @@ class ClassNode(ExprNode, ModuleNameMixin):
subexprs = ['bases', 'doc']
def analyse_types(self, env):
self.bases.analyse_types(env)
self.bases = self.bases.analyse_types(env)
if self.doc:
self.doc.analyse_types(env)
self.doc = self.doc.analyse_types(env)
self.doc = self.doc.coerce_to_pyobject(env)
self.type = py_object_type
self.is_temp = 1
env.use_utility_code(UtilityCode.load_cached("CreateClass", "ObjectHandling.c"))
#TODO(craig,haoyu) This should be moved to a better place
self.set_qualified_name(env, self.name)
return self
def may_be_none(self):
return True
......@@ -6192,6 +6227,7 @@ class Py3ClassNode(ExprNode):
def analyse_types(self, env):
self.type = py_object_type
self.is_temp = 1
return self
def may_be_none(self):
return True
......@@ -6252,12 +6288,14 @@ class KeywordArgsNode(ExprNode):
return dict_type
def analyse_types(self, env):
self.starstar_arg.analyse_types(env)
self.starstar_arg = self.starstar_arg.coerce_to_pyobject(env).as_none_safe_node(
arg = self.starstar_arg.analyse_types(env)
arg = arg.coerce_to_pyobject(env)
self.starstar_arg = arg.as_none_safe_node(
# FIXME: CPython's error message starts with the runtime function name
'argument after ** must be a mapping, not NoneType')
for item in self.keyword_args:
item.analyse_types(env)
self.keyword_args = [ item.analyse_types(env)
for item in self.keyword_args ]
return self
def may_be_none(self):
return False
......@@ -6336,6 +6374,7 @@ class PyClassMetaclassNode(ExprNode):
def analyse_types(self, env):
self.type = py_object_type
self.is_temp = True
return self
def may_be_none(self):
return True
......@@ -6362,14 +6401,15 @@ class PyClassNamespaceNode(ExprNode, ModuleNameMixin):
subexprs = ['doc']
def analyse_types(self, env):
self.bases.analyse_types(env)
self.bases = self.bases.analyse_types(env)
if self.doc:
self.doc.analyse_types(env)
self.doc = self.doc.analyse_types(env)
self.doc = self.doc.coerce_to_pyobject(env)
self.type = py_object_type
self.is_temp = 1
#TODO(craig,haoyu) This should be moved to a better place
self.set_qualified_name(env, self.name)
return self
def may_be_none(self):
return True
......@@ -6407,6 +6447,7 @@ class ClassCellInjectorNode(ExprNode):
if self.is_active:
env.use_utility_code(
UtilityCode.load_cached("CyFunctionClassCell", "CythonFunction.c"))
return self
def generate_evaluation_code(self, code):
if self.is_active:
......@@ -6431,7 +6472,7 @@ class ClassCellNode(ExprNode):
type = py_object_type
def analyse_types(self, env):
pass
return self
def generate_result_code(self, code):
if not self.is_generator:
......@@ -6460,9 +6501,10 @@ class BoundMethodNode(ExprNode):
subexprs = ['function']
def analyse_types(self, env):
self.function.analyse_types(env)
self.function = self.function.analyse_types(env)
self.type = py_object_type
self.is_temp = 1
return self
gil_message = "Constructing an bound method"
......@@ -6489,7 +6531,8 @@ class UnboundMethodNode(ExprNode):
subexprs = ['function']
def analyse_types(self, env):
self.function.analyse_types(env)
self.function = self.function.analyse_types(env)
return self
def may_be_none(self):
return False
......@@ -6557,6 +6600,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
#TODO(craig,haoyu) This should be moved to a better place
self.set_qualified_name(env, self.def_node.name)
return self
def analyse_default_args(self, env):
"""
......@@ -6602,9 +6646,9 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
if default_args:
if self.defaults_struct is None:
self.defaults_tuple = TupleNode(self.pos, args=[
defaults_tuple = TupleNode(self.pos, args=[
arg.default for arg in default_args])
self.defaults_tuple.analyse_types(env)
self.defaults_tuple = defaults_tuple.analyse_types(env)
else:
defaults_getter = Nodes.DefNode(
self.pos, args=[], star_arg=None, starstar_arg=None,
......@@ -6615,8 +6659,8 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
self.defaults_struct)),
decorators=None, name=StringEncoding.EncodedString("__defaults__"))
defaults_getter.analyse_declarations(env)
defaults_getter.analyse_expressions(env)
defaults_getter.body.analyse_expressions(
defaults_getter = defaults_getter.analyse_expressions(env)
defaults_getter.body = defaults_getter.body.analyse_expressions(
defaults_getter.local_scope)
defaults_getter.py_wrapper_required = False
defaults_getter.pymethdef_required = False
......@@ -6813,7 +6857,7 @@ class DefaultLiteralArgNode(ExprNode):
self.evaluated = False
def analyse_types(self, env):
pass
return self
def generate_result_code(self, code):
pass
......@@ -6840,6 +6884,7 @@ class DefaultNonLiteralArgNode(ExprNode):
def analyse_types(self, env):
self.type = self.arg.type
self.is_temp = False
return self
def generate_result_code(self, code):
pass
......@@ -6887,8 +6932,8 @@ class LambdaNode(InnerFunctionNode):
env.add_lambda_def(self.def_node)
def analyse_types(self, env):
self.def_node.analyse_expressions(env)
super(LambdaNode, self).analyse_types(env)
self.def_node = self.def_node.analyse_expressions(env)
return super(LambdaNode, self).analyse_types(env)
def generate_result_code(self, code):
self.def_node.generate_execution_code(code)
......@@ -6943,9 +6988,10 @@ class YieldExprNode(ExprNode):
error(self.pos, "'yield' not supported here")
self.is_temp = 1
if self.arg is not None:
self.arg.analyse_types(env)
self.arg = self.arg.analyse_types(env)
if not self.arg.type.is_pyobject:
self.coerce_yield_argument(env)
return self
def coerce_yield_argument(self, env):
self.arg = self.arg.coerce_to_pyobject(env)
......@@ -7051,6 +7097,7 @@ class GlobalsExprNode(AtomicExprNode):
def analyse_types(self, env):
env.use_utility_code(Builtin.globals_utility_code)
return self
gil_message = "Constructing globals dict"
......@@ -7063,13 +7110,14 @@ class GlobalsExprNode(AtomicExprNode):
class LocalsDictItemNode(DictItemNode):
def analyse_types(self, env):
self.key.analyse_types(env)
self.value.analyse_types(env)
self.key = self.key.analyse_types(env)
self.value = self.value.analyse_types(env)
self.key = self.key.coerce_to_pyobject(env)
if self.value.type.can_coerce_to_pyobject(env):
self.value = self.value.coerce_to_pyobject(env)
else:
self.value = None
return self
class FuncLocalsExprNode(DictNode):
......@@ -7084,9 +7132,10 @@ class FuncLocalsExprNode(DictNode):
exclude_null_values=True)
def analyse_types(self, env):
super(FuncLocalsExprNode, self).analyse_types(env)
self.key_value_pairs = [i for i in self.key_value_pairs
if i.value is not None]
node = super(FuncLocalsExprNode, self).analyse_types(env)
node.key_value_pairs = [ i for i in node.key_value_pairs
if i.value is not None ]
return node
class PyClassLocalsExprNode(AtomicExprNode):
......@@ -7097,6 +7146,7 @@ class PyClassLocalsExprNode(AtomicExprNode):
def analyse_types(self, env):
self.type = self.pyclass_dict.type
self.is_temp = False
return self
def result(self):
return self.pyclass_dict.result()
......@@ -7172,7 +7222,7 @@ class UnopNode(ExprNode):
return operand_type
def analyse_types(self, env):
self.operand.analyse_types(env)
self.operand = self.operand.analyse_types(env)
if self.is_py_operation():
self.coerce_operand_to_pyobject(env)
self.type = py_object_type
......@@ -7181,6 +7231,7 @@ class UnopNode(ExprNode):
self.analyse_cpp_operation(env)
else:
self.analyse_c_operation(env)
return self
def check_const(self):
return self.operand.check_const()
......@@ -7251,7 +7302,7 @@ class NotNode(UnopNode):
return PyrexTypes.c_bint_type
def analyse_types(self, env):
self.operand.analyse_types(env)
self.operand = self.operand.analyse_types(env)
operand_type = self.operand.type
if operand_type.is_cpp_class:
cpp_type = operand_type.find_cpp_operation_type(self.operator)
......@@ -7262,6 +7313,7 @@ class NotNode(UnopNode):
self.type = cpp_type
else:
self.operand = self.operand.coerce_to_boolean(env)
return self
def calculate_result_code(self):
return "(!%s)" % self.operand.result()
......@@ -7396,23 +7448,24 @@ class AmpersandNode(CUnopNode):
return PyrexTypes.c_ptr_type(operand_type)
def analyse_types(self, env):
self.operand.analyse_types(env)
self.operand = self.operand.analyse_types(env)
argtype = self.operand.type
if argtype.is_cpp_class:
cpp_type = argtype.find_cpp_operation_type(self.operator)
if cpp_type is not None:
self.type = cpp_type
return
return self
if not (argtype.is_cfunction or argtype.is_reference or self.operand.is_addressable()):
if argtype.is_memoryviewslice:
self.error("Cannot take address of memoryview slice")
else:
self.error("Taking address of non-lvalue")
return
return self
if argtype.is_pyobject:
self.error("Cannot take address of Python variable")
return
return self
self.type = PyrexTypes.c_ptr_type(argtype)
return self
def check_const(self):
return self.operand.check_const_addr()
......@@ -7481,7 +7534,7 @@ class TypecastNode(ExprNode):
error(self.pos,
"Cannot cast to a function type")
self.type = PyrexTypes.error_type
self.operand.analyse_types(env)
self.operand = self.operand.analyse_types(env)
to_py = self.type.is_pyobject
from_py = self.operand.type.is_pyobject
if from_py and not to_py and self.operand.is_ephemeral():
......@@ -7520,6 +7573,7 @@ class TypecastNode(ExprNode):
elif self.operand.type.is_fused:
self.operand = self.operand.coerce_to(self.type, env)
#self.type = self.operand.type
return self
def is_simple(self):
# either temp or a C cast => no side effects other than the operand's
......@@ -7617,7 +7671,7 @@ class CythonArrayNode(ExprNode):
def analyse_types(self, env):
import MemoryView
self.operand.analyse_types(env)
self.operand = self.operand.analyse_types(env)
if self.array_dtype:
array_dtype = self.array_dtype
else:
......@@ -7635,7 +7689,7 @@ class CythonArrayNode(ExprNode):
if not self.operand.type.is_ptr and not self.operand.type.is_array:
error(self.operand.pos, ERR_NOT_POINTER)
return
return self
# Dimension sizes of C array
array_dimension_sizes = []
......@@ -7647,16 +7701,16 @@ class CythonArrayNode(ExprNode):
base_type = base_type.base_type
else:
error(self.pos, "unexpected base type %s found" % base_type)
return
return self
if not (base_type.same_as(array_dtype) or base_type.is_void):
error(self.operand.pos, ERR_BASE_TYPE)
return
return self
elif self.operand.type.is_array and len(array_dimension_sizes) != ndim:
error(self.operand.pos,
"Expected %d dimensions, array has %d dimensions" %
(ndim, len(array_dimension_sizes)))
return
return self
# Verify the start, stop and step values
# In case of a C array, use the size of C array in each dimension to
......@@ -7664,7 +7718,7 @@ class CythonArrayNode(ExprNode):
for axis_no, axis in enumerate(axes):
if not axis.start.is_none:
error(axis.start.pos, ERR_START)
return
return self
if axis.stop.is_none:
if array_dimension_sizes:
......@@ -7674,9 +7728,9 @@ class CythonArrayNode(ExprNode):
type=PyrexTypes.c_int_type)
else:
error(axis.pos, ERR_NOT_STOP)
return
return self
axis.stop.analyse_types(env)
axis.stop = axis.stop.analyse_types(env)
shape = axis.stop.coerce_to(self.shape_type, env)
if not shape.is_literal:
shape.coerce_to_temp(env)
......@@ -7686,15 +7740,15 @@ class CythonArrayNode(ExprNode):
first_or_last = axis_no in (0, ndim - 1)
if not axis.step.is_none and first_or_last:
# '1' in the first or last dimension denotes F or C contiguity
axis.step.analyse_types(env)
axis.step = axis.step.analyse_types(env)
if (not axis.step.type.is_int and axis.step.is_literal and not
axis.step.type.is_error):
error(axis.step.pos, "Expected an integer literal")
return
return self
if axis.step.compile_time_value(env) != 1:
error(axis.step.pos, ERR_STEPS)
return
return self
if axis_no == 0:
self.mode = "fortran"
......@@ -7702,7 +7756,7 @@ class CythonArrayNode(ExprNode):
elif not axis.step.is_none and not first_or_last:
# step provided in some other dimension
error(axis.step.pos, ERR_STEPS)
return
return self
if not self.operand.is_name:
self.operand = self.operand.coerce_to_temp(env)
......@@ -7717,6 +7771,7 @@ class CythonArrayNode(ExprNode):
self.type = self.get_cython_array_type(env)
MemoryView.use_cython_array_utility_code(env)
env.use_utility_code(MemoryView.typeinfo_to_format_code)
return self
def allocate_temp_result(self, code):
if self.temp_code:
......@@ -7800,7 +7855,7 @@ class CythonArrayNode(ExprNode):
base_type_node=base_type)
result = CythonArrayNode(pos, base_type_node=memslicenode,
operand=src_node, array_dtype=base_type)
result.analyse_types(env)
result = result.analyse_types(env)
return result
class SizeofNode(ExprNode):
......@@ -7837,13 +7892,14 @@ class SizeofTypeNode(SizeofNode):
operand = AttributeNode(pos=self.pos, obj=operand, attribute=self.base_type.name)
self.operand = operand
self.__class__ = SizeofVarNode
self.analyse_types(env)
return
node = self.analyse_types(env)
return node
if self.arg_type is None:
base_type = self.base_type.analyse(env)
_, arg_type = self.declarator.analyse(base_type, env)
self.arg_type = arg_type
self.check_type()
return self
def check_type(self):
arg_type = self.arg_type
......@@ -7882,7 +7938,8 @@ class SizeofVarNode(SizeofNode):
self.__class__ = SizeofTypeNode
self.check_type()
else:
self.operand.analyse_types(env)
self.operand = self.operand.analyse_types(env)
return self
def calculate_result_code(self):
return "(sizeof(%s))" % self.operand.result()
......@@ -7902,11 +7959,12 @@ class TypeofNode(ExprNode):
subexprs = ['literal'] # 'operand' will be ignored after type analysis!
def analyse_types(self, env):
self.operand.analyse_types(env)
self.operand = self.operand.analyse_types(env)
value = StringEncoding.EncodedString(str(self.operand.type)) #self.operand.type.typeof_name())
self.literal = StringNode(self.pos, value=value)
self.literal.analyse_types(env)
self.literal = self.literal.coerce_to_pyobject(env)
literal = StringNode(self.pos, value=value)
literal = literal.analyse_types(env)
self.literal = literal.coerce_to_pyobject(env)
return self
def may_be_none(self):
return False
......@@ -7995,9 +8053,10 @@ class BinopNode(ExprNode):
self.operand2.infer_type(env))
def analyse_types(self, env):
self.operand1.analyse_types(env)
self.operand2.analyse_types(env)
self.operand1 = self.operand1.analyse_types(env)
self.operand2 = self.operand2.analyse_types(env)
self.analyse_operation(env)
return self
def analyse_operation(self, env):
if self.is_py_operation():
......@@ -8109,9 +8168,10 @@ class BinopNode(ExprNode):
class CBinopNode(BinopNode):
def analyse_types(self, env):
BinopNode.analyse_types(self, env)
if self.is_py_operation():
self.type = PyrexTypes.error_type
node = BinopNode.analyse_types(self, env)
if node.is_py_operation():
node.type = PyrexTypes.error_type
return node
def py_operation_function(self):
return ""
......@@ -8604,8 +8664,8 @@ class BoolBinopNode(ExprNode):
is_temp = self.is_temp)
def analyse_types(self, env):
self.operand1.analyse_types(env)
self.operand2.analyse_types(env)
self.operand1 = self.operand1.analyse_types(env)
self.operand2 = self.operand2.analyse_types(env)
self.type = PyrexTypes.independent_spanning_type(self.operand1.type, self.operand2.type)
self.operand1 = self.operand1.coerce_to(self.type, env)
self.operand2 = self.operand2.coerce_to(self.type, env)
......@@ -8615,6 +8675,7 @@ class BoolBinopNode(ExprNode):
self.operand1 = self.operand1.coerce_to_simple(env)
self.operand2 = self.operand2.coerce_to_simple(env)
self.is_temp = 1
return self
gil_message = "Truth-testing Python object"
......@@ -8690,10 +8751,9 @@ class CondExprNode(ExprNode):
self.constant_result = self.false_val.constant_result
def analyse_types(self, env):
self.test.analyse_types(env)
self.test = self.test.coerce_to_boolean(env)
self.true_val.analyse_types(env)
self.false_val.analyse_types(env)
self.test = self.test.analyse_types(env).coerce_to_boolean(env)
self.true_val = self.true_val.analyse_types(env)
self.false_val = self.false_val.analyse_types(env)
self.type = PyrexTypes.independent_spanning_type(self.true_val.type, self.false_val.type)
if self.true_val.type.is_pyobject or self.false_val.type.is_pyobject:
self.true_val = self.true_val.coerce_to(self.type, env)
......@@ -8701,6 +8761,7 @@ class CondExprNode(ExprNode):
self.is_temp = 1
if self.type == PyrexTypes.error_type:
self.type_error()
return self
def type_error(self):
if not (self.true_val.type.is_error or self.false_val.type.is_error):
......@@ -9083,19 +9144,19 @@ class PrimaryCmpNode(ExprNode, CmpNode):
return self.cascaded_compile_time_value(operand1, denv)
def analyse_types(self, env):
self.operand1.analyse_types(env)
self.operand2.analyse_types(env)
self.operand1 = self.operand1.analyse_types(env)
self.operand2 = self.operand2.analyse_types(env)
if self.is_cpp_comparison():
self.analyse_cpp_comparison(env)
if self.cascade:
error(self.pos, "Cascading comparison not yet supported for cpp types.")
return
return self
if self.analyse_memoryviewslice_comparison(env):
return
return self
if self.cascade:
self.cascade.analyse_types(env)
self.cascade = self.cascade.analyse_types(env)
if self.operator in ('in', 'not_in'):
if self.is_c_string_contains():
......@@ -9103,7 +9164,7 @@ class PrimaryCmpNode(ExprNode, CmpNode):
common_type = None
if self.cascade:
error(self.pos, "Cascading comparison not yet supported for 'int_val in string'.")
return
return self
if self.operand2.type is unicode_type:
env.use_utility_code(UtilityCode.load_cached("PyUCS4InUnicode", "StringTools.c"))
else:
......@@ -9119,7 +9180,7 @@ class PrimaryCmpNode(ExprNode, CmpNode):
error(self.pos, "Cascading comparison not supported for 'val in sliced pointer'.")
self.type = PyrexTypes.c_bint_type
# Will be transformed by IterationTransform
return
return self
elif self.find_special_bool_compare_function(env, self.operand1):
if not self.operand1.type.is_pyobject:
self.operand1 = self.operand1.coerce_to_pyobject(env)
......@@ -9159,6 +9220,7 @@ class PrimaryCmpNode(ExprNode, CmpNode):
if self.is_pycmp or self.cascade or self.special_bool_cmp_function:
# 1) owned reference, 2) reused value, 3) potential function error return value
self.is_temp = 1
return self
def analyse_cpp_comparison(self, env):
type1 = self.operand1.type
......@@ -9306,9 +9368,10 @@ class CascadedCmpNode(Node, CmpNode):
self.constant_result is not not_a_constant
def analyse_types(self, env):
self.operand2.analyse_types(env)
self.operand2 = self.operand2.analyse_types(env)
if self.cascade:
self.cascade.analyse_types(env)
self.cascade = self.cascade.analyse_types(env)
return self
def has_python_operands(self):
return self.operand2.type.is_pyobject
......@@ -9487,7 +9550,7 @@ class PyTypeTestNode(CoercionNode):
gil_message = "Python type test"
def analyse_types(self, env):
pass
return self
def may_be_none(self):
if self.notnone:
......@@ -9551,7 +9614,7 @@ class NoneCheckNode(CoercionNode):
nogil_check = None # this node only guards an operation that would fail already
def analyse_types(self, env):
pass
return self
def may_be_none(self):
return False
......@@ -9669,7 +9732,7 @@ class CoerceToPyTypeNode(CoercionNode):
def analyse_types(self, env):
# The arg is always already analysed
pass
return self
def generate_result_code(self, code):
if self.arg.type.is_memoryviewslice:
......@@ -9748,7 +9811,7 @@ class CoerceFromPyTypeNode(CoercionNode):
def analyse_types(self, env):
# The arg is always already analysed
pass
return self
def generate_result_code(self, code):
function = self.type.from_py_function
......@@ -9858,7 +9921,7 @@ class CoerceToTempNode(CoercionNode):
def analyse_types(self, env):
# The arg is always already analysed
pass
return self
def coerce_to_boolean(self, env):
self.arg = self.arg.coerce_to_boolean(env)
......@@ -9896,8 +9959,9 @@ class ProxyNode(CoercionNode):
self._proxy_type()
def analyse_expressions(self, env):
self.arg.analyse_expressions(env)
self.arg = self.arg.analyse_expressions(env)
self._proxy_type()
return self
def _proxy_type(self):
if hasattr(self.arg, 'type'):
......@@ -9967,6 +10031,7 @@ class CloneNode(CoercionNode):
self.is_temp = 1
if hasattr(self.arg, 'entry'):
self.entry = self.arg.entry
return self
def is_simple(self):
return True # result is always in a temp (or a name)
......@@ -10004,7 +10069,7 @@ class ModuleRefNode(ExprNode):
subexprs = []
def analyse_types(self, env):
pass
return self
def may_be_none(self):
return False
......@@ -10028,7 +10093,7 @@ class DocstringRefNode(ExprNode):
self.body = body
def analyse_types(self, env):
pass
return self
def generate_result_code(self, code):
code.putln('%s = __Pyx_GetAttr(%s, %s); %s' % (
......
......@@ -673,22 +673,22 @@ class FusedCFuncDefNode(StatListNode):
specialization_type.create_declaration_utility_code(env)
if self.py_func:
self.__signatures__.analyse_expressions(env)
self.py_func.analyse_expressions(env)
self.resulting_fused_function.analyse_expressions(env)
self.fused_func_assignment.analyse_expressions(env)
self.__signatures__ = self.__signatures__.analyse_expressions(env)
self.py_func = self.py_func.analyse_expressions(env)
self.resulting_fused_function = self.resulting_fused_function.analyse_expressions(env)
self.fused_func_assignment = self.fused_func_assignment.analyse_expressions(env)
self.defaults = defaults = []
for arg in self.node.args:
if arg.default:
arg.default.analyse_expressions(env)
arg.default = arg.default.analyse_expressions(env)
defaults.append(ProxyNode(arg.default))
else:
defaults.append(None)
for stat in self.stats:
stat.analyse_expressions(env)
for i, stat in enumerate(self.stats):
stat = self.stats[i] = stat.analyse_expressions(env)
if isinstance(stat, FuncDefNode):
for arg, default in zip(stat.args, defaults):
if default is not None:
......@@ -697,7 +697,7 @@ class FusedCFuncDefNode(StatListNode):
if self.py_func:
args = [CloneNode(default) for default in defaults if default]
self.defaults_tuple = TupleNode(self.pos, args=args)
self.defaults_tuple.analyse_types(env, skip_children=True)
self.defaults_tuple = self.defaults_tuple.analyse_types(env, skip_children=True)
self.defaults_tuple = ProxyNode(self.defaults_tuple)
self.code_object = ProxyNode(self.specialized_pycfuncs[0].code_object)
......@@ -705,10 +705,11 @@ class FusedCFuncDefNode(StatListNode):
fused_func.defaults_tuple = CloneNode(self.defaults_tuple)
fused_func.code_object = CloneNode(self.code_object)
for pycfunc in self.specialized_pycfuncs:
for i, pycfunc in enumerate(self.specialized_pycfuncs):
pycfunc.code_object = CloneNode(self.code_object)
pycfunc.analyse_types(env)
pycfunc = self.specialized_pycfuncs[i] = pycfunc.analyse_types(env)
pycfunc.defaults_tuple = CloneNode(self.defaults_tuple)
return self
def synthesize_defnodes(self):
"""
......
......@@ -75,12 +75,9 @@ def embed_position(pos, docstring):
return doc
from Code import CCodeWriter
from types import FunctionType
def write_func_call(func):
def write_func_call(func, codewriter_class):
def f(*args, **kwds):
if len(args) > 1 and isinstance(args[1], CCodeWriter):
if len(args) > 1 and isinstance(args[1], codewriter_class):
# here we annotate the code with this function call
# but only if new code is generated
node, code = args[:2]
......@@ -109,18 +106,45 @@ class VerboseCodeWriter(type):
# Set this as a metaclass to trace function calls in code.
# This slows down code generation and makes much larger files.
def __new__(cls, name, bases, attrs):
from types import FunctionType
from Code import CCodeWriter
attrs = dict(attrs)
for mname, m in attrs.items():
if isinstance(m, FunctionType):
attrs[mname] = write_func_call(m)
attrs[mname] = write_func_call(m, CCodeWriter)
return super(VerboseCodeWriter, cls).__new__(cls, name, bases, attrs)
class CheckAnalysers(type):
"""Metaclass to check that type analysis functions return a node.
"""
methods = set(['analyse_types',
'analyse_expressions',
'analyse_target_types'])
def __new__(cls, name, bases, attrs):
from types import FunctionType
def check(name, func):
def call(*args, **kwargs):
retval = func(*args, **kwargs)
if retval is None:
print name, args, kwargs
return retval
return call
attrs = dict(attrs)
for mname, m in attrs.items():
if isinstance(m, FunctionType) and mname in cls.methods:
attrs[mname] = check(mname, m)
return super(CheckAnalysers, cls).__new__(cls, name, bases, attrs)
class Node(object):
# pos (string, int, int) Source file position
# is_name boolean Is a NameNode
# is_literal boolean Is a ConstNode
#__metaclass__ = CheckAnalysers
if DebugFlags.debug_trace_code_generation:
__metaclass__ = VerboseCodeWriter
......@@ -305,8 +329,9 @@ class CompilerDirectivesNode(Node):
def analyse_expressions(self, env):
old = env.directives
env.directives = self.directives
self.body.analyse_expressions(env)
self.body = self.body.analyse_expressions(env)
env.directives = old
return self
def generate_function_definitions(self, env, code):
env_old = env.directives
......@@ -358,8 +383,9 @@ class StatListNode(Node):
def analyse_expressions(self, env):
#print "StatListNode.analyse_expressions" ###
for stat in self.stats:
stat.analyse_expressions(env)
self.stats = [ stat.analyse_expressions(env)
for stat in self.stats ]
return self
def generate_function_definitions(self, env, code):
#print "StatListNode.generate_function_definitions" ###
......@@ -413,7 +439,7 @@ class CDefExternNode(StatNode):
env.in_cinclude = old_cinclude_flag
def analyse_expressions(self, env):
pass
return self
def generate_execution_code(self, code):
pass
......@@ -604,7 +630,7 @@ class CFuncDeclaratorNode(CDeclaratorNode):
if self.exception_value:
self.exception_value.analyse_const_expression(env)
if self.exception_check == '+':
self.exception_value.analyse_types(env)
self.exception_value = self.exception_value.analyse_types(env)
exc_val_type = self.exception_value.type
if not exc_val_type.is_error and \
not exc_val_type.is_pyobject and \
......@@ -1206,7 +1232,7 @@ class CStructOrUnionDefNode(StatNode):
error(attr.pos, "Struct cannot contain itself as a member.")
def analyse_expressions(self, env):
pass
return self
def generate_execution_code(self, code):
pass
......@@ -1270,7 +1296,8 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode):
self.scope = scope
def analyse_expressions(self, env):
self.body.analyse_expressions(self.entry.type.scope)
self.body = self.body.analyse_expressions(self.entry.type.scope)
return self
def generate_function_definitions(self, env, code):
self.body.generate_function_definitions(self.entry.type.scope, code)
......@@ -1307,7 +1334,7 @@ class CEnumDefNode(StatNode):
item.analyse_declarations(env, self.entry)
def analyse_expressions(self, env):
pass
return self
def generate_execution_code(self, code):
if self.visibility == 'public' or self.api:
......@@ -1371,7 +1398,8 @@ class CTypeDefNode(StatNode):
entry.defined_in_pxd = 1
def analyse_expressions(self, env):
pass
return self
def generate_execution_code(self, code):
pass
......@@ -1413,7 +1441,7 @@ class FuncDefNode(StatNode, BlockNode):
if arg.default:
default_seen = 1
if arg.is_generic:
arg.default.analyse_types(env)
arg.default = arg.default.analyse_types(env)
arg.default = arg.default.coerce_to(arg.type, env)
else:
error(arg.pos,
......@@ -2173,10 +2201,11 @@ class CFuncDefNode(FuncDefNode):
self.local_scope.directives = env.directives
if self.py_func is not None:
# this will also analyse the default values
self.py_func.analyse_expressions(env)
self.py_func = self.py_func.analyse_expressions(env)
else:
self.analyse_default_values(env)
self.acquire_gil = self.need_gil_acquisition(self.local_scope)
return self
def needs_assignment_synthesis(self, env, code=None):
return False
......@@ -2719,9 +2748,10 @@ class DefNode(FuncDefNode):
if not self.needs_assignment_synthesis(env) and self.decorators:
for decorator in self.decorators[::-1]:
decorator.decorator.analyse_expressions(env)
decorator.decorator = decorator.decorator.analyse_expressions(env)
self.py_wrapper.prepare_argument_coercion(env)
return self
def needs_assignment_synthesis(self, env, code=None):
if self.is_wrapper or self.specialized_cpdefs or self.entry.is_fused_specialized:
......@@ -3802,9 +3832,11 @@ class OverrideCheckNode(StatNode):
self.func_node = ExprNodes.RawCNameExprNode(self.pos, py_object_type)
call_node = ExprNodes.SimpleCallNode(
self.pos, function=self.func_node,
args=[ExprNodes.NameNode(self.pos, name=arg.name) for arg in self.args[first_arg:]])
args=[ ExprNodes.NameNode(self.pos, name=arg.name)
for arg in self.args[first_arg:] ])
self.body = ReturnStatNode(self.pos, value=call_node)
self.body.analyse_expressions(env)
self.body = self.body.analyse_expressions(env)
return self
def generate_execution_code(self, code):
interned_attr_cname = code.intern_identifier(self.py_func.entry.name)
......@@ -3985,16 +4017,17 @@ class PyClassDefNode(ClassDefNode):
def analyse_expressions(self, env):
if self.py3_style_class:
self.bases.analyse_expressions(env)
self.metaclass.analyse_expressions(env)
self.mkw.analyse_expressions(env)
self.dict.analyse_expressions(env)
self.class_result.analyse_expressions(env)
self.bases = self.bases.analyse_expressions(env)
self.metaclass = self.metaclass.analyse_expressions(env)
self.mkw = self.mkw.analyse_expressions(env)
self.dict = self.dict.analyse_expressions(env)
self.class_result = self.class_result.analyse_expressions(env)
genv = env.global_scope()
cenv = self.scope
self.body.analyse_expressions(cenv)
self.body = self.body.analyse_expressions(cenv)
self.target.analyse_target_expression(env, self.classobj)
self.class_cell.analyse_expressions(cenv)
self.class_cell = self.class_cell.analyse_expressions(cenv)
return self
def generate_function_definitions(self, env, code):
self.generate_lambda_definitions(self.scope, code)
......@@ -4205,7 +4238,8 @@ class CClassDefNode(ClassDefNode):
def analyse_expressions(self, env):
if self.body:
scope = self.entry.type.scope
self.body.analyse_expressions(scope)
self.body = self.body.analyse_expressions(scope)
return self
def generate_function_definitions(self, env, code):
if self.body:
......@@ -4239,7 +4273,8 @@ class PropertyNode(StatNode):
self.body.analyse_declarations(entry.scope)
def analyse_expressions(self, env):
self.body.analyse_expressions(env)
self.body = self.body.analyse_expressions(env)
return self
def generate_function_definitions(self, env, code):
self.body.generate_function_definitions(env, code)
......@@ -4263,7 +4298,7 @@ class GlobalNode(StatNode):
env.declare_global(name, self.pos)
def analyse_expressions(self, env):
pass
return self
def generate_execution_code(self, code):
pass
......@@ -4281,7 +4316,7 @@ class NonlocalNode(StatNode):
env.declare_nonlocal(name, self.pos)
def analyse_expressions(self, env):
pass
return self
def generate_execution_code(self, code):
pass
......@@ -4312,7 +4347,8 @@ class ExprStatNode(StatNode):
def analyse_expressions(self, env):
self.expr.result_is_used = False # hint that .result() may safely be left empty
self.expr.analyse_expressions(env)
self.expr = self.expr.analyse_expressions(env)
return self
def nogil_check(self, env):
if self.expr.type.is_pyobject and self.expr.is_temp:
......@@ -4344,7 +4380,7 @@ class AssignmentNode(StatNode):
# to any of the left hand sides.
def analyse_expressions(self, env):
self.analyse_types(env)
return self.analyse_types(env)
# def analyse_expressions(self, env):
# self.analyse_expressions_1(env)
......@@ -4449,8 +4485,8 @@ class SingleAssignmentNode(AssignmentNode):
def analyse_types(self, env, use_temp = 0):
import ExprNodes
self.rhs.analyse_types(env)
self.lhs.analyse_target_types(env)
self.rhs = self.rhs.analyse_types(env)
self.lhs = self.lhs.analyse_target_types(env)
self.lhs.gil_assignment_check(env)
if self.lhs.memslice_broadcast or self.rhs.memslice_broadcast:
......@@ -4474,6 +4510,7 @@ class SingleAssignmentNode(AssignmentNode):
self.rhs = self.rhs.coerce_to_temp(env)
elif self.rhs.type.is_pyobject:
self.rhs = self.rhs.coerce_to_simple(env)
return self
def generate_rhs_evaluation_code(self, code):
self.rhs.generate_evaluation_code(code)
......@@ -4511,7 +4548,7 @@ class CascadedAssignmentNode(AssignmentNode):
def analyse_types(self, env, use_temp = 0):
from ExprNodes import CloneNode, ProxyNode
self.rhs.analyse_types(env)
self.rhs = self.rhs.analyse_types(env)
if use_temp or self.rhs.is_attribute:
# (cdef) attribute access is not safe as it traverses pointers
self.rhs = self.rhs.coerce_to_temp(env)
......@@ -4526,6 +4563,7 @@ class CascadedAssignmentNode(AssignmentNode):
rhs = CloneNode(self.rhs)
rhs = rhs.coerce_to(lhs.type, env)
self.coerced_rhs_list.append(rhs)
return self
def generate_rhs_evaluation_code(self, code):
self.rhs.generate_evaluation_code(code)
......@@ -4571,8 +4609,9 @@ class ParallelAssignmentNode(AssignmentNode):
stat.analyse_declarations(env)
def analyse_expressions(self, env):
for stat in self.stats:
stat.analyse_types(env, use_temp = 1)
self.stats = [ stat.analyse_types(env, use_temp = 1)
for stat in self.stats ]
return self
# def analyse_expressions(self, env):
# for stat in self.stats:
......@@ -4621,13 +4660,14 @@ class InPlaceAssignmentNode(AssignmentNode):
def analyse_types(self, env):
import ExprNodes
self.rhs.analyse_types(env)
self.lhs.analyse_target_types(env)
self.rhs = self.rhs.analyse_types(env)
self.lhs = self.lhs.analyse_target_types(env)
# When assigning to a fully indexed buffer or memoryview, coerce the rhs
if (isinstance(self.lhs, ExprNodes.IndexNode) and
(self.lhs.memslice_index or self.lhs.is_buffer_access)):
self.rhs = self.rhs.coerce_to(self.lhs.type, env)
return self
def generate_execution_code(self, code):
import ExprNodes
......@@ -4674,13 +4714,14 @@ class PrintStatNode(StatNode):
def analyse_expressions(self, env):
if self.stream:
self.stream.analyse_expressions(env)
self.stream = self.stream.coerce_to_pyobject(env)
self.arg_tuple.analyse_expressions(env)
self.arg_tuple = self.arg_tuple.coerce_to_pyobject(env)
stream = self.stream.analyse_expressions(env)
self.stream = stream.coerce_to_pyobject(env)
arg_tuple = self.arg_tuple.analyse_expressions(env)
self.arg_tuple = arg_tuple.coerce_to_pyobject(env)
env.use_utility_code(printing_utility_code)
if len(self.arg_tuple.args) == 1 and self.append_newline:
env.use_utility_code(printing_one_utility_code)
return self
nogil_check = Node.gil_error
gil_message = "Python print statement"
......@@ -4737,10 +4778,11 @@ class ExecStatNode(StatNode):
def analyse_expressions(self, env):
for i, arg in enumerate(self.args):
arg.analyse_expressions(env)
arg = arg.analyse_expressions(env)
arg = arg.coerce_to_pyobject(env)
self.args[i] = arg
env.use_utility_code(Builtin.pyexec_utility_code)
return self
nogil_check = Node.gil_error
gil_message = "Python exec statement"
......@@ -4781,8 +4823,8 @@ class DelStatNode(StatNode):
arg.analyse_target_declaration(env)
def analyse_expressions(self, env):
for arg in self.args:
arg.analyse_target_expression(env, None)
for i, arg in enumerate(self.args):
arg = self.args[i] = arg.analyse_target_expression(env, None)
if arg.type.is_pyobject or (arg.is_name and
arg.type.is_memoryviewslice):
pass
......@@ -4793,6 +4835,7 @@ class DelStatNode(StatNode):
else:
error(arg.pos, "Deletion of non-Python, non-C++ object")
#arg.release_target_temp(env)
return self
def nogil_check(self, env):
for arg in self.args:
......@@ -4822,7 +4865,7 @@ class PassStatNode(StatNode):
child_attrs = []
def analyse_expressions(self, env):
pass
return self
def generate_execution_code(self, code):
pass
......@@ -4843,7 +4886,7 @@ class BreakStatNode(StatNode):
is_terminator = True
def analyse_expressions(self, env):
pass
return self
def generate_execution_code(self, code):
if not code.break_label:
......@@ -4858,7 +4901,7 @@ class ContinueStatNode(StatNode):
is_terminator = True
def analyse_expressions(self, env):
pass
return self
def generate_execution_code(self, code):
if code.funcstate.in_try_finally:
......@@ -4888,9 +4931,9 @@ class ReturnStatNode(StatNode):
self.return_type = return_type
if not return_type:
error(self.pos, "Return not inside a function body")
return
return self
if self.value:
self.value.analyse_types(env)
self.value = self.value.analyse_types(env)
if return_type.is_void or return_type.is_returncode:
error(self.value.pos,
"Return with value in void function")
......@@ -4901,6 +4944,7 @@ class ReturnStatNode(StatNode):
and not return_type.is_pyobject
and not return_type.is_returncode):
error(self.pos, "Return value required")
return self
def nogil_check(self, env):
if self.return_type.is_pyobject:
......@@ -4981,17 +5025,17 @@ class RaiseStatNode(StatNode):
def analyse_expressions(self, env):
if self.exc_type:
self.exc_type.analyse_types(env)
self.exc_type = self.exc_type.coerce_to_pyobject(env)
exc_type = self.exc_type.analyse_types(env)
self.exc_type = exc_type.coerce_to_pyobject(env)
if self.exc_value:
self.exc_value.analyse_types(env)
self.exc_value = self.exc_value.coerce_to_pyobject(env)
exc_value = self.exc_value.analyse_types(env)
self.exc_value = exc_value.coerce_to_pyobject(env)
if self.exc_tb:
self.exc_tb.analyse_types(env)
self.exc_tb = self.exc_tb.coerce_to_pyobject(env)
exc_tb = self.exc_tb.analyse_types(env)
self.exc_tb = exc_tb.coerce_to_pyobject(env)
if self.cause:
self.cause.analyse_types(env)
self.cause = self.cause.coerce_to_pyobject(env)
cause = self.cause.analyse_types(env)
self.cause = cause.coerce_to_pyobject(env)
# special cases for builtin exceptions
self.builtin_exc_name = None
if self.exc_type and not self.exc_value and not self.exc_tb:
......@@ -5005,6 +5049,7 @@ class RaiseStatNode(StatNode):
self.builtin_exc_name = exc.name
if self.builtin_exc_name == 'MemoryError':
self.exc_type = None # has a separate implementation
return self
nogil_check = Node.gil_error
gil_message = "Raising exception"
......@@ -5075,7 +5120,7 @@ class ReraiseStatNode(StatNode):
is_terminator = True
def analyse_expressions(self, env):
pass
return self
nogil_check = Node.gil_error
gil_message = "Raising exception"
......@@ -5107,8 +5152,9 @@ class AssertStatNode(StatNode):
def analyse_expressions(self, env):
self.cond = self.cond.analyse_boolean_expression(env)
if self.value:
self.value.analyse_types(env)
self.value = self.value.coerce_to_pyobject(env)
value = self.value.analyse_types(env)
self.value = value.coerce_to_pyobject(env)
return self
nogil_check = Node.gil_error
gil_message = "Raising exception"
......@@ -5163,10 +5209,11 @@ class IfStatNode(StatNode):
self.else_clause.analyse_declarations(env)
def analyse_expressions(self, env):
for if_clause in self.if_clauses:
if_clause.analyse_expressions(env)
self.if_clauses = [ if_clause.analyse_expressions(env)
for if_clause in self.if_clauses ]
if self.else_clause:
self.else_clause.analyse_expressions(env)
self.else_clause = self.else_clause.analyse_expressions(env)
return self
def generate_execution_code(self, code):
code.mark_pos(self.pos)
......@@ -5206,7 +5253,8 @@ class IfClauseNode(Node):
def analyse_expressions(self, env):
self.condition = \
self.condition.analyse_temp_boolean_expression(env)
self.body.analyse_expressions(env)
self.body = self.body.analyse_expressions(env)
return self
def get_constant_condition_result(self):
if self.condition.has_constant_result():
......@@ -5315,9 +5363,10 @@ class WhileStatNode(LoopNode, StatNode):
def analyse_expressions(self, env):
if self.condition:
self.condition = self.condition.analyse_temp_boolean_expression(env)
self.body.analyse_expressions(env)
self.body = self.body.analyse_expressions(env)
if self.else_clause:
self.else_clause.analyse_expressions(env)
self.else_clause = self.else_clause.analyse_expressions(env)
return self
def generate_execution_code(self, code):
old_loop_labels = code.new_loop_labels()
......@@ -5384,22 +5433,24 @@ class DictIterationNextNode(Node):
def analyse_expressions(self, env):
import ExprNodes
self.dict_obj.analyse_types(env)
self.expected_size.analyse_types(env)
if self.pos_index_var: self.pos_index_var.analyse_types(env)
self.dict_obj = self.dict_obj.analyse_types(env)
self.expected_size = self.expected_size.analyse_types(env)
if self.pos_index_var:
self.pos_index_var = self.pos_index_var.analyse_types(env)
if self.key_target:
self.key_target.analyse_target_types(env)
self.key_target = self.key_target.analyse_target_types(env)
self.key_ref = ExprNodes.TempNode(self.key_target.pos, PyrexTypes.py_object_type)
self.coerced_key_var = self.key_ref.coerce_to(self.key_target.type, env)
if self.value_target:
self.value_target.analyse_target_types(env)
self.value_target = self.value_target.analyse_target_types(env)
self.value_ref = ExprNodes.TempNode(self.value_target.pos, type=PyrexTypes.py_object_type)
self.coerced_value_var = self.value_ref.coerce_to(self.value_target.type, env)
if self.tuple_target:
self.tuple_target.analyse_target_types(env)
self.tuple_target = self.tuple_target.analyse_target_types(env)
self.tuple_ref = ExprNodes.TempNode(self.tuple_target.pos, PyrexTypes.py_object_type)
self.coerced_tuple_var = self.tuple_ref.coerce_to(self.tuple_target.type, env)
self.is_dict_flag.analyse_types(env)
self.is_dict_flag = self.is_dict_flag.analyse_types(env)
return self
def generate_function_definitions(self, env, code):
self.dict_obj.generate_function_definitions(env, code)
......@@ -5472,22 +5523,23 @@ class ForInStatNode(LoopNode, StatNode):
self.item = ExprNodes.NextNode(self.iterator)
def analyse_expressions(self, env):
self.target.analyse_target_types(env)
self.iterator.analyse_expressions(env)
self.target = self.target.analyse_target_types(env)
self.iterator = self.iterator.analyse_expressions(env)
if self.item is None:
# Hack. Sometimes analyse_declarations not called.
import ExprNodes
self.item = ExprNodes.NextNode(self.iterator)
self.item.analyse_expressions(env)
self.item = self.item.analyse_expressions(env)
if (self.iterator.type.is_ptr or self.iterator.type.is_array) and \
self.target.type.assignable_from(self.iterator.type):
# C array slice optimization.
pass
else:
self.item = self.item.coerce_to(self.target.type, env)
self.body.analyse_expressions(env)
self.body = self.body.analyse_expressions(env)
if self.else_clause:
self.else_clause.analyse_expressions(env)
self.else_clause = self.else_clause.analyse_expressions(env)
return self
def generate_execution_code(self, code):
old_loop_labels = code.new_loop_labels()
......@@ -5581,13 +5633,13 @@ class ForFromStatNode(LoopNode, StatNode):
def analyse_expressions(self, env):
import ExprNodes
self.target.analyse_target_types(env)
self.bound1.analyse_types(env)
self.bound2.analyse_types(env)
self.target = self.target.analyse_target_types(env)
self.bound1 = self.bound1.analyse_types(env)
self.bound2 = self.bound2.analyse_types(env)
if self.step is not None:
if isinstance(self.step, ExprNodes.UnaryMinusNode):
warning(self.step.pos, "Probable infinite loop in for-from-by statement. Consider switching the directions of the relations.", 2)
self.step.analyse_types(env)
self.step = self.step.analyse_types(env)
if self.target.type.is_numeric:
loop_type = self.target.type
......@@ -5624,9 +5676,10 @@ class ForFromStatNode(LoopNode, StatNode):
self.loopvar_node = c_loopvar_node
self.py_loopvar_node = \
ExprNodes.CloneNode(c_loopvar_node).coerce_to_pyobject(env)
self.body.analyse_expressions(env)
self.body = self.body.analyse_expressions(env)
if self.else_clause:
self.else_clause.analyse_expressions(env)
self.else_clause = self.else_clause.analyse_expressions(env)
return self
def generate_execution_code(self, code):
old_loop_labels = code.new_loop_labels()
......@@ -5781,9 +5834,10 @@ class WithStatNode(StatNode):
self.body.analyse_declarations(env)
def analyse_expressions(self, env):
self.manager.analyse_types(env)
self.enter_call.analyse_types(env)
self.body.analyse_expressions(env)
self.manager = self.manager.analyse_types(env)
self.enter_call = self.enter_call.analyse_types(env)
self.body = self.body.analyse_expressions(env)
return self
def generate_function_definitions(self, env, code):
self.manager.generate_function_definitions(env, code)
......@@ -5851,10 +5905,11 @@ class WithTargetAssignmentStatNode(AssignmentNode):
self.lhs.analyse_target_declaration(env)
def analyse_expressions(self, env):
self.rhs.analyse_types(env)
self.lhs.analyse_target_types(env)
self.rhs = self.rhs.analyse_types(env)
self.lhs = self.lhs.analyse_target_types(env)
self.lhs.gil_assignment_check(env)
self.rhs = self.rhs.coerce_to(self.lhs.type, env)
return self
def generate_execution_code(self, code):
if self.orig_rhs.type.is_pyobject:
......@@ -5901,17 +5956,18 @@ class TryExceptStatNode(StatNode):
env.use_utility_code(reset_exception_utility_code)
def analyse_expressions(self, env):
self.body.analyse_expressions(env)
self.body = self.body.analyse_expressions(env)
default_clause_seen = 0
for except_clause in self.except_clauses:
except_clause.analyse_expressions(env)
for i, except_clause in enumerate(self.except_clauses):
except_clause = self.except_clauses[i] = except_clause.analyse_expressions(env)
if default_clause_seen:
error(except_clause.pos, "default 'except:' must be last")
if not except_clause.pattern:
default_clause_seen = 1
self.has_default_clause = default_clause_seen
if self.else_clause:
self.else_clause.analyse_expressions(env)
self.else_clause = self.else_clause.analyse_expressions(env)
return self
nogil_check = Node.gil_error
gil_message = "Try-except statement"
......@@ -6057,20 +6113,21 @@ class ExceptClauseNode(Node):
if self.pattern:
# normalise/unpack self.pattern into a list
for i, pattern in enumerate(self.pattern):
pattern.analyse_expressions(env)
pattern = pattern.analyse_expressions(env)
self.pattern[i] = pattern.coerce_to_pyobject(env)
if self.target:
import ExprNodes
self.exc_value = ExprNodes.ExcValueNode(self.pos, env)
self.target.analyse_target_expression(env, self.exc_value)
self.target = self.target.analyse_target_expression(env, self.exc_value)
if self.excinfo_target is not None:
import ExprNodes
self.excinfo_tuple = ExprNodes.TupleNode(pos=self.pos, args=[
excinfo_tuple = ExprNodes.TupleNode(pos=self.pos, args=[
ExprNodes.ExcValueNode(pos=self.pos, env=env) for _ in range(3)])
self.excinfo_tuple.analyse_expressions(env)
self.excinfo_tuple = excinfo_tuple.analyse_expressions(env)
self.body.analyse_expressions(env)
self.body = self.body.analyse_expressions(env)
return self
def generate_handling_code(self, code, end_label):
code.mark_pos(self.pos)
......@@ -6213,8 +6270,9 @@ class TryFinallyStatNode(StatNode):
self.finally_clause.analyse_declarations(env)
def analyse_expressions(self, env):
self.body.analyse_expressions(env)
self.finally_clause.analyse_expressions(env)
self.body = self.body.analyse_expressions(env)
self.finally_clause = self.finally_clause.analyse_expressions(env)
return self
nogil_check = Node.gil_error
gil_message = "Try-finally statement"
......@@ -6415,8 +6473,9 @@ class GILStatNode(NogilTryFinallyStatNode):
UtilityCode.load_cached("ForceInitThreads", "ModuleSetupCode.c"))
was_nogil = env.nogil
env.nogil = self.state == 'nogil'
TryFinallyStatNode.analyse_expressions(self, env)
node = TryFinallyStatNode.analyse_expressions(self, env)
env.nogil = was_nogil
return node
def generate_execution_code(self, code):
code.mark_pos(self.pos)
......@@ -6441,7 +6500,7 @@ class GILExitNode(StatNode):
child_attrs = []
def analyse_expressions(self, env):
pass
return self
def generate_execution_code(self, code):
if self.state == 'gil':
......@@ -6500,7 +6559,7 @@ class CImportStatNode(StatNode):
*utility_code_for_cimports[self.module_name]))
def analyse_expressions(self, env):
pass
return self
def generate_execution_code(self, code):
pass
......@@ -6574,7 +6633,7 @@ class FromCImportStatNode(StatNode):
return 1
def analyse_expressions(self, env):
pass
return self
def generate_execution_code(self, code):
pass
......@@ -6605,7 +6664,7 @@ class FromImportStatNode(StatNode):
def analyse_expressions(self, env):
import ExprNodes
self.module.analyse_expressions(env)
self.module = self.module.analyse_expressions(env)
self.item = ExprNodes.RawCNameExprNode(self.pos, py_object_type)
self.interned_items = []
for name, target in self.items:
......@@ -6630,7 +6689,7 @@ class FromImportStatNode(StatNode):
continue
except AttributeError:
pass
target.analyse_target_expression(env, None)
target = target.analyse_target_expression(env, None) # FIXME?
if target.type is py_object_type:
coerced_item = None
else:
......@@ -6638,6 +6697,7 @@ class FromImportStatNode(StatNode):
self.interned_items.append((name, target, coerced_item))
if self.interned_items:
env.use_utility_code(raise_import_error_utility_code)
return self
def generate_execution_code(self, code):
self.module.generate_evaluation_code(code)
......@@ -6797,12 +6857,12 @@ class ParallelStatNode(StatNode, ParallelNode):
def analyse_expressions(self, env):
if self.num_threads:
self.num_threads.analyse_expressions(env)
self.num_threads = self.num_threads.analyse_expressions(env)
if self.chunksize:
self.chunksize.analyse_expressions(env)
self.chunksize = self.chunksize.analyse_expressions(env)
self.body.analyse_expressions(env)
self.body = self.body.analyse_expressions(env)
self.analyse_sharing_attributes(env)
if self.num_threads is not None:
......@@ -6821,7 +6881,8 @@ class ParallelStatNode(StatNode, ParallelNode):
if not self.num_threads.is_simple():
self.num_threads = self.num_threads.coerce_to(
PyrexTypes.c_int_type, env).coerce_to_temp(env)
PyrexTypes.c_int_type, env).coerce_to_temp(env)
return self
def analyse_sharing_attributes(self, env):
"""
......@@ -7504,9 +7565,9 @@ class ParallelRangeNode(ParallelStatNode):
if self.target is None:
error(self.pos, "prange() can only be used as part of a for loop")
return
return self
self.target.analyse_target_types(env)
self.target = self.target.analyse_target_types(env)
if not self.target.type.is_numeric:
# Not a valid type, assume one for now anyway
......@@ -7545,7 +7606,7 @@ class ParallelRangeNode(ParallelStatNode):
self.index_type, node.type)
if self.else_clause is not None:
self.else_clause.analyse_expressions(env)
self.else_clause = self.else_clause.analyse_expressions(env)
# Although not actually an assignment in this scope, it should be
# treated as such to ensure it is unpacked if a closure temp, and to
......@@ -7555,35 +7616,36 @@ class ParallelRangeNode(ParallelStatNode):
if hasattr(self.target, 'entry'):
self.assignments[self.target.entry] = self.target.pos, None
super(ParallelRangeNode, self).analyse_expressions(env)
node = super(ParallelRangeNode, self).analyse_expressions(env)
if self.chunksize:
if not self.schedule:
error(self.chunksize.pos,
if node.chunksize:
if not node.schedule:
error(node.chunksize.pos,
"Must provide schedule with chunksize")
elif self.schedule == 'runtime':
error(self.chunksize.pos,
elif node.schedule == 'runtime':
error(node.chunksize.pos,
"Chunksize not valid for the schedule runtime")
elif (self.chunksize.type.is_int and
self.chunksize.is_literal and
self.chunksize.compile_time_value(env) <= 0):
error(self.chunksize.pos, "Chunksize must not be negative")
elif (node.chunksize.type.is_int and
node.chunksize.is_literal and
node.chunksize.compile_time_value(env) <= 0):
error(node.chunksize.pos, "Chunksize must not be negative")
self.chunksize = self.chunksize.coerce_to(
PyrexTypes.c_int_type, env).coerce_to_temp(env)
node.chunksize = node.chunksize.coerce_to(
PyrexTypes.c_int_type, env).coerce_to_temp(env)
if self.nogil:
if node.nogil:
env.nogil = was_nogil
self.is_nested_prange = self.parent and self.parent.is_prange
if self.is_nested_prange:
parent = self
node.is_nested_prange = node.parent and node.parent.is_prange
if node.is_nested_prange:
parent = node
while parent.parent and parent.parent.is_prange:
parent = parent.parent
parent.assignments.update(self.assignments)
parent.privates.update(self.privates)
parent.assigned_nodes.extend(self.assigned_nodes)
parent.assignments.update(node.assignments)
parent.privates.update(node.privates)
parent.assigned_nodes.extend(node.assigned_nodes)
return node
def nogil_check(self, env):
names = 'start', 'stop', 'step', 'target'
......@@ -7866,7 +7928,8 @@ class CnameDecoratorNode(StatNode):
return '%s_%s' % (self.cname, cname)
def analyse_expressions(self, env):
self.node.analyse_expressions(env)
self.node = self.node.analyse_expressions(env)
return self
def generate_function_definitions(self, env, code):
"Ensure a prototype for every @cname method in the right place"
......
......@@ -100,7 +100,7 @@ class IterationTransform(Visitor.EnvTransform):
iterator=ExprNodes.IteratorNode(node.operand2.pos, sequence=node.operand2),
body=if_node,
else_clause=Nodes.SingleAssignmentNode(pos, lhs=result_ref, rhs=ExprNodes.BoolNode(pos, value=0))))
for_loop.analyse_expressions(self.current_env())
for_loop = for_loop.analyse_expressions(self.current_env())
for_loop = self.visit(for_loop)
new_node = UtilNodes.TempResultFromStatNode(result_ref, for_loop)
......@@ -704,7 +704,7 @@ class IterationTransform(Visitor.EnvTransform):
dict_temp, dict_len_temp.ref(dict_obj.pos), pos_temp,
key_target, value_target, tuple_target,
is_dict_temp)
iter_next_node.analyse_expressions(self.current_env())
iter_next_node = iter_next_node.analyse_expressions(self.current_env())
body.stats[0:0] = [iter_next_node]
if method:
......@@ -1187,7 +1187,7 @@ class SimplifyCalls(Visitor.EnvTransform):
node.pos,
function=node.function,
args=args)
call_node.analyse_types(self.current_env())
call_node = call_node.analyse_types(self.current_env())
if node.type != call_node.type:
call_node = call_node.coerce_to(
node.type, self.current_env())
......
......@@ -1819,20 +1819,20 @@ class AnalyseExpressionsTransform(CythonTransform):
def visit_ModuleNode(self, node):
node.scope.infer_types()
node.body.analyse_expressions(node.scope)
node.body = node.body.analyse_expressions(node.scope)
self.visitchildren(node)
return node
def visit_FuncDefNode(self, node):
node.local_scope.infer_types()
node.body.analyse_expressions(node.local_scope)
node.body = node.body.analyse_expressions(node.local_scope)
self.visitchildren(node)
return node
def visit_ScopedExprNode(self, node):
if node.has_local_scope:
node.expr_scope.infer_types()
node.analyse_scoped_expressions(node.expr_scope)
node = node.analyse_scoped_expressions(node.expr_scope)
self.visitchildren(node)
return node
......
......@@ -33,9 +33,11 @@ class TempRefNode(AtomicExprNode):
def analyse_types(self, env):
assert self.type == self.handle.type
return self
def analyse_target_types(self, env):
assert self.type == self.handle.type
return self
def analyse_target_declaration(self, env):
pass
......@@ -104,7 +106,8 @@ class TempsBlockNode(Node):
self.body.analyse_declarations(env)
def analyse_expressions(self, env):
self.body.analyse_expressions(env)
self.body = self.body.analyse_expressions(env)
return self
def generate_function_definitions(self, env, code):
self.body.generate_function_definitions(env, code)
......@@ -149,6 +152,7 @@ class ResultRefNode(AtomicExprNode):
def analyse_types(self, env):
if self.expression is not None:
self.type = self.expression.type
return self
def infer_type(self, env):
if self.type is not None:
......@@ -263,9 +267,10 @@ class EvalWithTempExprNode(ExprNodes.ExprNode, LetNodeMixin):
return self.subexpression.result()
def analyse_types(self, env):
self.temp_expression.analyse_types(env)
self.subexpression.analyse_types(env)
self.temp_expression = self.temp_expression.analyse_types(env)
self.subexpression = self.subexpression.analyse_types(env)
self.type = self.subexpression.type
return self
def free_subexpr_temps(self, code):
self.subexpression.free_temps(code)
......@@ -302,8 +307,9 @@ class LetNode(Nodes.StatNode, LetNodeMixin):
self.body.analyse_declarations(env)
def analyse_expressions(self, env):
self.temp_expression.analyse_expressions(env)
self.body.analyse_expressions(env)
self.temp_expression = self.temp_expression.analyse_expressions(env)
self.body = self.body.analyse_expressions(env)
return self
def generate_execution_code(self, code):
self.setup_temp_expr(code)
......@@ -335,7 +341,8 @@ class TempResultFromStatNode(ExprNodes.ExprNode):
self.body.analyse_declarations(env)
def analyse_types(self, env):
self.body.analyse_expressions(env)
self.body = self.body.analyse_expressions(env)
return self
def generate_result_code(self, code):
self.result_ref.result_code = self.result()
......
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