From 2350ce92c326ceb61e7f76eaec7fb41fb5fd539a Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Fri, 11 Dec 2009 14:15:35 +0100 Subject: [PATCH] fix #466: make sure ConstNode.coerce_to() always returns a new node (required to support CloneNodes in cascading assignments to differently typed targets) --- Cython/Compiler/ExprNodes.py | 63 ++++++++++++++++----------- Cython/Compiler/Nodes.py | 2 +- tests/bugs.txt | 1 - tests/run/extended_unpacking_T466.pyx | 11 +++++ 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index d5b6b2f1..57572fdb 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -532,6 +532,14 @@ class ExprNode(Node): # # This method is called during the analyse_expressions # 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_type = self.type src_is_py_type = src_type.is_pyobject @@ -748,24 +756,28 @@ class IntNode(ConstNode): type = PyrexTypes.c_long_type def coerce_to(self, dst_type, env): - if dst_type.is_numeric and not dst_type.is_complex: - self.type = PyrexTypes.c_long_type + if self.type is dst_type: return self - # Arrange for a Python version of the number to be pre-allocated - # when coercing to a Python type. + node = IntNode(self.pos, value=self.value, + unsigned=self.unsigned, longness=self.longness) + if dst_type.is_numeric and not dst_type.is_complex: + return node 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 # result, because we might be coercing to an extension type, # 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): - self.type = PyrexTypes.c_bint_type - return self + return IntNode( + self.pos, value=self.value, + type = PyrexTypes.c_bint_type, + unsigned=self.unsigned, longness=self.longness) def generate_evaluation_code(self, code): if self.type.is_pyobject: + # pre-allocate a Python version of the number self.result_code = code.get_py_num(self.value, self.longness) else: self.result_code = self.get_constant_c_result_code() @@ -830,31 +842,29 @@ class BytesNode(ConstNode): return len(self.value) == 1 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 not self.can_coerce_to_char_literal(): error(self.pos, "Only single-character strings can be coerced into ints.") return self 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 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: self.fail_assignment(dst_type) return self - else: - node = self elif dst_type.is_pyobject and dst_type is not py_object_type: self.check_for_coercion_error(dst_type, fail=True) - return self + return node # We still need to perform normal coerce_to processing on the # result, because we might be coercing to an extension type, @@ -1002,15 +1012,16 @@ class ImagNode(AtomicExprNode): self.type.create_declaration_utility_code(env) def coerce_to(self, dst_type, env): - # Arrange for a Python version of the number to be pre-allocated - # when coercing to a Python type. + if self.type is dst_type: + return self + node = ImagNode(self.pos, value=self.value) if dst_type.is_pyobject: - self.is_temp = 1 - self.type = PyrexTypes.py_object_type + node.is_temp = 1 + node.type = PyrexTypes.py_object_type # We still need to perform normal coerce_to processing on the # result, because we might be coercing to an extension type, # 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" diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 84ece73d..cd38b63d 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -3063,7 +3063,7 @@ class CascadedAssignmentNode(AssignmentNode): def analyse_types(self, env, use_temp = 0): 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) else: self.rhs = self.rhs.coerce_to_simple(env) diff --git a/tests/bugs.txt b/tests/bugs.txt index 29aa0373..55e7e2c3 100644 --- a/tests/bugs.txt +++ b/tests/bugs.txt @@ -7,4 +7,3 @@ numpy_ValueError_T172 unsignedbehaviour_T184 missing_baseclass_in_predecl_T262 cfunc_call_tuple_args_T408 -extended_unpacking_T466 diff --git a/tests/run/extended_unpacking_T466.pyx b/tests/run/extended_unpacking_T466.pyx index 6c0d3f74..8f03a253 100644 --- a/tests/run/extended_unpacking_T466.pyx +++ b/tests/run/extended_unpacking_T466.pyx @@ -8,3 +8,14 @@ def simple_parallel_typed(): cdef int a,c a, c = d = e = [1,2] 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 -- 2.26.2