From 020cec980e56a3048e16844d4751ad0b4418b164 Mon Sep 17 00:00:00 2001 From: Xavier Thompson <xavier.thompson@nexedi.com> Date: Tue, 28 Jul 2020 17:42:13 +0200 Subject: [PATCH] Disallow cypclass method overloading with narrower or larger arguments --- Cython/Compiler/PyrexTypes.py | 26 ++++++++++++++++++++++++++ Cython/Compiler/Symtab.py | 7 ++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index c32d8a229..a7961a751 100644 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -3044,6 +3044,32 @@ class CFuncType(CType): return 0 return 1 + def narrower_or_larger_arguments_than(self, other_type, as_cmethod = 0): + return self.narrower_or_larger_arguments_than_resolved_type(other_type.resolve(), as_cmethod) + + def narrower_or_larger_arguments_than_resolved_type(self, other_type, as_cmethod): + if other_type is error_type: + return 1 + if not other_type.is_cfunction: + return 0 + nargs = len(self.args) + if nargs != len(other_type.args): + return 0 + for i in range(as_cmethod, nargs): + if not self.args[i].type.subtype_of_resolved_type(other_type.args[i].type): + if not other_type.args[i].type.subtype_of_resolved_type(self.args[i].type): + return 0 + else: + other_type.args[i].needs_type_test = True + else: + self.args[i].needs_type_test = other_type.args[i].needs_type_test \ + or not self.args[i].type.same_as(other_type.args[i].type) + if self.has_varargs != other_type.has_varargs: + return 0 + if self.optional_arg_count != other_type.optional_arg_count: + return 0 + return 1 + def narrower_arguments_than(self, other_type, as_cmethod = 0): return self.narrower_arguments_than_resolved_type(other_type.resolve(), as_cmethod) diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index 2497510f4..a6cf943a6 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -571,7 +571,7 @@ class Scope(object): alt_declarator_str = alt_type.declarator_code(name, for_display = 1).strip() new_declarator_str = type.declarator_code(name, for_display = 1).strip() if new_declarator_str != alt_declarator_str: - error(pos, ("Fallacious override:\n" + error(pos, ("False override:\n" "Cypclass method\n" ">> %s\n" "has compatible arguments with inherited method\n" @@ -598,8 +598,9 @@ class Scope(object): # if an overloaded alternative has narrower argument types than another, then the method # actually called will depend on the static type of the arguments - elif type.narrower_arguments_than(alt_type) or alt_type.narrower_arguments_than(type): - error(pos, "Cypclass overloaded method with narrower arguments") + # we actually also disallow methods where each argument is either narrower or larger + elif type.narrower_or_larger_arguments_than(alt_type): + error(pos, "Cypclass overloaded method with narrower or larger arguments") if alt_entry.pos is not None: error(alt_entry.pos, "Conflicting method is defined here") -- 2.30.9