From 9ada8c82357a10673f062c922c6fa745cefd04e6 Mon Sep 17 00:00:00 2001 From: Robert Bradshaw Date: Thu, 7 Feb 2008 04:00:51 -0800 Subject: [PATCH] Number of arguments can grow with overridden cdef functions. --- Cython/Compiler/ExprNodes.py | 14 ++++++++--- Cython/Compiler/Nodes.py | 2 +- Cython/Compiler/PyrexTypes.py | 45 +++++++++++++++++++++++++++++++++++ Cython/Compiler/Symtab.py | 7 ++++-- 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 74a1cb91..83f57e47 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -1523,7 +1523,7 @@ class SimpleCallNode(ExprNode): if func_type.has_varargs: expected_str = "at least " + expected_str elif func_type.optional_arg_count: - if actual_nargs > max_nargs: + if actual_nargs < max_nargs: expected_str = "at least " + expected_str else: expected_str = "at most " + str(max_nargs) @@ -1569,7 +1569,11 @@ class SimpleCallNode(ExprNode): arg_list_code.append(arg_code) if func_type.optional_arg_count: if expected_nargs == actual_nargs: - arg_list_code.append(func_type.op_args.cast_code('NULL')) + if func_type.old_signature: + struct_type = func_type.old_signature.op_args + else: + struct_type = func_type.op_args + optional_args = struct_type.cast_code('NULL') else: optional_arg_code = [str(actual_nargs - expected_nargs)] for formal_arg, actual_arg in args[expected_nargs:actual_nargs]: @@ -1578,7 +1582,11 @@ class SimpleCallNode(ExprNode): # for formal_arg in formal_args[actual_nargs:max_nargs]: # optional_arg_code.append(formal_arg.type.cast_code('0')) optional_arg_struct = '{%s}' % ','.join(optional_arg_code) - arg_list_code.append('&' + func_type.op_args.base_type.cast_code(optional_arg_struct)) + optional_args = '&' + func_type.op_args.base_type.cast_code(optional_arg_struct) + if func_type.old_signature and \ + func_type.old_signature.op_args != func_type.op_args: + optional_args = func_type.old_signature.op_args.cast_code(optional_args) + arg_list_code.append(optional_args) for actual_arg in self.args[len(formal_args):]: arg_list_code.append(actual_arg.result_code) result = "%s(%s)" % (self.function.result_code, diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 6f6ad261..fcc6acf2 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -345,7 +345,7 @@ class CFuncDeclaratorNode(CDeclaratorNode): scope.declare_var('n', PyrexTypes.c_int_type, self.pos) for arg in func_type_args[len(func_type_args)-self.optional_arg_count:]: scope.declare_var(arg.name, arg.type, arg.pos, allow_pyobject = 1) - struct_cname = Naming.opt_arg_prefix + self.base.name + struct_cname = Naming.opt_arg_prefix + env.mangle(self.base.name) self.op_args_struct = env.global_scope().declare_struct_or_union(name = struct_cname, kind = 'struct', scope = scope, diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index 9928dad7..ff3148cd 100644 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -584,6 +584,7 @@ class CFuncType(CType): # with_gil boolean Acquire gil around function body is_cfunction = 1 + old_signature = None def __init__(self, return_type, args, has_varargs = 0, exception_value = None, exception_check = 0, calling_convention = "", @@ -648,6 +649,49 @@ class CFuncType(CType): return 0 return 1 + + def compatible_signature_with(self, other_type, as_cmethod = 0): + return self.compatible_signature_with_resolved_type(other_type.resolve(), as_cmethod) + + def compatible_signature_with_resolved_type(self, other_type, as_cmethod): + #print "CFuncType.same_c_signature_as_resolved_type:", \ + # self, other_type, "as_cmethod =", as_cmethod ### + if other_type is error_type: + return 1 + if not other_type.is_cfunction: + return 0 + if self.is_overridable != other_type.is_overridable: + return 0 + nargs = len(self.args) + if nargs - self.optional_arg_count != len(other_type.args) - other_type.optional_arg_count: + return 0 + if self.optional_arg_count < other_type.optional_arg_count: + return 0 + # When comparing C method signatures, the first argument + # is exempt from compatibility checking (the proper check + # is performed elsewhere). + for i in range(as_cmethod, len(other_type.args)): + if not self.args[i].type.same_as( + other_type.args[i].type): + return 0 + if self.has_varargs != other_type.has_varargs: + return 0 + if not self.return_type.same_as(other_type.return_type): + return 0 + if not self.same_calling_convention_as(other_type): + return 0 + self.old_signature = other_type + if as_cmethod: + self.args[0] = other_type.args[0] + if self.optional_arg_count and \ + self.optional_arg_count == other_type.optional_arg_count: + self.op_args = other_type.op_args + print self.op_args, other_type.op_args, self.optional_arg_count, other_type.optional_arg_count + elif self.optional_arg_count: + print self.op_args, other_type.op_args, self.optional_arg_count, other_type.optional_arg_count + 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) @@ -698,6 +742,7 @@ class CFuncType(CType): arg.type.declaration_code("", for_display, pyrex = pyrex)) if self.optional_arg_count: arg_decl_list.append(self.op_args.declaration_code(Naming.optional_args_cname)) +# arg_decl_list.append(c_void_ptr_type.declaration_code(Naming.optional_args_cname)) if self.has_varargs: arg_decl_list.append("...") arg_decl_code = string.join(arg_decl_list, ", ") diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index aeeee977..6b13e540 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -1273,11 +1273,14 @@ class CClassScope(ClassScope): if defining and entry.func_cname: error(pos, "'%s' already defined" % name) #print "CClassScope.declare_cfunction: checking signature" ### - if type.same_c_signature_as(entry.type, as_cmethod = 1): - pass + if type.compatible_signature_with(entry.type, as_cmethod = 1): + entry.type = type + elif type.same_c_signature_as(entry.type, as_cmethod = 1): + print "not compatible", name # if type.narrower_c_signature_than(entry.type, as_cmethod = 1): # entry.type = type else: + print "here" error(pos, "Signature not compatible with previous declaration") else: if self.defined: -- 2.26.2