Commit cbd2a528 authored by Robert Bradshaw's avatar Robert Bradshaw

type narrowing for cdef methods

Now if you inherit cdef methods from another class, you may re-declare the
arguments and return variables to be sub-types of the original declared type.
This will be especially convenient for the SAGE arithmetic architecture.
Type-checking is performed if necessary.
parent 7fbdbd53
...@@ -1944,7 +1944,7 @@ class CFuncDefNode(FuncDefNode): ...@@ -1944,7 +1944,7 @@ class CFuncDefNode(FuncDefNode):
for arg in self.type.args: for arg in self.type.args:
if not arg.name: if not arg.name:
error(arg.pos, "Missing argument name") error(arg.pos, "Missing argument name")
self.declare_argument(env, arg) arg.entry = self.declare_argument(env, arg)
def generate_function_header(self, code, with_pymethdef): def generate_function_header(self, code, with_pymethdef):
arg_decls = [] arg_decls = []
...@@ -1989,7 +1989,27 @@ class CFuncDefNode(FuncDefNode): ...@@ -1989,7 +1989,27 @@ class CFuncDefNode(FuncDefNode):
pass pass
def generate_argument_type_tests(self, code): def generate_argument_type_tests(self, code):
pass # Generate type tests for args whose type in a parent
# class is a supertype of the declared type.
for arg in self.type.args:
if arg.needs_type_test:
self.generate_arg_type_test(arg, code)
def generate_arg_type_test(self, arg, code):
# Generate type test for one argument.
if arg.type.typeobj_is_available():
typeptr_cname = arg.type.typeptr_cname
arg_code = "((PyObject *)%s)" % arg.entry.cname
code.putln(
'if (!__Pyx_ArgTypeTest(%s, %s, %d, "%s")) %s' % (
arg_code,
typeptr_cname,
not arg.not_none,
arg.name,
code.error_goto(arg.pos)))
else:
error(arg.pos, "Cannot test type of extern C class "
"without type object name specification")
def error_value(self): def error_value(self):
if self.return_type.is_pyobject: if self.return_type.is_pyobject:
...@@ -3804,6 +3824,9 @@ static int __Pyx_GetVtable(PyObject *dict, void *vtabptr); /*proto*/ ...@@ -3804,6 +3824,9 @@ static int __Pyx_GetVtable(PyObject *dict, void *vtabptr); /*proto*/
static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, char *modname); /*proto*/ static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, char *modname); /*proto*/
static int __Pyx_InternStrings(__Pyx_InternTabEntry *t); /*proto*/ static int __Pyx_InternStrings(__Pyx_InternTabEntry *t); /*proto*/
static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/ static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/
#DEFINE __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False))
#DEFINE __Pyx_PyObject_IsTrue(x) ({PyObject *_x = (x); _x == Py_True ? 1 : (_x) == Py_False ? 0 : PyObject_IsTrue(_x)})
""" """
get_name_predeclaration = \ get_name_predeclaration = \
......
...@@ -347,8 +347,8 @@ class CBIntType(CIntType): ...@@ -347,8 +347,8 @@ class CBIntType(CIntType):
# TODO: this should be a macro "(__ ? Py_True : Py_False)" # TODO: this should be a macro "(__ ? Py_True : Py_False)"
# and no error checking should be needed (just an incref). # and no error checking should be needed (just an incref).
to_py_function = "PyBool_FromLong" to_py_function = "__Pyx_PyBool_FromLong"
from_py_function = "PyObject_IsTrue" from_py_function = "__Pyx_PyObject_IsTrue"
class CPySSizeTType(CIntType): class CPySSizeTType(CIntType):
...@@ -529,6 +529,30 @@ class CFuncType(CType): ...@@ -529,6 +529,30 @@ class CFuncType(CType):
return 0 return 0
return 1 return 1
def narrower_c_signature_than(self, other_type, as_cmethod = 0):
return self.narrower_c_signature_than_resolved_type(other_type.resolve(), as_cmethod)
def narrower_c_signature_than_resolved_type(self, other_type, as_cmethod):
if other_type is error_type:
return 1
if not other_type.is_cfunction:
return 0
nargs = len(self.args)
if nargs <> len(other_type.args):
return 0
for i in range(as_cmethod, nargs):
if not self.args[i].type.subtype_of_resolved_type(other_type.args[i].type):
return 0
else:
self.args[i].needs_type_test = other_type.args[i].needs_type_test \
or not self.args[i].type.same_as(other_type.args[i].type)
if self.has_varargs <> other_type.has_varargs:
return 0
if not self.return_type.subtype_of_resolved_type(other_type.return_type):
return 0
return 1
def same_exception_signature_as(self, other_type): def same_exception_signature_as(self, other_type):
return self.same_exception_signature_as_resolved_type( return self.same_exception_signature_as_resolved_type(
other_type.resolve()) other_type.resolve())
...@@ -576,6 +600,8 @@ class CFuncTypeArg: ...@@ -576,6 +600,8 @@ class CFuncTypeArg:
self.cname = Naming.var_prefix + name self.cname = Naming.var_prefix + name
self.type = type self.type = type
self.pos = pos self.pos = pos
self.not_none = False
self.needs_type_test = False # TODO: should these defaults be set in analyse_types()?
def __repr__(self): def __repr__(self):
return "%s:%s" % (self.name, repr(self.type)) return "%s:%s" % (self.name, repr(self.type))
......
...@@ -1075,7 +1075,11 @@ class CClassScope(ClassScope): ...@@ -1075,7 +1075,11 @@ class CClassScope(ClassScope):
if defining and entry.func_cname: if defining and entry.func_cname:
error(pos, "'%s' already defined" % name) error(pos, "'%s' already defined" % name)
if not entry.type.same_as(type, as_cmethod = 1): if not entry.type.same_as(type, as_cmethod = 1):
error(pos, "Signature does not match previous declaration") old_type = entry.type
if type.narrower_c_signature_than(entry.type, as_cmethod = 1):
entry.type = type
else:
error(pos, "Signature not compatible with previous declaration")
else: else:
if self.defined: if self.defined:
error(pos, error(pos,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment