Commit 1c187e8b authored by Vitja Makarov's avatar Vitja Makarov

Final method support, see ticket #586

parent 278cc338
......@@ -3844,6 +3844,8 @@ class AttributeNode(ExprNode):
#print "...obj_code =", obj_code ###
if self.entry and self.entry.is_cmethod:
if obj.type.is_extension_type and not self.entry.is_builtin_cmethod:
if self.entry.final_func_cname:
return self.entry.final_func_cname
return "((struct %s *)%s%s%s)->%s" % (
obj.type.vtabstruct_cname, obj_code, self.op,
obj.type.vtabslot_cname, self.member)
......
......@@ -457,6 +457,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.generate_typeobj_predeclaration(entry, code)
self.generate_exttype_vtable_struct(entry, code)
self.generate_exttype_vtabptr_declaration(entry, code)
self.generate_exttype_final_methods_declaration(entry, code)
def generate_declarations_for_modules(self, env, modules, globalstate):
typecode = globalstate['type_declarations']
......@@ -991,6 +992,23 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
type.vtabstruct_cname,
type.vtabptr_cname))
def generate_exttype_final_methods_declaration(self, entry, code):
if not entry.used:
return
code.mark_pos(entry.pos)
# Generate final methods prototypes
type = entry.type
for method_entry in entry.type.scope.cfunc_entries:
if not method_entry.is_inherited and method_entry.final_func_cname:
declaration = method_entry.type.declaration_code(
method_entry.final_func_cname)
if entry.func_modifiers:
modifiers = "%s " % ' '.join(entry.func_modifiers).upper()
else:
modifiers = ''
code.putln("static %s%s;" % (modifiers, declaration))
def generate_objstruct_predeclaration(self, type, code):
if not type.scope:
return
......
......@@ -1751,7 +1751,8 @@ class CFuncDefNode(FuncDefNode):
self.entry.as_variable = self.py_func.entry
# Reset scope entry the above cfunction
env.entries[name] = self.entry
if not env.is_module_scope or Options.lookup_module_cpdef:
if (not self.entry.is_final_cmethod and
(not env.is_module_scope or Options.lookup_module_cpdef)):
self.override = OverrideCheckNode(self.pos, py_func = self.py_func)
self.body = StatListNode(self.pos, stats=[self.override, self.body])
self.create_local_scope(env)
......
......@@ -141,7 +141,7 @@ for key, val in directive_defaults.items():
directive_scopes = { # defaults to available everywhere
# 'module', 'function', 'class', 'with statement'
'final' : ('cclass',), # add 'method' in the future
'final' : ('cclass', 'function'),
'internal' : ('cclass',),
'autotestdict' : ('module',),
'autotestdict.all' : ('module',),
......
......@@ -70,6 +70,7 @@ class Entry(object):
# is_cmethod boolean Is a C method of an extension type
# is_builtin_cmethod boolean Is a C method of a builtin type (implies is_cmethod)
# is_unbound_cmethod boolean Is an unbound C method of an extension type
# is_final_cmethod boolean Is non-overridable C method
# is_anonymous boolean Is a anonymous pyfunction entry
# is_type boolean Is a type definition
# is_cclass boolean Is an extension class
......@@ -139,6 +140,7 @@ class Entry(object):
is_cmethod = 0
is_builtin_cmethod = False
is_unbound_cmethod = 0
is_final_cmethod = 0
is_anonymous = 0
is_type = 0
is_cclass = 0
......@@ -157,6 +159,7 @@ class Entry(object):
is_readonly = 0
func_cname = None
func_modifiers = []
final_func_cname = None
doc = None
as_variable = None
xdecref_cleanup = 0
......@@ -1798,7 +1801,9 @@ 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) and type.nogil == entry.type.nogil:
if entry.is_final_cmethod:
error(pos, "Overriding final methods is not allowed")
elif type.same_c_signature_as(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil:
pass
elif type.compatible_signature_with(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil:
entry = self.add_cfunction(name, type, pos, cname or name, visibility='ignore', modifiers=modifiers)
......@@ -1816,6 +1821,9 @@ class CClassScope(ClassScope):
if defining:
entry.func_cname = self.mangle(Naming.func_prefix, name)
entry.utility_code = utility_code
if self.directives.get('final'):
entry.is_final_cmethod = True
entry.final_func_cname = entry.func_cname
return entry
def add_cfunction(self, name, type, pos, cname, visibility, modifiers):
......@@ -1874,6 +1882,10 @@ class CClassScope(ClassScope):
base_entry.pos, cname,
base_entry.visibility, base_entry.func_modifiers)
entry.is_inherited = 1
if base_entry.is_final_cmethod:
entry.is_final_cmethod = True
if self.parent_scope == base_scope.parent_scope:
entry.final_func_cname = base_entry.final_func_cname
if is_builtin:
entry.is_builtin_cmethod = True
entry.as_variable = var_entry
......
# mode: error
cimport cython
cdef class BaseClass:
@cython.final
cdef cdef_method(self):
pass
@cython.final
cpdef cpdef_method(self):
pass
cdef class SubType(BaseClass):
cdef cdef_method(self):
pass
cpdef cpdef_method(self):
pass
_ERRORS = """
16:9: Overriding final methods is not allowed
19:10: Overriding final methods is not allowed
"""
# mode: run
# ticket: 568
cimport cython
cdef class FinalMethods(object):
"""
>>> obj = FinalMethods()
>>> obj.test_cdef()
>>> obj.test_cpdef()
"""
@cython.test_assert_path_exists("//CFuncDefNode[@entry.is_final_cmethod=True]")
@cython.final
cdef cdef_method(self):
pass
@cython.test_assert_path_exists("//CFuncDefNode[@entry.is_final_cmethod=True]")
@cython.test_fail_if_path_exists("//CFuncDefNode//OverrideCheckNode")
@cython.final
cpdef cpdef_method(self):
pass
@cython.test_assert_path_exists("//AttributeNode[@entry.is_final_cmethod=True]")
def test_cdef(self):
self.cdef_method()
@cython.test_assert_path_exists("//AttributeNode[@entry.is_final_cmethod=True]")
def test_cpdef(self):
self.cpdef_method()
cdef class SubType(FinalMethods):
"""
>>> obj = SubType()
>>> obj.test_cdef()
>>> obj.test_cpdef()
"""
@cython.test_assert_path_exists("//AttributeNode[@entry.is_final_cmethod=True]")
def test_cdef(self):
self.cdef_method()
@cython.test_assert_path_exists("//AttributeNode[@entry.is_final_cmethod=True]")
def test_cpdef(self):
self.cpdef_method()
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