fix #466: make sure ConstNode.coerce_to() always returns a new node (required to...
authorStefan Behnel <scoder@users.berlios.de>
Fri, 11 Dec 2009 13:15:35 +0000 (14:15 +0100)
committerStefan Behnel <scoder@users.berlios.de>
Fri, 11 Dec 2009 13:15:35 +0000 (14:15 +0100)
Cython/Compiler/ExprNodes.py
Cython/Compiler/Nodes.py
tests/bugs.txt
tests/run/extended_unpacking_T466.pyx

index d5b6b2f15d4544c993f5e1d6e57345ba86a97099..57572fdb0e11b3884607097b74f856829b2e7c13 100644 (file)
@@ -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"
 
index 84ece73db7c4c5c12a3887f0270cd92faf57400d..cd38b63d78c1cae94cbdfa8bb9b53e5703ddc984 100644 (file)
@@ -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)
index 29aa0373b36ac7fe423187658b77fd1e918f7aa2..55e7e2c3df15948183cbb2335604ab9c3cdb361e 100644 (file)
@@ -7,4 +7,3 @@ numpy_ValueError_T172
 unsignedbehaviour_T184
 missing_baseclass_in_predecl_T262
 cfunc_call_tuple_args_T408
-extended_unpacking_T466
index 6c0d3f74aeaac5376c5ede955300e95e40db56d9..8f03a25305b56602e42c24a5d0e2fa17e8bd8bef 100644 (file)
@@ -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