Commit bae3c65e authored by Xavier Thompson's avatar Xavier Thompson

Use MRO to resolve ambiguous cypclass method calls instead of hiding overriden methods

parent ff1f5035
...@@ -400,7 +400,8 @@ def inject_acthon_interfaces(self): ...@@ -400,7 +400,8 @@ def inject_acthon_interfaces(self):
"ActhonResultInterface", result_scope, "ActhonResultInterface", (PyrexTypes.cy_object_type,), "ActhonResultInterface", result_scope, "ActhonResultInterface", (PyrexTypes.cy_object_type,),
lock_mode="nolock", activable=False) lock_mode="nolock", activable=False)
result_scope.type = result_type result_scope.type = result_type
#result_type.set_scope is a little bit overkill here, because parent_type is only used when doing scope inheritance #result_type.set_scope is required because parent_type is used when doing scope inheritance
result_type.set_scope(result_scope)
result_entry = self.declare("ActhonResultInterface", "ActhonResultInterface", result_type, None, "extern") result_entry = self.declare("ActhonResultInterface", "ActhonResultInterface", result_type, None, "extern")
result_entry.is_type = 1 result_entry.is_type = 1
...@@ -457,6 +458,7 @@ def inject_acthon_interfaces(self): ...@@ -457,6 +458,7 @@ def inject_acthon_interfaces(self):
acthon_message_type = message_type = PyrexTypes.CypClassType( acthon_message_type = message_type = PyrexTypes.CypClassType(
"ActhonMessageInterface", message_scope, "ActhonMessageInterface", (PyrexTypes.cy_object_type,), "ActhonMessageInterface", message_scope, "ActhonMessageInterface", (PyrexTypes.cy_object_type,),
lock_mode="nolock", activable=False) lock_mode="nolock", activable=False)
message_type.set_scope(message_scope)
message_scope.type = message_type message_scope.type = message_type
# cypclass ActhonSyncInterface(CyObject): # cypclass ActhonSyncInterface(CyObject):
...@@ -470,6 +472,7 @@ def inject_acthon_interfaces(self): ...@@ -470,6 +472,7 @@ def inject_acthon_interfaces(self):
acthon_sync_type = sync_type = PyrexTypes.CypClassType( acthon_sync_type = sync_type = PyrexTypes.CypClassType(
"ActhonSyncInterface", sync_scope, "ActhonSyncInterface", (PyrexTypes.cy_object_type,), "ActhonSyncInterface", sync_scope, "ActhonSyncInterface", (PyrexTypes.cy_object_type,),
lock_mode="nolock", activable=False) lock_mode="nolock", activable=False)
sync_type.set_scope(sync_scope)
sync_scope.type = sync_type sync_scope.type = sync_type
sync_entry = self.declare("ActhonSyncInterface", "ActhonSyncInterface", sync_type, None, "extern") sync_entry = self.declare("ActhonSyncInterface", "ActhonSyncInterface", sync_type, None, "extern")
sync_entry.is_type = 1 sync_entry.is_type = 1
...@@ -538,6 +541,7 @@ def inject_acthon_interfaces(self): ...@@ -538,6 +541,7 @@ def inject_acthon_interfaces(self):
acthon_queue_type = queue_type = PyrexTypes.CypClassType( acthon_queue_type = queue_type = PyrexTypes.CypClassType(
"ActhonQueueInterface", queue_scope, "ActhonQueueInterface", (PyrexTypes.cy_object_type,), "ActhonQueueInterface", queue_scope, "ActhonQueueInterface", (PyrexTypes.cy_object_type,),
lock_mode="nolock", activable=False) lock_mode="nolock", activable=False)
queue_type.set_scope(queue_scope)
queue_scope.type = queue_type queue_scope.type = queue_type
queue_entry = self.declare("ActhonQueueInterface", "ActhonQueueInterface", queue_type, self, "extern") queue_entry = self.declare("ActhonQueueInterface", "ActhonQueueInterface", queue_type, self, "extern")
queue_entry.is_type = 1 queue_entry.is_type = 1
...@@ -574,6 +578,7 @@ def inject_acthon_interfaces(self): ...@@ -574,6 +578,7 @@ def inject_acthon_interfaces(self):
acthon_activable_type = activable_type = PyrexTypes.CypClassType( acthon_activable_type = activable_type = PyrexTypes.CypClassType(
"ActhonActivableClass", activable_scope, "ActhonActivableClass", (PyrexTypes.cy_object_type,), "ActhonActivableClass", activable_scope, "ActhonActivableClass", (PyrexTypes.cy_object_type,),
lock_mode="nolock", activable=False) lock_mode="nolock", activable=False)
activable_type.set_scope(activable_scope)
activable_entry = self.declare("ActhonActivableClass", None, activable_type, "ActhonActivableClass", "extern") activable_entry = self.declare("ActhonActivableClass", None, activable_type, "ActhonActivableClass", "extern")
activable_entry.is_type = 1 activable_entry.is_type = 1
......
...@@ -4808,13 +4808,15 @@ def best_match(arg_types, functions, pos=None, env=None, args=None): ...@@ -4808,13 +4808,15 @@ def best_match(arg_types, functions, pos=None, env=None, args=None):
bad_types.append((func, error_mesg)) bad_types.append((func, error_mesg))
break break
else: else:
possibilities.append((score, index, func)) # so we can sort it from .Symtab import Entry
mro_score = func.mro_index if isinstance(func, Entry) else 0
possibilities.append((mro_score, score, index, func)) # so we can sort it
if possibilities: if possibilities:
possibilities.sort() possibilities.sort()
if len(possibilities) > 1: if len(possibilities) > 1:
score1 = possibilities[0][0] score1 = possibilities[0][:2]
score2 = possibilities[1][0] score2 = possibilities[1][:2]
if score1 == score2: if score1 == score2:
if pos is not None: if pos is not None:
error(pos, "ambiguous overloaded method") error(pos, "ambiguous overloaded method")
......
...@@ -165,6 +165,8 @@ class Entry(object): ...@@ -165,6 +165,8 @@ class Entry(object):
# #
# is_default boolean This entry is a compiler-generated default and # is_default boolean This entry is a compiler-generated default and
# is not user-defined (e.g default contructor) # is not user-defined (e.g default contructor)
# mro_index integer The index of the type where this entry was originally
# declared in the mro of the cypclass where it is now
# TODO: utility_code and utility_code_definition serves the same purpose... # TODO: utility_code and utility_code_definition serves the same purpose...
...@@ -253,6 +255,7 @@ class Entry(object): ...@@ -253,6 +255,7 @@ class Entry(object):
self.cf_references = [] self.cf_references = []
self.inner_entries = [] self.inner_entries = []
self.defining_entry = self self.defining_entry = self
self.mro_index = 0
def __repr__(self): def __repr__(self):
return "%s(<%x>, name=%s, type=%s)" % (type(self).__name__, id(self), self.name, self.type) return "%s(<%x>, name=%s, type=%s)" % (type(self).__name__, id(self), self.name, self.type)
...@@ -345,6 +348,7 @@ class Scope(object): ...@@ -345,6 +348,7 @@ class Scope(object):
# is_closure_scope boolean Is a closure scope # is_closure_scope boolean Is a closure scope
# is_passthrough boolean Outer scope is passed directly # is_passthrough boolean Outer scope is passed directly
# is_cpp_class_scope boolean Is a C++ class scope # is_cpp_class_scope boolean Is a C++ class scope
# is_cyp_class_scope boolean Is a C++ class scope of a cypclass
# is_property_scope boolean Is a extension type property scope # is_property_scope boolean Is a extension type property scope
# scope_prefix string Disambiguator for C names # scope_prefix string Disambiguator for C names
# in_cinclude boolean Suppress C declaration code # in_cinclude boolean Suppress C declaration code
...@@ -362,6 +366,7 @@ class Scope(object): ...@@ -362,6 +366,7 @@ class Scope(object):
is_genexpr_scope = 0 is_genexpr_scope = 0
is_passthrough = 0 is_passthrough = 0
is_cpp_class_scope = 0 is_cpp_class_scope = 0
is_cyp_class_scope = 0
is_property_scope = 0 is_property_scope = 0
is_module_scope = 0 is_module_scope = 0
is_internal = 0 is_internal = 0
...@@ -501,7 +506,7 @@ class Scope(object): ...@@ -501,7 +506,7 @@ class Scope(object):
key = entry key = entry
return self.tracked_entries.get(key, None) return self.tracked_entries.get(key, None)
def declare(self, name, cname, type, pos, visibility, shadow = 0, is_type = 0, create_wrapper = 0): def declare(self, name, cname, type, pos, visibility, shadow = 0, is_type = 0, create_wrapper = 0, from_type = None):
# Create new entry, and add to dictionary if # Create new entry, and add to dictionary if
# name is not None. Reports a warning if already # name is not None. Reports a warning if already
# declared. # declared.
...@@ -527,18 +532,15 @@ class Scope(object): ...@@ -527,18 +532,15 @@ class Scope(object):
cpp_override_allowed = False cpp_override_allowed = False
# If we're not in a cypclass, any inherited method is visible if self.is_cyp_class_scope:
# until overloaded by a method with the same signature # allow default constructor or __alloc__ to be redeclared by user
if not self.is_cyp_class_scope: if alt_entry.is_default:
if alt_entry.is_inherited:
previous_alternative_indices.append(index) previous_alternative_indices.append(index)
cpp_override_allowed = True cpp_override_allowed = True
# In a cypclass, only the predeclared default constructor and __alloc__ are allowed to be redeclared. # Any inherited method is visible
# We don't have to deal with inherited entries because they are hidden as soon as the subclass has a method # until overloaded by a method with the same signature
# of the same name, regardless of the exact signature (this is also C++ behavior by default). if alt_entry.is_inherited:
# The default entry is overriden when there is a subsequent entry with a compatible signature.
elif alt_entry.is_default:
previous_alternative_indices.append(index) previous_alternative_indices.append(index)
cpp_override_allowed = True cpp_override_allowed = True
...@@ -563,9 +565,13 @@ class Scope(object): ...@@ -563,9 +565,13 @@ class Scope(object):
elif visibility != 'ignore': elif visibility != 'ignore':
error(pos, "'%s' redeclared " % name) error(pos, "'%s' redeclared " % name)
old_entry.already_declared_here() old_entry.already_declared_here()
entry = Entry(name, cname, type, pos = pos) entry = Entry(name, cname, type, pos = pos)
if from_type and self.is_cyp_class_scope:
entry.mro_index = self.parent_type.mro().index(from_type)
entry.in_cinclude = self.in_cinclude entry.in_cinclude = self.in_cinclude
entry.create_wrapper = create_wrapper entry.create_wrapper = create_wrapper
if name: if name:
entry.qualified_name = self.qualify_name(name) entry.qualified_name = self.qualify_name(name)
...@@ -2672,7 +2678,6 @@ class CppClassScope(Scope): ...@@ -2672,7 +2678,6 @@ class CppClassScope(Scope):
# Namespace of a C++ class. # Namespace of a C++ class.
is_cpp_class_scope = 1 is_cpp_class_scope = 1
is_cyp_class_scope = 0
default_constructor = None default_constructor = None
type = None type = None
...@@ -2832,7 +2837,7 @@ class CppClassScope(Scope): ...@@ -2832,7 +2837,7 @@ class CppClassScope(Scope):
def declare_cfunction(self, name, type, pos, def declare_cfunction(self, name, type, pos,
cname=None, visibility='extern', api=0, in_pxd=0, cname=None, visibility='extern', api=0, in_pxd=0,
defining=0, modifiers=(), utility_code=None, overridable=False, inheriting=0): defining=0, modifiers=(), utility_code=None, overridable=False):
reify = self.type.is_cyp_class and self.type.activable reify = self.type.is_cyp_class and self.type.activable
class_name = self.name.split('::')[-1] class_name = self.name.split('::')[-1]
if name in (class_name, '__init__') and cname is None: if name in (class_name, '__init__') and cname is None:
...@@ -2853,13 +2858,6 @@ class CppClassScope(Scope): ...@@ -2853,13 +2858,6 @@ class CppClassScope(Scope):
if self.type.is_cyp_class and not self.lookup_here("__new__"): if self.type.is_cyp_class and not self.lookup_here("__new__"):
# In cypclasses, inherited methods are all hidden as soon as a
# method with the same name is declared in the subclass
if not inheriting:
prev_constructor = self.lookup_here("<constructor>")
if prev_constructor and prev_constructor.is_inherited:
del self.entries["<constructor>"]
self.declare_constructor_wrapper(type.args, pos, defining, self.declare_constructor_wrapper(type.args, pos, defining,
type.has_varargs, type.optional_arg_count, type.has_varargs, type.optional_arg_count,
getattr(type, 'op_arg_struct', None)) getattr(type, 'op_arg_struct', None))
...@@ -2910,13 +2908,6 @@ class CppClassScope(Scope): ...@@ -2910,13 +2908,6 @@ class CppClassScope(Scope):
error(pos, "Constructor cannot be called without GIL unless all base constructors can also be called without GIL") error(pos, "Constructor cannot be called without GIL unless all base constructors can also be called without GIL")
error(base_entry.pos, "Base constructor defined here.") error(base_entry.pos, "Base constructor defined here.")
# In cypclasses, inherited methods are all hidden as soon as a
# method with the same name is declared in the subclass
if self.type.is_cyp_class and not inheriting:
prev_entry = self.lookup_here(name)
if prev_entry and prev_entry.is_inherited:
del self.entries[name]
entry = self.declare_var(name, type, pos, entry = self.declare_var(name, type, pos,
defining=defining, defining=defining,
cname=cname, visibility=visibility) cname=cname, visibility=visibility)
...@@ -2987,9 +2978,9 @@ class CppClassScope(Scope): ...@@ -2987,9 +2978,9 @@ class CppClassScope(Scope):
for base_entry in base_scope.var_entries: for base_entry in base_scope.var_entries:
base_entry_type = base_entry.type base_entry_type = base_entry.type
#constructor/destructor is not inherited #constructor/destructor is not inherited
if base_entry.name == "<del>"\ if base_entry.name == "<del>" or base_entry.name in ("<constructor>", "<alloc>", "<active_self>", "__activate__"):
or base_entry.name in ("<constructor>", "<alloc>", "<active_self>", "__activate__"):
continue continue
elif base_entry.name == "<init>" and not self.lookup_here("__new__"): elif base_entry.name == "<init>" and not self.lookup_here("__new__"):
wrapper_entry = self.declare_constructor_wrapper(base_entry_type.args, base_entry.pos, wrapper_entry = self.declare_constructor_wrapper(base_entry_type.args, base_entry.pos,
defining=1, has_varargs = base_entry_type.has_varargs, defining=1, has_varargs = base_entry_type.has_varargs,
...@@ -3022,7 +3013,7 @@ class CppClassScope(Scope): ...@@ -3022,7 +3013,7 @@ class CppClassScope(Scope):
return_type=base_entry_type.return_type) return_type=base_entry_type.return_type)
wrapper_entry.is_inherited = 1 wrapper_entry.is_inherited = 1
entry = self.declare(base_entry.name, base_entry.cname, base_entry_type, base_entry.pos, 'extern') entry = self.declare(base_entry.name, base_entry.cname, base_entry_type, base_entry.pos, 'extern', from_type = base_class)
entry.is_variable = 1 entry.is_variable = 1
entry.is_inherited = 1 entry.is_inherited = 1
entry.is_cfunction = base_entry.is_cfunction entry.is_cfunction = base_entry.is_cfunction
......
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