Commit cf2ffbcc authored by Robert Bradshaw's avatar Robert Bradshaw

Cleanup.

parent c2e7b11e
...@@ -2875,7 +2875,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2875,7 +2875,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.generate_base_type_import_code(env, entry, code) self.generate_base_type_import_code(env, entry, code)
self.generate_exttype_vtable_init_code(entry, code) self.generate_exttype_vtable_init_code(entry, code)
if entry.type.early_init: if entry.type.early_init:
self.generate_type_ready_code(entry, code) self.generate_type_ready_code(entry, code)
def generate_base_type_import_code(self, env, entry, code): def generate_base_type_import_code(self, env, entry, code):
base_type = entry.type.base_type base_type = entry.type.base_type
......
...@@ -4589,34 +4589,33 @@ class CClassDefNode(ClassDefNode): ...@@ -4589,34 +4589,33 @@ class CClassDefNode(ClassDefNode):
env.add_imported_module(self.module) env.add_imported_module(self.module)
if self.bases.args: if self.bases.args:
base = self.bases.args[0] base = self.bases.args[0]
base_type = base.analyse_as_type(env) base_type = base.analyse_as_type(env)
if base_type in (PyrexTypes.c_int_type, PyrexTypes.c_long_type, PyrexTypes.c_float_type): if base_type in (PyrexTypes.c_int_type, PyrexTypes.c_long_type, PyrexTypes.c_float_type):
# Use the Python rather than C variant of these types. # Use the Python rather than C variant of these types.
base_type = env.lookup(str(base_type)).type base_type = env.lookup(base_type.sign_and_name()).type
if base_type is None: if base_type is None:
error(base.pos, "First base of '%s' is not an extension type" % self.class_name) error(base.pos, "First base of '%s' is not an extension type" % self.class_name)
elif base_type == PyrexTypes.py_object_type: elif base_type == PyrexTypes.py_object_type:
base_class_scope = None base_class_scope = None
elif not base_type.is_extension_type and \ elif not base_type.is_extension_type and \
not (base_type.is_builtin_type and base_type.objstruct_cname): not (base_type.is_builtin_type and base_type.objstruct_cname):
print (base_type, base_type.is_builtin_type) error(base.pos, "'%s' is not an extension type" % base_type)
error(base.pos, "'%s' is not an extension type" % base_type) elif not base_type.is_complete():
elif not base_type.is_complete(): error(base.pos, "Base class '%s' of type '%s' is incomplete" % (
error(base.pos, "Base class '%s' of type '%s' is incomplete" % ( base_type.name, self.class_name))
base_type.name, self.class_name)) elif base_type.scope and base_type.scope.directives and \
elif base_type.scope and base_type.scope.directives and \ base_type.is_final_type:
base_type.is_final_type: error(base.pos, "Base class '%s' of type '%s' is final" % (
error(base.pos, "Base class '%s' of type '%s' is final" % ( base_type, self.class_name))
base_type, self.class_name)) elif base_type.is_builtin_type and \
elif base_type.is_builtin_type and \ base_type.name in ('tuple', 'str', 'bytes'):
base_type.name in ('tuple', 'str', 'bytes'): error(base.pos, "inheritance from PyVarObject types like '%s' is not currently supported"
error(base.pos, "inheritance from PyVarObject types like '%s' is not currently supported" % base_type.name)
% base_type.name) else:
else: self.base_type = base_type
self.base_type = base_type if env.directives.get('freelist', 0) > 0 and base_type != PyrexTypes.py_object_type:
if env.directives.get('freelist', 0) > 0 and base_type != PyrexTypes.py_object_type: warning(self.pos, "freelists cannot be used on subtypes, only the base class can manage them", 1)
warning(self.pos, "freelists cannot be used on subtypes, only the base class can manage them", 1)
has_body = self.body is not None has_body = self.body is not None
if has_body and self.base_type and not self.base_type.scope: if has_body and self.base_type and not self.base_type.scope:
...@@ -4677,29 +4676,29 @@ class CClassDefNode(ClassDefNode): ...@@ -4677,29 +4676,29 @@ class CClassDefNode(ClassDefNode):
scope.implemented = 1 scope.implemented = 1
if len(self.bases.args) > 1: if len(self.bases.args) > 1:
if not has_body or self.in_pxd: if not has_body or self.in_pxd:
error(self.bases.args[1].pos, "Only declare first base in declaration.") error(self.bases.args[1].pos, "Only declare first base in declaration.")
for other_base in self.bases.args[1:]: for other_base in self.bases.args[1:]:
if other_base.analyse_as_type(env): if other_base.analyse_as_type(env):
# TODO(robertwb): We may also want to enforce some checks # TODO(robertwb): We may also want to enforce some checks
# at runtime. # at runtime.
error(other_base.pos, "Only one extension type base class allowed.") error(other_base.pos, "Only one extension type base class allowed.")
if not self.scope.lookup("__dict__"): if not self.scope.lookup("__dict__"):
#TODO(robertwb): See if this can be safely removed. #TODO(robertwb): See if this can be safely removed.
error(self.pos, "Extension types with multiple bases must have a __dict__ attribute") error(self.pos, "Extension types with multiple bases must have a __dict__ attribute")
self.entry.type.early_init = 0 self.entry.type.early_init = 0
from . import ExprNodes from . import ExprNodes
self.type_init_args = ExprNodes.TupleNode( self.type_init_args = ExprNodes.TupleNode(
self.pos, self.pos,
args=[ExprNodes.StringNode(self.pos, value=self.class_name), args=[ExprNodes.IdentifierStringNode(self.pos, value=self.class_name),
self.bases, self.bases,
ExprNodes.DictNode(self.pos, key_value_pairs=[])]) ExprNodes.DictNode(self.pos, key_value_pairs=[])])
elif self.base_type: elif self.base_type:
self.entry.type.early_init = self.base_type.is_external or self.base_type.early_init self.entry.type.early_init = self.base_type.is_external or self.base_type.early_init
self.type_init_args = None self.type_init_args = None
else: else:
self.entry.type.early_init = 1 self.entry.type.early_init = 1
self.type_init_args = None self.type_init_args = None
env.allocate_vtable_names(self.entry) env.allocate_vtable_names(self.entry)
...@@ -4727,29 +4726,29 @@ class CClassDefNode(ClassDefNode): ...@@ -4727,29 +4726,29 @@ class CClassDefNode(ClassDefNode):
self.body.generate_execution_code(code) self.body.generate_execution_code(code)
if not self.entry.type.early_init: if not self.entry.type.early_init:
if self.type_init_args: if self.type_init_args:
self.type_init_args.generate_evaluation_code(code) self.type_init_args.generate_evaluation_code(code)
bases = "PyTuple_GET_ITEM(%s, 1)" % self.type_init_args.result() bases = "PyTuple_GET_ITEM(%s, 1)" % self.type_init_args.result()
first_base = "((PyTypeObject*)PyTuple_GET_ITEM(%s, 0))" % bases first_base = "((PyTypeObject*)PyTuple_GET_ITEM(%s, 0))" % bases
# Let Python do the base types compatibility checking. # Let Python do the base types compatibility checking.
trial_type = code.funcstate.allocate_temp(PyrexTypes.py_object_type, True) trial_type = code.funcstate.allocate_temp(PyrexTypes.py_object_type, True)
code.putln("%s = PyType_Type.tp_new(&PyType_Type, %s, NULL);" % ( code.putln("%s = PyType_Type.tp_new(&PyType_Type, %s, NULL);" % (
trial_type, self.type_init_args.result())) trial_type, self.type_init_args.result()))
code.putln(code.error_goto_if_null(trial_type, self.pos)) code.putln(code.error_goto_if_null(trial_type, self.pos))
code.put_gotref(trial_type) code.put_gotref(trial_type)
code.putln("if (((PyTypeObject*) %s)->tp_base != %s) {" % ( code.putln("if (((PyTypeObject*) %s)->tp_base != %s) {" % (
trial_type, first_base)) trial_type, first_base))
code.putln("PyErr_Format(PyExc_TypeError, \"best base '%s' must be equal to first base '%s'\",") code.putln("PyErr_Format(PyExc_TypeError, \"best base '%s' must be equal to first base '%s'\",")
code.putln(" ((PyTypeObject*) %s)->tp_base->tp_name, %s->tp_name);" % ( code.putln(" ((PyTypeObject*) %s)->tp_base->tp_name, %s->tp_name);" % (
trial_type, first_base)) trial_type, first_base))
code.putln(code.error_goto(self.pos)) code.putln(code.error_goto(self.pos))
code.putln("}") code.putln("}")
code.funcstate.release_temp(trial_type) code.funcstate.release_temp(trial_type)
code.put_incref(bases, PyrexTypes.py_object_type) code.put_incref(bases, PyrexTypes.py_object_type)
code.put_giveref(bases) code.put_giveref(bases)
code.putln("%s.tp_bases = %s;" % (self.entry.type.typeobj_cname, bases)) code.putln("%s.tp_bases = %s;" % (self.entry.type.typeobj_cname, bases))
code.put_decref_clear(trial_type, PyrexTypes.py_object_type) code.put_decref_clear(trial_type, PyrexTypes.py_object_type)
self.type_init_args.generate_disposal_code(code) self.type_init_args.generate_disposal_code(code)
self.type_init_args.free_temps(code) self.type_init_args.free_temps(code)
self.generate_type_ready_code(self.entry, code, True) self.generate_type_ready_code(self.entry, code, True)
...@@ -4761,106 +4760,107 @@ class CClassDefNode(ClassDefNode): ...@@ -4761,106 +4760,107 @@ class CClassDefNode(ClassDefNode):
type = entry.type type = entry.type
typeobj_cname = type.typeobj_cname typeobj_cname = type.typeobj_cname
scope = type.scope scope = type.scope
if scope: # could be None if there was an error if not scope: # could be None if there was an error
if entry.visibility != 'extern': return
for slot in TypeSlots.slot_table: if entry.visibility != 'extern':
slot.generate_dynamic_init_code(scope, code) for slot in TypeSlots.slot_table:
if heap_type_bases: slot.generate_dynamic_init_code(scope, code)
# As of https://bugs.python.org/issue22079 if heap_type_bases:
# PyType_Ready enforces that all bases of a non-heap type # As of https://bugs.python.org/issue22079
# are non-heap. We know this is the case for the solid base, # PyType_Ready enforces that all bases of a non-heap type
# but other bases may be heap allocated and are kept alive # are non-heap. We know this is the case for the solid base,
# though the bases reference. # but other bases may be heap allocated and are kept alive
# Other than this check, this flag is unused in this method. # though the bases reference.
code.putln("#if PY_VERSION_HEX >= 0x03050000") # Other than this check, this flag is unused in this method.
code.putln("%s.tp_flags |= Py_TPFLAGS_HEAPTYPE;" % typeobj_cname) code.putln("#if PY_VERSION_HEX >= 0x03050000")
code.putln("#endif") code.putln("%s.tp_flags |= Py_TPFLAGS_HEAPTYPE;" % typeobj_cname)
code.putln( code.putln("#endif")
"if (PyType_Ready(&%s) < 0) %s" % ( code.putln(
typeobj_cname, "if (PyType_Ready(&%s) < 0) %s" % (
code.error_goto(entry.pos))) typeobj_cname,
if heap_type_bases: code.error_goto(entry.pos)))
code.putln("#if PY_VERSION_HEX >= 0x03050000") if heap_type_bases:
code.putln("%s.tp_flags &= ~Py_TPFLAGS_HEAPTYPE;" % typeobj_cname) code.putln("#if PY_VERSION_HEX >= 0x03050000")
code.putln("#endif") code.putln("%s.tp_flags &= ~Py_TPFLAGS_HEAPTYPE;" % typeobj_cname)
# Don't inherit tp_print from builtin types, restoring the code.putln("#endif")
# behavior of using tp_repr or tp_str instead. # Don't inherit tp_print from builtin types, restoring the
code.putln("%s.tp_print = 0;" % typeobj_cname) # behavior of using tp_repr or tp_str instead.
# Fix special method docstrings. This is a bit of a hack, but code.putln("%s.tp_print = 0;" % typeobj_cname)
# unless we let PyType_Ready create the slot wrappers we have # Fix special method docstrings. This is a bit of a hack, but
# a significant performance hit. (See trac #561.) # unless we let PyType_Ready create the slot wrappers we have
for func in entry.type.scope.pyfunc_entries: # a significant performance hit. (See trac #561.)
is_buffer = func.name in ('__getbuffer__', '__releasebuffer__') for func in entry.type.scope.pyfunc_entries:
if (func.is_special and Options.docstrings and is_buffer = func.name in ('__getbuffer__', '__releasebuffer__')
func.wrapperbase_cname and not is_buffer): if (func.is_special and Options.docstrings and
slot = TypeSlots.method_name_to_slot[func.name] func.wrapperbase_cname and not is_buffer):
preprocessor_guard = slot.preprocessor_guard_code() slot = TypeSlots.method_name_to_slot[func.name]
if preprocessor_guard: preprocessor_guard = slot.preprocessor_guard_code()
code.putln(preprocessor_guard) if preprocessor_guard:
code.putln('#if CYTHON_COMPILING_IN_CPYTHON') code.putln(preprocessor_guard)
code.putln("{") code.putln('#if CYTHON_COMPILING_IN_CPYTHON')
code.putln( code.putln("{")
'PyObject *wrapper = PyObject_GetAttrString((PyObject *)&%s, "%s"); %s' % (
typeobj_cname,
func.name,
code.error_goto_if_null('wrapper', entry.pos)))
code.putln(
"if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) {")
code.putln(
"%s = *((PyWrapperDescrObject *)wrapper)->d_base;" % (
func.wrapperbase_cname))
code.putln(
"%s.doc = %s;" % (func.wrapperbase_cname, func.doc_cname))
code.putln(
"((PyWrapperDescrObject *)wrapper)->d_base = &%s;" % (
func.wrapperbase_cname))
code.putln("}")
code.putln("}")
code.putln('#endif')
if preprocessor_guard:
code.putln('#endif')
if type.vtable_cname:
code.putln( code.putln(
"if (__Pyx_SetVtable(%s.tp_dict, %s) < 0) %s" % ( 'PyObject *wrapper = PyObject_GetAttrString((PyObject *)&%s, "%s"); %s' % (
typeobj_cname, typeobj_cname,
type.vtabptr_cname, func.name,
code.error_goto(entry.pos))) code.error_goto_if_null('wrapper', entry.pos)))
code.globalstate.use_utility_code(
UtilityCode.load_cached('SetVTable', 'ImportExport.c'))
if not type.scope.is_internal and not type.scope.directives['internal']:
# scope.is_internal is set for types defined by
# Cython (such as closures), the 'internal'
# directive is set by users
code.putln( code.putln(
'if (PyObject_SetAttrString(%s, "%s", (PyObject *)&%s) < 0) %s' % ( "if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) {")
Naming.module_cname, code.putln(
scope.class_name, "%s = *((PyWrapperDescrObject *)wrapper)->d_base;" % (
typeobj_cname, func.wrapperbase_cname))
code.error_goto(entry.pos))) code.putln(
weakref_entry = scope.lookup_here("__weakref__") if not scope.is_closure_class_scope else None "%s.doc = %s;" % (func.wrapperbase_cname, func.doc_cname))
if weakref_entry: code.putln(
if weakref_entry.type is py_object_type: "((PyWrapperDescrObject *)wrapper)->d_base = &%s;" % (
tp_weaklistoffset = "%s.tp_weaklistoffset" % typeobj_cname func.wrapperbase_cname))
if type.typedef_flag: code.putln("}")
objstruct = type.objstruct_cname code.putln("}")
else: code.putln('#endif')
objstruct = "struct %s" % type.objstruct_cname if preprocessor_guard:
code.putln("if (%s == 0) %s = offsetof(%s, %s);" % ( code.putln('#endif')
tp_weaklistoffset, if type.vtable_cname:
tp_weaklistoffset, code.putln(
objstruct, "if (__Pyx_SetVtable(%s.tp_dict, %s) < 0) %s" % (
weakref_entry.cname)) typeobj_cname,
type.vtabptr_cname,
code.error_goto(entry.pos)))
code.globalstate.use_utility_code(
UtilityCode.load_cached('SetVTable', 'ImportExport.c'))
if not type.scope.is_internal and not type.scope.directives['internal']:
# scope.is_internal is set for types defined by
# Cython (such as closures), the 'internal'
# directive is set by users
code.putln(
'if (PyObject_SetAttrString(%s, "%s", (PyObject *)&%s) < 0) %s' % (
Naming.module_cname,
scope.class_name,
typeobj_cname,
code.error_goto(entry.pos)))
weakref_entry = scope.lookup_here("__weakref__") if not scope.is_closure_class_scope else None
if weakref_entry:
if weakref_entry.type is py_object_type:
tp_weaklistoffset = "%s.tp_weaklistoffset" % typeobj_cname
if type.typedef_flag:
objstruct = type.objstruct_cname
else: else:
error(weakref_entry.pos, "__weakref__ slot must be of type 'object'") objstruct = "struct %s" % type.objstruct_cname
if scope.lookup_here("__reduce_cython__") if not scope.is_closure_class_scope else None: code.putln("if (%s == 0) %s = offsetof(%s, %s);" % (
# Unfortunately, we cannot reliably detect whether a tp_weaklistoffset,
# superclass defined __reduce__ at compile time, so we must tp_weaklistoffset,
# do so at runtime. objstruct,
code.globalstate.use_utility_code( weakref_entry.cname))
UtilityCode.load_cached('SetupReduce', 'ExtensionTypes.c')) else:
code.putln('if (__Pyx_setup_reduce((PyObject*)&%s) < 0) %s' % ( error(weakref_entry.pos, "__weakref__ slot must be of type 'object'")
typeobj_cname, if scope.lookup_here("__reduce_cython__") if not scope.is_closure_class_scope else None:
code.error_goto(entry.pos))) # Unfortunately, we cannot reliably detect whether a
# superclass defined __reduce__ at compile time, so we must
# do so at runtime.
code.globalstate.use_utility_code(
UtilityCode.load_cached('SetupReduce', 'ExtensionTypes.c'))
code.putln('if (__Pyx_setup_reduce((PyObject*)&%s) < 0) %s' % (
typeobj_cname,
code.error_goto(entry.pos)))
# Generate code to initialise the typeptr of an extension # Generate code to initialise the typeptr of an extension
# type defined in this module to point to its type object. # type defined in this module to point to its type object.
if type.typeobj_cname: if type.typeobj_cname:
......
...@@ -3439,10 +3439,10 @@ def p_c_class_definition(s, pos, ctx): ...@@ -3439,10 +3439,10 @@ def p_c_class_definition(s, pos, ctx):
if s.sy == '(': if s.sy == '(':
positional_args, keyword_args = p_call_parse_args(s, allow_genexp=False) positional_args, keyword_args = p_call_parse_args(s, allow_genexp=False)
if keyword_args: if keyword_args:
s.error("C classes cannot take keyword bases.") s.error("C classes cannot take keyword bases.")
bases, _ = p_call_build_packed_args(pos, positional_args, keyword_args) bases, _ = p_call_build_packed_args(pos, positional_args, keyword_args)
if bases is None: if bases is None:
bases = ExprNodes.TupleNode(pos, args=[]) bases = ExprNodes.TupleNode(pos, args=[])
if s.sy == '[': if s.sy == '[':
if ctx.visibility not in ('public', 'extern') and not ctx.api: if ctx.visibility not in ('public', 'extern') and not ctx.api:
......
cdef class CBase(object): cdef class CBase(object):
cdef int a cdef int a
cdef c_method(self): cdef c_method(self):
return "CBase" return "CBase"
cpdef cpdef_method(self): cpdef cpdef_method(self):
return "CBase" return "CBase"
class PyBase(object): class PyBase(object):
def py_method(self): def py_method(self):
return "PyBase" return "PyBase"
cdef class Both(CBase, PyBase): cdef class Both(CBase, PyBase):
cdef dict __dict__ cdef dict __dict__
""" """
>>> b = Both() >>> b = Both()
>>> b.py_method() >>> b.py_method()
'PyBase' 'PyBase'
>>> b.cp_method() >>> b.cp_method()
'Both' 'Both'
>>> b.call_c_method() >>> b.call_c_method()
'Both' 'Both'
>>> isinstance(b, CBase) >>> isinstance(b, CBase)
True True
>>> isinstance(b, PyBase) >>> isinstance(b, PyBase)
True True
""" """
cdef c_method(self): cdef c_method(self):
return "Both" return "Both"
cpdef cp_method(self): cpdef cp_method(self):
return "Both" return "Both"
def call_c_method(self): def call_c_method(self):
return self.c_method() return self.c_method()
cdef class BothSub(Both): cdef class BothSub(Both):
""" """
>>> b = BothSub() >>> b = BothSub()
>>> b.py_method() >>> b.py_method()
'PyBase' 'PyBase'
>>> b.cp_method() >>> b.cp_method()
'Both' 'Both'
>>> b.call_c_method() >>> b.call_c_method()
'Both' 'Both'
""" """
pass pass
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