fix #688: optimised builtin functions/methods return 0 instead of None
authorStefan Behnel <scoder@users.berlios.de>
Sun, 17 Apr 2011 08:04:00 +0000 (10:04 +0200)
committerStefan Behnel <scoder@users.berlios.de>
Sun, 17 Apr 2011 08:04:00 +0000 (10:04 +0200)
Cython/Compiler/Builtin.py
Cython/Compiler/Optimize.py
Cython/Compiler/PyrexTypes.py
tests/run/builtin_methods_return_values.pyx [new file with mode: 0644]

index d9c4207e184ed63a1f7eea5528748e9ae8081f27..dce7c16fea16db8dd3277cbba30c054cacb4f9f6 100644 (file)
@@ -478,9 +478,9 @@ builtin_types_table = [
 
     ("tuple",   "PyTuple_Type",    []),
 
-    ("list",    "PyList_Type",     [BuiltinMethod("insert",  "TzO",  "i", "PyList_Insert"),
-                                    BuiltinMethod("reverse", "T",    "i", "PyList_Reverse"),
-                                    BuiltinMethod("append",  "TO",   "i", "PyList_Append"),
+    ("list",    "PyList_Type",     [BuiltinMethod("insert",  "TzO",  "r", "PyList_Insert"),
+                                    BuiltinMethod("reverse", "T",    "r", "PyList_Reverse"),
+                                    BuiltinMethod("append",  "TO",   "r", "PyList_Append"),
                                     ]),
 
     ("dict",    "PyDict_Type",     [BuiltinMethod("items", "T",   "O", "PyDict_Items"),  # FIXME: Py3 mode?
@@ -494,9 +494,9 @@ builtin_types_table = [
                                     ]),
 #    ("file",    "PyFile_Type",     []),  # not in Py3
 
-    ("set",       "PySet_Type",    [BuiltinMethod("clear",   "T",  "i", "PySet_Clear"),
-                                    BuiltinMethod("discard", "TO", "i", "PySet_Discard"),
-                                    BuiltinMethod("add",     "TO", "i", "PySet_Add"),
+    ("set",       "PySet_Type",    [BuiltinMethod("clear",   "T",  "r", "PySet_Clear"),
+                                    BuiltinMethod("discard", "TO", "r", "PySet_Discard"),
+                                    BuiltinMethod("add",     "TO", "r", "PySet_Add"),
                                     BuiltinMethod("pop",     "T",  "O", "PySet_Pop")]),
     ("frozenset", "PyFrozenSet_Type", []),
 ]
index b6ee4628d69054d86bb306d23821015b339bfaef..d4821ca1ee774c885434ad402e3ffe002494bc49 100644 (file)
@@ -1604,6 +1604,15 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
             return node.operand
         return node
 
+    def visit_ExprStatNode(self, node):
+        """
+        Drop useless coercions.
+        """
+        self.visitchildren(node)
+        if isinstance(node.expr, ExprNodes.CoerceToPyTypeNode):
+            node.expr = node.expr.arg
+        return node
+
     def visit_CoerceToBooleanNode(self, node):
         """Drop redundant conversion nodes after tree changes.
         """
@@ -2146,7 +2155,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
     _handle_simple_method_list_pop = _handle_simple_method_object_pop
 
     single_param_func_type = PyrexTypes.CFuncType(
-        PyrexTypes.c_int_type, [
+        PyrexTypes.c_returncode_type, [
             PyrexTypes.CFuncTypeArg("obj", PyrexTypes.py_object_type, None),
             ],
         exception_value = "-1")
@@ -2158,7 +2167,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
             return node
         return self._substitute_method_call(
             node, "PyList_Sort", self.single_param_func_type,
-            'sort', is_unbound_method, args)
+            'sort', is_unbound_method, args).coerce_to(node.type, self.current_env)
 
     Pyx_PyDict_GetItem_func_type = PyrexTypes.CFuncType(
         PyrexTypes.py_object_type, [
index 45e9af08894b5198ffbceb2e20b1f1c2ca199dac..4dc231d9c798973c67b389996546e20c0570bc4d 100755 (executable)
@@ -913,6 +913,8 @@ class CAnonEnumType(CIntType):
 
 class CReturnCodeType(CIntType):
 
+    to_py_function = "__Pyx_Owned_Py_None"
+
     is_returncode = 1
 
 
@@ -2783,6 +2785,7 @@ type_conversion_predeclarations = """
 #define __Pyx_PyBytes_FromUString(s) PyBytes_FromString((char*)s)
 #define __Pyx_PyBytes_AsUString(s)   ((unsigned char*) PyBytes_AsString(s))
 
+#define __Pyx_Owned_Py_None(b) (Py_INCREF(Py_None), Py_None)
 #define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False))
 static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
 static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x);
diff --git a/tests/run/builtin_methods_return_values.pyx b/tests/run/builtin_methods_return_values.pyx
new file mode 100644 (file)
index 0000000..e117987
--- /dev/null
@@ -0,0 +1,89 @@
+# mode: run
+# tag: list, set, builtins
+# ticket: 688
+
+_set = set
+
+class TestObj(object):
+    pass
+
+def _setattr(obj):
+    """
+    >>> t = TestObj()
+    >>> _setattr(t) is None
+    True
+    >>> t.test is None
+    True
+    """
+    setattr(obj, 'test', None)
+    return setattr(obj, 'test', None)
+
+def _delattr(obj):
+    """
+    >>> t = TestObj()
+    >>> t.test1 = t.test2 = True
+    >>> _delattr(t) is None
+    True
+    >>> hasattr(t, 'test1')
+    False
+    >>> hasattr(t, 'test2')
+    False
+    """
+    delattr(obj, 'test1')
+    return delattr(obj, 'test2')
+
+def list_sort(list l):
+    """
+    >>> list_sort([1,2,3]) is None
+    True
+    """
+    l.sort()
+    return l.sort()
+
+def list_reverse(list l):
+    """
+    >>> list_reverse([1,2,3]) is None
+    True
+    """
+    l.reverse()
+    return l.reverse()
+
+def list_insert(list l):
+    """
+    >>> list_insert([1,2,3]) is None
+    True
+    """
+    l.insert(1, 2)
+    return l.insert(1, 2)
+
+def list_append(list l):
+    """
+    >>> list_append([1,2,3]) is None
+    True
+    """
+    l.append(1)
+    return l.append(2)
+
+def set_clear(set s):
+    """
+    >>> set_clear(_set([1,2,3])) is None
+    True
+    """
+    s.clear()
+    return s.clear()
+
+def set_discard(set s):
+    """
+    >>> set_discard(_set([1,2,3])) is None
+    True
+    """
+    s.discard(1)
+    return s.discard(2)
+
+def set_add(set s):
+    """
+    >>> set_add(_set([1,2,3])) is None
+    True
+    """
+    s.add(1)
+    return s.add(2)