Commit 2350ce92 authored by Stefan Behnel's avatar Stefan Behnel

fix #466: make sure ConstNode.coerce_to() always returns a new node (required...

fix #466: make sure ConstNode.coerce_to() always returns a new node (required to support CloneNodes in cascading assignments to differently typed targets)
parent 03960539
...@@ -532,6 +532,14 @@ class ExprNode(Node): ...@@ -532,6 +532,14 @@ class ExprNode(Node):
# #
# This method is called during the analyse_expressions # This method is called during the analyse_expressions
# phase of the src_node's processing. # phase of the src_node's processing.
#
# Note that subclasses that override this (especially
# ConstNodes) must not (re-)set their own .type attribute
# here. Since expression nodes may turn up in different
# places in the tree (e.g. inside of CloneNodes in cascaded
# assignments), this method must return a new node instance
# if it changes the type.
#
src = self src = self
src_type = self.type src_type = self.type
src_is_py_type = src_type.is_pyobject src_is_py_type = src_type.is_pyobject
...@@ -748,24 +756,28 @@ class IntNode(ConstNode): ...@@ -748,24 +756,28 @@ class IntNode(ConstNode):
type = PyrexTypes.c_long_type type = PyrexTypes.c_long_type
def coerce_to(self, dst_type, env): def coerce_to(self, dst_type, env):
if dst_type.is_numeric and not dst_type.is_complex: if self.type is dst_type:
self.type = PyrexTypes.c_long_type
return self return self
# Arrange for a Python version of the number to be pre-allocated node = IntNode(self.pos, value=self.value,
# when coercing to a Python type. unsigned=self.unsigned, longness=self.longness)
if dst_type.is_numeric and not dst_type.is_complex:
return node
if dst_type.is_pyobject: if dst_type.is_pyobject:
self.type = PyrexTypes.py_object_type node.type = PyrexTypes.py_object_type
# We still need to perform normal coerce_to processing on the # We still need to perform normal coerce_to processing on the
# result, because we might be coercing to an extension type, # result, because we might be coercing to an extension type,
# in which case a type test node will be needed. # in which case a type test node will be needed.
return ConstNode.coerce_to(self, dst_type, env) return ConstNode.coerce_to(node, dst_type, env)
def coerce_to_boolean(self, env): def coerce_to_boolean(self, env):
self.type = PyrexTypes.c_bint_type return IntNode(
return self self.pos, value=self.value,
type = PyrexTypes.c_bint_type,
unsigned=self.unsigned, longness=self.longness)
def generate_evaluation_code(self, code): def generate_evaluation_code(self, code):
if self.type.is_pyobject: if self.type.is_pyobject:
# pre-allocate a Python version of the number
self.result_code = code.get_py_num(self.value, self.longness) self.result_code = code.get_py_num(self.value, self.longness)
else: else:
self.result_code = self.get_constant_c_result_code() self.result_code = self.get_constant_c_result_code()
...@@ -830,31 +842,29 @@ class BytesNode(ConstNode): ...@@ -830,31 +842,29 @@ class BytesNode(ConstNode):
return len(self.value) == 1 return len(self.value) == 1
def coerce_to(self, dst_type, env): def coerce_to(self, dst_type, env):
if dst_type == PyrexTypes.c_char_ptr_type:
self.type = PyrexTypes.c_char_ptr_type
return self
elif dst_type == PyrexTypes.c_uchar_ptr_type:
self.type = PyrexTypes.c_char_ptr_type
return CastNode(self, PyrexTypes.c_uchar_ptr_type)
if dst_type.is_int: if dst_type.is_int:
if not self.can_coerce_to_char_literal(): if not self.can_coerce_to_char_literal():
error(self.pos, "Only single-character strings can be coerced into ints.") error(self.pos, "Only single-character strings can be coerced into ints.")
return self return self
return CharNode(self.pos, value=self.value) return CharNode(self.pos, value=self.value)
node = self node = BytesNode(self.pos, value=self.value)
if dst_type == PyrexTypes.c_char_ptr_type:
node.type = PyrexTypes.c_char_ptr_type
return node
elif dst_type == PyrexTypes.c_uchar_ptr_type:
node.type = PyrexTypes.c_char_ptr_type
return CastNode(node, PyrexTypes.c_uchar_ptr_type)
if not self.type.is_pyobject: if not self.type.is_pyobject:
if dst_type in (py_object_type, Builtin.bytes_type): if dst_type in (py_object_type, Builtin.bytes_type):
node = self.as_py_string_node(env) node.type = Builtin.bytes_type
elif dst_type.is_pyobject: elif dst_type.is_pyobject:
self.fail_assignment(dst_type) self.fail_assignment(dst_type)
return self return self
else:
node = self
elif dst_type.is_pyobject and dst_type is not py_object_type: elif dst_type.is_pyobject and dst_type is not py_object_type:
self.check_for_coercion_error(dst_type, fail=True) self.check_for_coercion_error(dst_type, fail=True)
return self return node
# We still need to perform normal coerce_to processing on the # We still need to perform normal coerce_to processing on the
# result, because we might be coercing to an extension type, # result, because we might be coercing to an extension type,
...@@ -1002,15 +1012,16 @@ class ImagNode(AtomicExprNode): ...@@ -1002,15 +1012,16 @@ class ImagNode(AtomicExprNode):
self.type.create_declaration_utility_code(env) self.type.create_declaration_utility_code(env)
def coerce_to(self, dst_type, env): def coerce_to(self, dst_type, env):
# Arrange for a Python version of the number to be pre-allocated if self.type is dst_type:
# when coercing to a Python type. return self
node = ImagNode(self.pos, value=self.value)
if dst_type.is_pyobject: if dst_type.is_pyobject:
self.is_temp = 1 node.is_temp = 1
self.type = PyrexTypes.py_object_type node.type = PyrexTypes.py_object_type
# We still need to perform normal coerce_to processing on the # We still need to perform normal coerce_to processing on the
# result, because we might be coercing to an extension type, # result, because we might be coercing to an extension type,
# in which case a type test node will be needed. # in which case a type test node will be needed.
return AtomicExprNode.coerce_to(self, dst_type, env) return AtomicExprNode.coerce_to(node, dst_type, env)
gil_message = "Constructing complex number" gil_message = "Constructing complex number"
......
...@@ -3063,7 +3063,7 @@ class CascadedAssignmentNode(AssignmentNode): ...@@ -3063,7 +3063,7 @@ class CascadedAssignmentNode(AssignmentNode):
def analyse_types(self, env, use_temp = 0): def analyse_types(self, env, use_temp = 0):
self.rhs.analyse_types(env) self.rhs.analyse_types(env)
if use_temp: if use_temp and not self.rhs.is_simple():
self.rhs = self.rhs.coerce_to_temp(env) self.rhs = self.rhs.coerce_to_temp(env)
else: else:
self.rhs = self.rhs.coerce_to_simple(env) self.rhs = self.rhs.coerce_to_simple(env)
......
...@@ -7,4 +7,3 @@ numpy_ValueError_T172 ...@@ -7,4 +7,3 @@ numpy_ValueError_T172
unsignedbehaviour_T184 unsignedbehaviour_T184
missing_baseclass_in_predecl_T262 missing_baseclass_in_predecl_T262
cfunc_call_tuple_args_T408 cfunc_call_tuple_args_T408
extended_unpacking_T466
...@@ -8,3 +8,14 @@ def simple_parallel_typed(): ...@@ -8,3 +8,14 @@ def simple_parallel_typed():
cdef int a,c cdef int a,c
a, c = d = e = [1,2] a, c = d = e = [1,2]
return a, c, d, e return a, c, d, e
def simple_parallel_int_mix():
"""
>>> simple_parallel_int_mix()
(1, 2, 1, 2, 1, 2, [1, 2], [1, 2])
"""
cdef int ai,bi
cdef long al,bl
cdef object ao, bo
ai, bi = al, bl = ao, bo = c = d = [1,2]
return ao, bo, ai, bi, al, bl, c, d
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