From 3f1a75bdd76e861c58dcd11cbf1abd382fbc215e Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Sun, 7 Nov 2010 10:10:31 +0100 Subject: [PATCH] fix 'self' argument type in generic builtin method overrides, test for None at call time (ticket #571) --- Cython/Compiler/Builtin.py | 24 ++++++++++++++---------- Cython/Compiler/ExprNodes.py | 6 +++++- Cython/Compiler/TypeSlots.py | 10 +++++++--- tests/run/set.pyx | 7 +++++++ 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/Cython/Compiler/Builtin.py b/Cython/Compiler/Builtin.py index e5226d78..fbed2e31 100644 --- a/Cython/Compiler/Builtin.py +++ b/Cython/Compiler/Builtin.py @@ -112,20 +112,20 @@ builtin_types_table = [ ("tuple", "PyTuple_Type", []), - ("list", "PyList_Type", [("insert", "OzO", "i", "PyList_Insert")]), + ("list", "PyList_Type", [("insert", "TzO", "i", "PyList_Insert")]), - ("dict", "PyDict_Type", [("items", "O", "O", "PyDict_Items"), - ("keys", "O", "O", "PyDict_Keys"), - ("values","O", "O", "PyDict_Values"), - ("copy", "O", "O", "PyDict_Copy")]), + ("dict", "PyDict_Type", [("items", "T", "O", "PyDict_Items"), + ("keys", "T", "O", "PyDict_Keys"), + ("values","T", "O", "PyDict_Values"), + ("copy", "T", "O", "PyDict_Copy")]), ("slice", "PySlice_Type", []), # ("file", "PyFile_Type", []), # not in Py3 - ("set", "PySet_Type", [("clear", "O", "i", "PySet_Clear"), - ("discard", "OO", "i", "PySet_Discard"), - ("add", "OO", "i", "PySet_Add"), - ("pop", "O", "O", "PySet_Pop")]), + ("set", "PySet_Type", [("clear", "T", "i", "PySet_Clear"), + ("discard", "TO", "i", "PySet_Discard"), + ("add", "TO", "i", "PySet_Add"), + ("pop", "T", "O", "PySet_Pop")]), ("frozenset", "PyFrozenSet_Type", []), ] @@ -470,7 +470,11 @@ def init_builtin_types(): builtin_types[name] = the_type for name, args, ret, cname in funcs: sig = Signature(args, ret) - the_type.scope.declare_cfunction(name, sig.function_type(), None, cname) + # override 'self' type (first argument) + self_arg = PyrexTypes.CFuncTypeArg("", the_type, None) + self_arg.not_none = True + method_type = sig.function_type(self_arg) + the_type.scope.declare_cfunction(name, method_type, None, cname) def init_builtin_structs(): for name, cname, attribute_types in builtin_structs_table: diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 0bb334de..5c63ff23 100755 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -2836,7 +2836,11 @@ class SimpleCallNode(CallNode): arg.analyse_types(env) if self.self and func_type.args: # Coerce 'self' to the type expected by the method. - expected_type = func_type.args[0].type + self_arg = func_type.args[0] + if self_arg.not_none: # C methods must do the None test for self at *call* time + self.self = self.self.as_none_safe_node( + "'NoneType' object has no attribute '%s'" % self.function.entry.name) + expected_type = self_arg.type self.coerced_self = CloneNode(self.self).coerce_to( expected_type, env) # Insert coerced 'self' argument into argument list. diff --git a/Cython/Compiler/TypeSlots.py b/Cython/Compiler/TypeSlots.py index a85bbae1..9f44eb44 100644 --- a/Cython/Compiler/TypeSlots.py +++ b/Cython/Compiler/TypeSlots.py @@ -100,12 +100,16 @@ class Signature(object): def exception_value(self): return self.error_value_map.get(self.ret_format) - def function_type(self): + def function_type(self, self_arg_override=None): # Construct a C function type descriptor for this signature args = [] for i in xrange(self.num_fixed_args()): - arg_type = self.fixed_arg_type(i) - args.append(PyrexTypes.CFuncTypeArg("", arg_type, None)) + if self_arg_override is not None and self.is_self_arg(i): + assert isinstance(self_arg_override, PyrexTypes.CFuncTypeArg) + args.append(self_arg_override) + else: + arg_type = self.fixed_arg_type(i) + args.append(PyrexTypes.CFuncTypeArg("", arg_type, None)) ret_type = self.return_type() exc_value = self.exception_value() return PyrexTypes.CFuncType(ret_type, args, exception_value = exc_value) diff --git a/tests/run/set.pyx b/tests/run/set.pyx index d078a672..343274a5 100644 --- a/tests/run/set.pyx +++ b/tests/run/set.pyx @@ -56,6 +56,13 @@ def test_set_clear(): s1.clear() return s1 +def test_set_clear_None(): + """ + >>> test_set_clear_None() + """ + cdef set s1 = None + s1.clear() + def test_set_list_comp(): """ >>> type(test_set_list_comp()) is _set -- 2.26.2