Commit 593e4420 authored by Xavier Thompson's avatar Xavier Thompson

Make cypclasses inherit from ancestors in MRO order

parent 931de505
...@@ -2117,13 +2117,6 @@ if VALUE is not None: ...@@ -2117,13 +2117,6 @@ if VALUE is not None:
return property return property
class ComputeMROTransform(CythonTransform):
def visit_CppClassNode(self, node):
if node.cypclass:
node.entry.type.compute_mro()
return node
class CalculateQualifiedNamesTransform(EnvTransform): class CalculateQualifiedNamesTransform(EnvTransform):
""" """
Calculate and store the '__qualname__' and the global Calculate and store the '__qualname__' and the global
......
...@@ -142,7 +142,6 @@ def create_pipeline(context, mode, exclude_classes=()): ...@@ -142,7 +142,6 @@ def create_pipeline(context, mode, exclude_classes=()):
from .Visitor import PrintTree from .Visitor import PrintTree
from .ParseTreeTransforms import WithTransform, NormalizeTree, PostParse, PxdPostParse from .ParseTreeTransforms import WithTransform, NormalizeTree, PostParse, PxdPostParse
from .ParseTreeTransforms import ForwardDeclareTypes, InjectGilHandling, AnalyseDeclarationsTransform from .ParseTreeTransforms import ForwardDeclareTypes, InjectGilHandling, AnalyseDeclarationsTransform
from .ParseTreeTransforms import ComputeMROTransform
from .ParseTreeTransforms import AnalyseExpressionsTransform, FindInvalidUseOfFusedTypes from .ParseTreeTransforms import AnalyseExpressionsTransform, FindInvalidUseOfFusedTypes
from .ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform from .ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform
from .ParseTreeTransforms import TrackNumpyAttributes, InterpretCompilerDirectives, TransformBuiltinMethods from .ParseTreeTransforms import TrackNumpyAttributes, InterpretCompilerDirectives, TransformBuiltinMethods
...@@ -197,7 +196,6 @@ def create_pipeline(context, mode, exclude_classes=()): ...@@ -197,7 +196,6 @@ def create_pipeline(context, mode, exclude_classes=()):
ForwardDeclareTypes(context), ForwardDeclareTypes(context),
InjectGilHandling(), InjectGilHandling(),
AnalyseDeclarationsTransform(context), AnalyseDeclarationsTransform(context),
ComputeMROTransform(context),
AutoTestDictTransform(context), AutoTestDictTransform(context),
EmbedSignature(context), EmbedSignature(context),
ReplacePropertyNode(context), ReplacePropertyNode(context),
......
...@@ -3956,7 +3956,7 @@ def compute_mro_generic(cls): ...@@ -3956,7 +3956,7 @@ def compute_mro_generic(cls):
class CypClassType(CppClassType): class CypClassType(CppClassType):
# lock_mode string (tri-state: "nolock"/"checklock"/"autolock") # lock_mode string (tri-state: "nolock"/"checklock"/"autolock")
# mro [CppClassType] or None The Method Resolution Order of this cypclass according to Python # _mro [CppClassType] or None The Method Resolution Order of this cypclass according to Python
is_cyp_class = 1 is_cyp_class = 1
...@@ -3964,27 +3964,27 @@ class CypClassType(CppClassType): ...@@ -3964,27 +3964,27 @@ class CypClassType(CppClassType):
CppClassType.__init__(self, name, scope, cname, base_classes, templates, template_type, nogil) CppClassType.__init__(self, name, scope, cname, base_classes, templates, template_type, nogil)
self.lock_mode = lock_mode if lock_mode else "autolock" self.lock_mode = lock_mode if lock_mode else "autolock"
self.activable = activable self.activable = activable
self.mro = None self._mro = None
# compute the MRO for this cypclass # Return the MRO for this cypclass
# the mro is also computed for bases when needed # Compute all the mro needed when a previous computation is not available
# based on https://mail.python.org/pipermail/python-dev/2002-October/029176.html # based on https://mail.python.org/pipermail/python-dev/2002-October/029176.html
def compute_mro(self): def mro(self):
if self.mro is not None: if self._mro is not None:
return self.mro return self._mro
if self.base_classes is None: if self.base_classes is None:
self.mro = [self] self._mro = [self]
return self.mro return self._mro
inputs = [[self]] inputs = [[self]]
for base in self.base_classes: for base in self.base_classes:
if base.is_cyp_class: if base.is_cyp_class:
base_mro = base.compute_mro() base_mro = base.mro()
else: else:
base_mro = compute_mro_generic(base) base_mro = compute_mro_generic(base)
inputs.append(base_mro) inputs.append(base_mro)
inputs.append(self.base_classes) inputs.append(self.base_classes)
self.mro = mro_C3_merge(inputs) self._mro = mro_C3_merge(inputs)
return self.mro return self._mro
def empty_declaration_code(self): def empty_declaration_code(self):
if self._empty_declaration is None: if self._empty_declaration is None:
......
...@@ -710,14 +710,24 @@ class Scope(object): ...@@ -710,14 +710,24 @@ class Scope(object):
entry.already_declared_here() entry.already_declared_here()
def declare_inherited_attributes(entry, base_classes): def declare_inherited_attributes(entry, base_classes):
for base_class in base_classes: def examine_base(base_class):
if base_class is PyrexTypes.error_type or base_class is PyrexTypes.cy_object_type: if base_class is PyrexTypes.error_type or base_class is PyrexTypes.cy_object_type:
continue return False
if base_class.scope is None: if base_class.scope is None:
error(pos, "Cannot inherit from incomplete type") error(pos, "Cannot inherit from incomplete type")
else: return False
declare_inherited_attributes(entry, base_class.base_classes) return True
entry.type.scope.declare_inherited_cpp_attributes(base_class)
if cypclass:
for base_class in reversed(entry.type.mro()):
if examine_base(base_class):
entry.type.scope.declare_inherited_cyp_attributes(base_class)
else:
for base_class in base_classes:
if examine_base(base_class):
declare_inherited_attributes(entry, base_class.base_classes)
entry.type.scope.declare_inherited_cpp_attributes(base_class)
if scope: if scope:
entry.type.set_scope(scope) entry.type.set_scope(scope)
declare_inherited_attributes(entry, base_classes) declare_inherited_attributes(entry, base_classes)
...@@ -2891,6 +2901,79 @@ class CppClassScope(Scope): ...@@ -2891,6 +2901,79 @@ class CppClassScope(Scope):
entry.is_inherited = 1 entry.is_inherited = 1
self.inherited_type_entries.append(entry) self.inherited_type_entries.append(entry)
def declare_inherited_cyp_attributes(self, base_class):
base_scope = base_class.scope
template_type = base_class
while getattr(template_type, 'template_type', None):
template_type = template_type.template_type
if getattr(template_type, 'templates', None):
base_templates = [T.name for T in template_type.templates]
else:
base_templates = ()
# Declare entries for all the C++ attributes of an
# inherited type, with cnames modified appropriately
# to work with this type.
for base_entry in base_scope.var_entries:
base_entry_type = base_entry.type
#constructor/destructor is not inherited
if base_entry.name == "<del>"\
or base_entry.name in ("<constructor>", "<alloc>", "<active_self>", "__activate__"):
continue
elif base_entry.name == "<init>" and not self.lookup_here("__new__"):
wrapper_entry = self.declare_constructor_wrapper(base_entry_type.args, base_entry.pos,
defining=1, has_varargs = base_entry_type.has_varargs,
optional_arg_count = base_entry_type.optional_arg_count,
op_arg_struct = getattr(base_entry_type, 'op_arg_struct', None),
return_type=self.parent_type)
wrapper_entry.is_inherited = 1
elif base_entry.name == "__new__":
# Rewrite first argument for __new__
alloc_type = PyrexTypes.CPtrType(PyrexTypes.CFuncType(self.parent_type, [], nogil=1))
alloc_arg = PyrexTypes.CFuncTypeArg(base_entry.type.args[0].name, alloc_type,
base_entry.type.args[0].pos, cname=base_entry.type.args[0].cname)
base_entry_type = PyrexTypes.CFuncType(base_entry_type.return_type,
[alloc_arg] + base_entry_type.args[1:], nogil=1,
has_varargs=base_entry_type.has_varargs,
optional_arg_count=base_entry_type.optional_arg_count)
if hasattr(base_entry.type, 'op_arg_struct'):
base_entry_type.op_arg_struct = base_entry.type.op_arg_struct
base_entry_type.original_alloc_type = base_entry.type.original_alloc_type
if base_entry.name in self.entries:
del self.entries[base_entry.name]
del self.entries["<constructor>"]
elif "<init>" in self.entries:
del self.entries["<constructor>"]
wrapper_entry = self.declare_constructor_wrapper(base_entry_type.args[1:],
base_entry.pos, defining=1,
has_varargs = base_entry_type.has_varargs,
optional_arg_count = base_entry_type.optional_arg_count,
op_arg_struct = getattr(base_entry_type, 'op_arg_struct', None),
return_type=base_entry_type.return_type)
wrapper_entry.is_inherited = 1
entry = self.declare(base_entry.name, base_entry.cname, base_entry_type, base_entry.pos, 'extern')
entry.is_variable = 1
entry.is_inherited = 1
entry.is_cfunction = base_entry.is_cfunction
if entry.is_cfunction:
entry.func_cname = base_entry.func_cname
self.inherited_var_entries.append(entry)
for base_entry in base_scope.cfunc_entries:
entry = self.declare_cfunction(base_entry.name, base_entry.type,
base_entry.pos, base_entry.cname,
base_entry.visibility, api=0,
modifiers=base_entry.func_modifiers,
utility_code=base_entry.utility_code,
inheriting=1)
entry.is_inherited = 1
for base_entry in base_scope.type_entries:
if base_entry.name not in base_templates:
entry = self.declare_type(base_entry.name, base_entry.type,
base_entry.pos, base_entry.cname,
base_entry.visibility, defining=0)
entry.is_inherited = 1
self.inherited_type_entries.append(entry)
def specialize(self, values, type_entry): def specialize(self, values, type_entry):
scope = CppClassScope(self.name, self.outer_scope) scope = CppClassScope(self.name, self.outer_scope)
scope.type = type_entry scope.type = type_entry
......
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