diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index fcc3a21c97a9cc453f6ea0e860685fe319091cad..792ab2aef2f89aa5d1fd6afca93021b18361ffc2 100644 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -2553,11 +2553,11 @@ class CFuncType(CType): def as_argument_type(self): return c_ptr_type(self) - def same_c_signature_as(self, other_type, as_cmethod = 0): + def same_c_signature_as(self, other_type, as_cmethod = 0, as_pxd_definition = 0): return self.same_c_signature_as_resolved_type( other_type.resolve(), as_cmethod) - def same_c_signature_as_resolved_type(self, other_type, as_cmethod = 0): + def same_c_signature_as_resolved_type(self, other_type, as_cmethod = 0, as_pxd_definition = 0): #print "CFuncType.same_c_signature_as_resolved_type:", \ # self, other_type, "as_cmethod =", as_cmethod ### if other_type is error_type: @@ -2579,8 +2579,13 @@ class CFuncType(CType): return 0 if self.optional_arg_count != other_type.optional_arg_count: return 0 - if not self.return_type.same_as(other_type.return_type): - return 0 + if as_pxd_definition: + # A narrowing of the return type declared in the pxd is allowed. + if not self.return_type.subtype_of_resolved_type(other_type.return_type): + return 0 + else: + if not self.return_type.same_as(other_type.return_type): + return 0 if not self.same_calling_convention_as(other_type): return 0 if self.exception_check != other_type.exception_check: diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index d42f7f624b50f6e68cdf658a88ccbf091720579b..99d256d875d251dbdf99bb2419eb36cd34c117d6 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -2094,7 +2094,8 @@ class CClassScope(ClassScope): # Fix with_gil vs nogil. entry.type = entry.type.with_with_gil(type.with_gil) elif type.compatible_signature_with(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil: - if self.defined and not in_pxd: + if (self.defined and not in_pxd + and not type.same_c_signature_as_resolved_type(entry.type, as_cmethod = 1, as_pxd_definition = 1)): error(pos, "Compatible but non-identical C method '%s' not redeclared " "in definition part of extension type '%s'" % (name, self.class_name)) diff --git a/tests/errors/cmethbasematch.pxd b/tests/errors/cmethbasematch.pxd index 24e5466be26d97ebeba5989a7b353476c9fd29af..dc4aa2762097570fd293f4adf4336edb74b1369b 100644 --- a/tests/errors/cmethbasematch.pxd +++ b/tests/errors/cmethbasematch.pxd @@ -6,3 +6,6 @@ cdef class MissingRedeclaration(Base): cdef class BadRedeclaration(Base): cdef f(self) + +cdef class NarrowerReturn(Base): + pass diff --git a/tests/errors/cmethbasematch.pyx b/tests/errors/cmethbasematch.pyx index 1c1488a182c5949bd0ee790ff8d645e2ca230a14..154946ab9842d688dc1370f63234377aa2ff8a7a 100644 --- a/tests/errors/cmethbasematch.pyx +++ b/tests/errors/cmethbasematch.pyx @@ -28,6 +28,11 @@ cdef class UnneededRedeclaration(Base): cpdef f(self): pass +cdef class NarrowerReturn(Base): + # This does not require a new vtable entry. + cdef Base f(self): + pass + _ERRORS = u""" 8: 9: Signature not compatible with previous declaration