use a straight call to PyList_Tuple() on code like tuple([...])
authorStefan Behnel <scoder@users.berlios.de>
Fri, 19 Dec 2008 02:05:14 +0000 (03:05 +0100)
committerStefan Behnel <scoder@users.berlios.de>
Fri, 19 Dec 2008 02:05:14 +0000 (03:05 +0100)
Cython/Compiler/Optimize.py
tests/run/tuple.pyx

index 1f2836dcb9a470324c28712c435ca2b4a80cc531..1ddd988686a812ce6dcf739672a7a2a7c1cf59eb 100644 (file)
@@ -426,6 +426,16 @@ class FlattenInListTransform(Visitor.VisitorTransform, SkipDeclarations):
 class FlattenBuiltinTypeCreation(Visitor.VisitorTransform):
     """Optimise some common instantiation patterns for builtin types.
     """
+    PyList_AsTuple_func_type = PyrexTypes.CFuncType(
+        PyrexTypes.py_object_type, [
+            PyrexTypes.CFuncTypeArg("list",  Builtin.list_type, None)
+            ])
+
+    PyList_AsTuple_name = EncodedString("PyList_AsTuple")
+
+    PyList_AsTuple_entry = Symtab.Entry(
+        PyList_AsTuple_name, PyList_AsTuple_name, PyList_AsTuple_func_type)
+
     def visit_GeneralCallNode(self, node):
         self.visitchildren(node)
         handler = self._find_handler('general', node.function)
@@ -486,6 +496,32 @@ class FlattenBuiltinTypeCreation(Visitor.VisitorTransform):
         else:
             return node
 
+    def _handle_simple_tuple(self, node, pos_args, kwargs):
+        """Replace tuple([...]) by a call to PyList_AsTuple.
+        """
+        if not isinstance(pos_args, ExprNodes.TupleNode):
+            return node
+        if len(pos_args.args) != 1:
+            return node
+        list_arg = pos_args.args[0]
+        if list_arg.type is not Builtin.list_type:
+            return node
+        if not isinstance(list_arg, (ExprNodes.ComprehensionNode,
+                                     ExprNodes.ListNode)):
+            # everything else may be None => take the safe path
+            return node
+
+        node.args = pos_args.args
+        node.arg_tuple = None
+        node.type = Builtin.tuple_type
+        node.result_ctype = Builtin.tuple_type
+        node.function = ExprNodes.NameNode(
+            pos = node.pos,
+            name = self.PyList_AsTuple_name,
+            type = self.PyList_AsTuple_func_type,
+            entry = self.PyList_AsTuple_entry)
+        return node
+
     def visit_PyTypeTestNode(self, node):
         """Flatten redundant type checks after tree changes.
         """
index 484731124d9dde330b8c39528ba72d5eaa44fbd6..869107a2418000e89dd21b537e0db4344a1412d9 100644 (file)
@@ -11,6 +11,12 @@ __doc__ = u"""
     (2, 3, 4)
     >>> l(1,2,3,4,5)
     (17, 42, 88)
+    >>> tuple_none()
+    Traceback (most recent call last):
+    TypeError: 'NoneType' object is not iterable
+    >>> tuple_none_list()
+    Traceback (most recent call last):
+    TypeError: 'NoneType' object is not iterable
 """
 
 def f(obj1, obj2, obj3, obj4, obj5):
@@ -51,3 +57,10 @@ def l(obj1, obj2, obj3, obj4, obj5):
     obj1 = (obj2, obj3, obj4,)
     obj1 = 17, 42, 88
     return obj1
+
+def tuple_none():
+    return tuple(None)
+
+def tuple_none_list():
+    cdef list none = None
+    return tuple(none)