Skip to content

Commit

Permalink
- allow skipping optional arguments of the parent function in a virtu…
Browse files Browse the repository at this point in the history
…al override definition.

This is mainly to allow retroactive addition to existing virtual functions without breaking existing content.
The MeansOfDeath fix for Actor.Die would not be possible without such handling.
  • Loading branch information
coelckers committed Jul 29, 2018
1 parent ff69d94 commit 6634416
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 7 deletions.
27 changes: 24 additions & 3 deletions src/dobjtype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/dobjtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class PClass
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);

Expand Down
7 changes: 4 additions & 3 deletions src/scripting/zscript/zcc_compile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<PFunction>(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)
{
Expand All @@ -2705,7 +2707,6 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
else
{
auto oldfunc = clstype->Virtuals[vindex];
auto parentfunc = dyn_cast<PFunction>(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);
Expand Down Expand Up @@ -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());
Expand Down

0 comments on commit 6634416

Please sign in to comment.