diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index b27546e33..e3dfd232a 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -776,16 +776,18 @@ PClass *PClass::FindClassTentative(FName name) // //========================================================================== -int PClass::FindVirtualIndex(FName name, PPrototype *proto) +int PClass::FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction *parentfunc) { + auto proto = variant->Proto; for (unsigned i = 0; i < Virtuals.Size(); i++) { if (Virtuals[i]->Name == name) { auto vproto = Virtuals[i]->Proto; if (vproto->ReturnTypes.Size() != proto->ReturnTypes.Size() || - vproto->ArgumentTypes.Size() != proto->ArgumentTypes.Size()) + vproto->ArgumentTypes.Size() < proto->ArgumentTypes.Size()) { + continue; // number of parameters does not match, so it's incompatible } bool fail = false; @@ -808,7 +810,26 @@ int PClass::FindVirtualIndex(FName name, PPrototype *proto) break; } } - if (!fail) return i; + if (!fail) + { + if (vproto->ArgumentTypes.Size() > proto->ArgumentTypes.Size() && parentfunc) + { + // Check if the difference between both functions is only some optional arguments. + for (unsigned a = proto->ArgumentTypes.Size(); a < vproto->ArgumentTypes.Size(); a++) + { + if (!(parentfunc->Variants[0].ArgFlags[a] & VARF_Optional)) return -1; + } + + // Todo: extend the prototype + for (unsigned a = proto->ArgumentTypes.Size(); a < vproto->ArgumentTypes.Size(); a++) + { + proto->ArgumentTypes.Push(vproto->ArgumentTypes[a]); + variant->ArgFlags.Push(parentfunc->Variants[0].ArgFlags[a]); + variant->ArgNames.Push(NAME_None); + } + } + return i; + } } } return -1; diff --git a/src/dobjtype.h b/src/dobjtype.h index 12a6ae287..212174005 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -42,7 +42,7 @@ public: void WriteAllFields(FSerializer &ar, const void *addr) const; bool ReadAllFields(FSerializer &ar, void *addr) const; void InitializeDefaults(); - int FindVirtualIndex(FName name, PPrototype *proto); + int FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction *parentfunc); PSymbol *FindSymbol(FName symname, bool searchparents) const; PField *AddField(FName name, PType *type, uint32_t flags); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index cc8424b50..0a06f7b7c 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2694,7 +2694,9 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool if (forclass) { - int vindex = clstype->FindVirtualIndex(sym->SymbolName, sym->Variants[0].Proto); + auto parentfunc = clstype->ParentClass? dyn_cast(clstype->ParentClass->VMType->Symbols.FindSymbol(sym->SymbolName, true)) : nullptr; + + int vindex = clstype->FindVirtualIndex(sym->SymbolName, &sym->Variants[0], parentfunc); // specifying 'override' is necessary to prevent one of the biggest problem spots with virtual inheritance: Mismatching argument types. if (varflags & VARF_Override) { @@ -2705,7 +2707,6 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool else { auto oldfunc = clstype->Virtuals[vindex]; - auto parentfunc = dyn_cast(clstype->ParentClass->VMType->Symbols.FindSymbol(sym->SymbolName, true)); if (parentfunc && parentfunc->mVersion > mVersion) { Error(f, "Attempt to override function %s which is incompatible with version %d.%d.%d", FName(f->Name).GetChars(), mVersion.major, mVersion.minor, mVersion.revision); @@ -2765,7 +2766,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool } else if (forclass) { - int vindex = clstype->FindVirtualIndex(sym->SymbolName, sym->Variants[0].Proto); + int vindex = clstype->FindVirtualIndex(sym->SymbolName, &sym->Variants[0], nullptr); if (vindex != -1) { Error(f, "Function %s attempts to override parent function without 'override' qualifier", FName(f->Name).GetChars());