From: Stefan Behnel Date: Mon, 8 Nov 2010 11:34:32 +0000 (+0100) Subject: second try to fix ticket #583: method signatures of overridden C methods in pure... X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=78a87802d451f214b25332f5a6349aad73eaa72b;p=cython.git second try to fix ticket #583: method signatures of overridden C methods in pure mode --- diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 83e89d4a..0735e39d 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -534,8 +534,9 @@ class CFuncDeclaratorNode(CDeclaratorNode): if nonempty: nonempty -= 1 func_type_args = [] - for arg_node in self.args: - name_declarator, type = arg_node.analyse(env, nonempty = nonempty) + for i, arg_node in enumerate(self.args): + name_declarator, type = arg_node.analyse(env, nonempty = nonempty, + is_self_arg = (i == 0 and env.is_c_class_scope)) name = name_declarator.name if name_declarator.cname: error(self.pos, @@ -649,8 +650,9 @@ class CArgDeclNode(Node): default_value = None annotation = None - def analyse(self, env, nonempty = 0): - #print "CArgDeclNode.analyse: is_self_arg =", self.is_self_arg ### + def analyse(self, env, nonempty = 0, is_self_arg = False): + if is_self_arg: + self.base_type.is_self_arg = self.is_self_arg = True if self.type is None: # The parser may missinterpret names as types... # We fix that here. @@ -1600,7 +1602,7 @@ class CFuncDefNode(FuncDefNode): def analyse_declarations(self, env): self.directive_locals.update(env.directives['locals']) base_type = self.base_type.analyse(env) - # The 2 here is because we need both function and argument names. + # The 2 here is because we need both function and argument names. name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None)) if not type.is_cfunction: error(self.pos, @@ -1907,12 +1909,15 @@ class DefNode(FuncDefNode): is_overridable = True) cfunc = CVarDefNode(self.pos, type=cfunc_type) else: + if scope is None: + scope = cfunc.scope cfunc_type = cfunc.type if len(self.args) != len(cfunc_type.args) or cfunc_type.has_varargs: error(self.pos, "wrong number of arguments") error(cfunc.pos, "previous declaration here") - for formal_arg, type_arg in zip(self.args, cfunc_type.args): - name_declarator, type = formal_arg.analyse(cfunc.scope, nonempty=1) + for i, (formal_arg, type_arg) in enumerate(zip(self.args, cfunc_type.args)): + name_declarator, type = formal_arg.analyse(scope, nonempty=1, + is_self_arg = (i == 0 and scope.is_c_class_scope)) if type is None or type is PyrexTypes.py_object_type: formal_arg.type = type_arg.type formal_arg.name_declarator = name_declarator diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index 753dfb42..2be6f7a4 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -1233,15 +1233,11 @@ class AlignFunctionDefinitions(CythonTransform): def visit_DefNode(self, node): pxd_def = self.scope.lookup(node.name) if pxd_def: - if self.scope.is_c_class_scope and len(pxd_def.type.args) > 0: - # The self parameter type needs adjusting. - pxd_def.type.args[0].type = self.scope.parent_type - if pxd_def.is_cfunction: - node = node.as_cfunction(pxd_def) - else: + if not pxd_def.is_cfunction: error(node.pos, "'%s' redeclared" % node.name) error(pxd_def.pos, "previous declaration here") return None + node = node.as_cfunction(pxd_def) elif self.scope.is_module_scope and self.directives['auto_cpdef']: node = node.as_cfunction(scope=self.scope) # Enable this when internal def functions are allowed. diff --git a/tests/run/pure_mode_cmethod_inheritance_T583.pxd b/tests/run/pure_mode_cmethod_inheritance_T583.pxd index 79d4af9e..f6108008 100644 --- a/tests/run/pure_mode_cmethod_inheritance_T583.pxd +++ b/tests/run/pure_mode_cmethod_inheritance_T583.pxd @@ -1,5 +1,19 @@ cdef class Base: - cpdef str method(self) + cpdef str noargs(self) + cpdef str int_arg(self, int i) + cpdef str _class(tp) cdef class Derived(Base): - cpdef str method(self) + cpdef str noargs(self) + cpdef str int_arg(self, int i) + cpdef str _class(tp) + +cdef class DerivedDerived(Derived): + cpdef str noargs(self) + cpdef str int_arg(self, int i) + cpdef str _class(tp) + +cdef class Derived2(Base): + cpdef str noargs(self) + cpdef str int_arg(self, int i) + cpdef str _class(tp) diff --git a/tests/run/pure_mode_cmethod_inheritance_T583.py b/tests/run/pure_mode_cmethod_inheritance_T583.py index 44a88f19..92a28473 100644 --- a/tests/run/pure_mode_cmethod_inheritance_T583.py +++ b/tests/run/pure_mode_cmethod_inheritance_T583.py @@ -1,18 +1,74 @@ class Base(object): ''' >>> base = Base() - >>> print(base.method()) + >>> print(base.noargs()) + Base + >>> print(base.int_arg(1)) + Base + >>> print(base._class()) Base ''' - def method(self): + def noargs(self): + return "Base" + def int_arg(self, i): + return "Base" + @classmethod + def _class(tp): return "Base" class Derived(Base): ''' >>> derived = Derived() - >>> print(derived.method()) + >>> print(derived.noargs()) + Derived + >>> print(derived.int_arg(1)) + Derived + >>> print(derived._class()) Derived ''' - def method(self): + def noargs(self): + return "Derived" + def int_arg(self, i): + return "Derived" + @classmethod + def _class(tp): return "Derived" + + +class DerivedDerived(Derived): + ''' + >>> derived = DerivedDerived() + >>> print(derived.noargs()) + DerivedDerived + >>> print(derived.int_arg(1)) + DerivedDerived + >>> print(derived._class()) + DerivedDerived + ''' + def noargs(self): + return "DerivedDerived" + def int_arg(self, i): + return "DerivedDerived" + @classmethod + def _class(tp): + return "DerivedDerived" + + +class Derived2(Base): + ''' + >>> derived = Derived2() + >>> print(derived.noargs()) + Derived2 + >>> print(derived.int_arg(1)) + Derived2 + >>> print(derived._class()) + Derived2 + ''' + def noargs(self): + return "Derived2" + def int_arg(self, i): + return "Derived2" + @classmethod + def _class(tp): + return "Derived2"