1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 19:48:20 +02:00

Added extern method override support in extensions

This commit is contained in:
Brian Fiete 2020-10-23 11:48:37 -07:00
parent 1e020dc14e
commit 101fde1a4b
8 changed files with 99 additions and 35 deletions

View file

@ -5319,6 +5319,8 @@ void BfCompiler::PopulateReified()
// If we have chained methods, make sure we implement the chain members if the chain head is implemented and reified // If we have chained methods, make sure we implement the chain members if the chain head is implemented and reified
if (typeInst->mTypeDef->mIsCombinedPartial) if (typeInst->mTypeDef->mIsCombinedPartial)
{ {
typeInst->mTypeDef->PopulateMemberSets();
bool hasUnimpChainMembers = false; bool hasUnimpChainMembers = false;
impChainHeadMethods.Clear(); impChainHeadMethods.Clear();
@ -5342,6 +5344,35 @@ void BfCompiler::PopulateReified()
if (!methodInstance->IsReifiedAndImplemented()) if (!methodInstance->IsReifiedAndImplemented())
hasUnimpChainMembers = true; hasUnimpChainMembers = true;
} }
else if (methodInstance->mIsInnerOverride)
{
if (!methodInstance->IsReifiedAndImplemented())
{
bool forceMethod = false;
BfMemberSetEntry* memberSetEntry;
if (typeInst->mTypeDef->mMethodSet.TryGetWith((StringImpl&)methodInstance->mMethodDef->mName, &memberSetEntry))
{
BfMethodDef* checkMethodDef = (BfMethodDef*)memberSetEntry->mMemberDef;
while (checkMethodDef != NULL)
{
auto& checkMethodInstanceGroup = typeInst->mMethodInstanceGroups[checkMethodDef->mIdx];
auto checkMethodInstance = checkMethodInstanceGroup.mDefault;
if (checkMethodInstance == NULL)
continue;
if ((checkMethodDef->mIsExtern) && (checkMethodInstance->IsReifiedAndImplemented()))
forceMethod = true;
checkMethodDef = checkMethodDef->mNextWithSameName;
}
}
if (forceMethod)
{
typeInst->mModule->GetMethodInstance(methodInstance->GetOwner(), methodInstance->mMethodDef, BfTypeVector(),
(BfGetMethodInstanceFlags)(BfGetMethodInstanceFlag_UnspecializedPass));
}
}
}
} }
if ((hasUnimpChainMembers) && (!impChainHeadMethods.IsEmpty())) if ((hasUnimpChainMembers) && (!impChainHeadMethods.IsEmpty()))

View file

@ -2020,7 +2020,8 @@ void BfMSMangler::Mangle(StringImpl& name, bool is64Bit, BfMethodInstance* metho
} }
if ((methodInst->mMethodDef->mDeclaringType->mPartialIdx != -1) && (methodInst->mMethodDef->mDeclaringType->IsExtension()) && if ((methodInst->mMethodDef->mDeclaringType->mPartialIdx != -1) && (methodInst->mMethodDef->mDeclaringType->IsExtension()) &&
(!methodInst->mIsForeignMethodDef) && (!methodInst->mMethodDef->mIsExtern)) (!methodInst->mIsForeignMethodDef) && (!methodInst->mMethodDef->mIsExtern) &&
((!methodInst->mMethodDef->mIsOverride) || (methodDef->mName == BF_METHODNAME_MARKMEMBERS) || (methodDef->mMethodType == BfMethodType_Dtor)))
{ {
auto declType = methodInst->mMethodDef->mDeclaringType; auto declType = methodInst->mMethodDef->mDeclaringType;
BF_ASSERT(methodInst->GetOwner()->mTypeDef->mIsCombinedPartial); BF_ASSERT(methodInst->GetOwner()->mTypeDef->mIsCombinedPartial);
@ -2098,7 +2099,10 @@ void BfMSMangler::Mangle(StringImpl& name, bool is64Bit, BfMethodInstance* metho
if ((methodDef->mIsStatic) || (doExplicitThis)) if ((methodDef->mIsStatic) || (doExplicitThis))
attrib += 2; attrib += 2;
attrib += (methodDef->mIsVirtual ? 4 : 0);
if ((methodDef->mIsVirtual) && (!methodDef->mIsOverride))
attrib += 4;
name += attrib; name += attrib;
auto bfSystem = methodInst->GetOwner()->mModule->mSystem; auto bfSystem = methodInst->GetOwner()->mModule->mSystem;

View file

@ -21517,12 +21517,6 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
methodInstance->mChainType = BfMethodChainType_ChainMember; methodInstance->mChainType = BfMethodChainType_ChainMember;
} }
} }
else if ((checkMethod->mBody == NULL) && (methodDef->mBody != NULL) &&
(checkMethod->mDeclaringType != methodDef->mDeclaringType))
{
// We're allowed to override an empty-bodied method
checkMethodInstance->mChainType = BfMethodChainType_ChainSkip;
}
else else
{ {
if (!typeInstance->IsTypeMemberAccessible(checkMethod->mDeclaringType, methodDef->mDeclaringType)) if (!typeInstance->IsTypeMemberAccessible(checkMethod->mDeclaringType, methodDef->mDeclaringType))
@ -21539,7 +21533,13 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
} }
else else
{ {
if ((methodDef->mDeclaringType->mProject != checkMethod->mDeclaringType->mProject) && if ((methodDef->mIsOverride) && (checkMethod->mIsExtern))
{
silentlyAllow = true;
methodInstance->mIsInnerOverride = true;
CheckOverridenMethod(methodInstance, checkMethodInstance);
}
else if ((methodDef->mDeclaringType->mProject != checkMethod->mDeclaringType->mProject) &&
(!checkMethod->mDeclaringType->IsExtension())) (!checkMethod->mDeclaringType->IsExtension()))
{ {
foundHiddenMethod = true; foundHiddenMethod = true;
@ -21764,6 +21764,9 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo
auto propertyDeclaration = methodDef->GetPropertyDeclaration(); auto propertyDeclaration = methodDef->GetPropertyDeclaration();
auto propertyMethodDeclaration = methodDef->GetPropertyMethodDeclaration(); auto propertyMethodDeclaration = methodDef->GetPropertyMethodDeclaration();
if (methodInstance->mIsInnerOverride)
return false;
BfAstNode* declaringNode = methodDeclaration; BfAstNode* declaringNode = methodDeclaration;
if (propertyMethodDeclaration != NULL) if (propertyMethodDeclaration != NULL)
declaringNode = propertyMethodDeclaration->mNameNode; declaringNode = propertyMethodDeclaration->mNameNode;
@ -22128,30 +22131,11 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo
} }
} }
if (methodOverriden != NULL) if (methodOverriden != NULL)
{ {
auto prevProtection = methodOverriden->mMethodDef->mProtection; CheckOverridenMethod(methodInstance, methodOverriden);
if ((methodDef->mProtection != prevProtection) && (methodDef->mMethodType != BfMethodType_Dtor))
{
const char* protectionNames[] = {"hidden", "private", "internal", "protected", "public"};
BfAstNode* protectionRefNode = NULL;
if (auto propertyMethodDeclaration = methodDef->GetPropertyMethodDeclaration())
{
protectionRefNode = propertyMethodDeclaration->mProtectionSpecifier;
if (protectionRefNode == NULL)
protectionRefNode = propertyMethodDeclaration->mPropertyDeclaration->mProtectionSpecifier;
if (protectionRefNode == NULL)
protectionRefNode = propertyMethodDeclaration->mPropertyDeclaration->mNameNode;
}
else if (auto methodDeclaration = methodDef->GetMethodDeclaration())
{
protectionRefNode = methodDeclaration->mProtectionSpecifier;
if (protectionRefNode == NULL)
protectionRefNode = methodDeclaration->mNameNode;
}
if (protectionRefNode != NULL)
Fail(StrFormat("Cannot change access modifiers when overriding '%s' inherited member", protectionNames[(int)prevProtection]), protectionRefNode, true);
}
} }
} }
} }
@ -22369,6 +22353,33 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo
return usedMethod; return usedMethod;
} }
void BfModule::CheckOverridenMethod(BfMethodInstance* methodInstance, BfMethodInstance* methodOverriden)
{
auto methodDef = methodInstance->mMethodDef;
auto prevProtection = methodOverriden->mMethodDef->mProtection;
if ((methodDef->mProtection != prevProtection) && (methodDef->mMethodType != BfMethodType_Dtor))
{
const char* protectionNames[] = { "hidden", "private", "internal", "protected", "public" };
BfAstNode* protectionRefNode = NULL;
if (auto propertyMethodDeclaration = methodDef->GetPropertyMethodDeclaration())
{
protectionRefNode = propertyMethodDeclaration->mProtectionSpecifier;
if (protectionRefNode == NULL)
protectionRefNode = propertyMethodDeclaration->mPropertyDeclaration->mProtectionSpecifier;
if (protectionRefNode == NULL)
protectionRefNode = propertyMethodDeclaration->mPropertyDeclaration->mNameNode;
}
else if (auto methodDeclaration = methodDef->GetMethodDeclaration())
{
protectionRefNode = methodDeclaration->mProtectionSpecifier;
if (protectionRefNode == NULL)
protectionRefNode = methodDeclaration->mNameNode;
}
if (protectionRefNode != NULL)
Fail(StrFormat("Cannot change access modifiers when overriding '%s' inherited member", protectionNames[(int)prevProtection]), protectionRefNode, true);
}
}
bool BfModule::SlotInterfaceMethod(BfMethodInstance* methodInstance) bool BfModule::SlotInterfaceMethod(BfMethodInstance* methodInstance)
{ {
auto typeInstance = mCurTypeInstance; auto typeInstance = mCurTypeInstance;

View file

@ -1851,6 +1851,7 @@ public:
void UniqueSlotVirtualMethod(BfMethodInstance* methodInstance); void UniqueSlotVirtualMethod(BfMethodInstance* methodInstance);
void CompareDeclTypes(BfTypeDef* newDeclType, BfTypeDef* prevDeclType, bool& isBetter, bool& isWorse); void CompareDeclTypes(BfTypeDef* newDeclType, BfTypeDef* prevDeclType, bool& isBetter, bool& isWorse);
bool SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityContext* ambiguityContext = NULL); bool SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityContext* ambiguityContext = NULL);
void CheckOverridenMethod(BfMethodInstance* methodInstance, BfMethodInstance* methodOverriden);
bool SlotInterfaceMethod(BfMethodInstance* methodInstance); bool SlotInterfaceMethod(BfMethodInstance* methodInstance);
void SetMethodDependency(BfMethodInstance* methodInstance); void SetMethodDependency(BfMethodInstance* methodInstance);
BfModuleMethodInstance ReferenceExternalMethodInstance(BfMethodInstance* methodInstance, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None); BfModuleMethodInstance ReferenceExternalMethodInstance(BfMethodInstance* methodInstance, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None);

View file

@ -787,6 +787,11 @@ bool BfMethodInstance::HasThis()
return (!mMethodInstanceGroup->mOwner->IsValuelessType()); return (!mMethodInstanceGroup->mOwner->IsValuelessType());
} }
bool BfMethodInstance::IsVirtual()
{
return mMethodDef->mIsVirtual && !mIsInnerOverride;
}
BfType* BfMethodInstance::GetThisType() BfType* BfMethodInstance::GetThisType()
{ {
BF_ASSERT(!mMethodDef->mIsStatic); BF_ASSERT(!mMethodDef->mIsStatic);

View file

@ -816,6 +816,7 @@ public:
bool mIsIntrinsic:1; bool mIsIntrinsic:1;
bool mHasMethodRefType:1; bool mHasMethodRefType:1;
bool mDisallowCalling:1; bool mDisallowCalling:1;
bool mIsInnerOverride:1;
BfMethodChainType mChainType; BfMethodChainType mChainType;
BfCallingConvention mCallingConvention; BfCallingConvention mCallingConvention;
BfMethodInstanceGroup* mMethodInstanceGroup; BfMethodInstanceGroup* mMethodInstanceGroup;
@ -851,6 +852,7 @@ public:
mIsIntrinsic = false; mIsIntrinsic = false;
mHasMethodRefType = false; mHasMethodRefType = false;
mDisallowCalling = false; mDisallowCalling = false;
mIsInnerOverride = false;
mChainType = BfMethodChainType_None; mChainType = BfMethodChainType_None;
mCallingConvention = BfCallingConvention_Unspecified; mCallingConvention = BfCallingConvention_Unspecified;
mMethodInstanceGroup = NULL; mMethodInstanceGroup = NULL;
@ -882,6 +884,7 @@ public:
bool IsOrInUnspecializedVariation(); bool IsOrInUnspecializedVariation();
bool HasExternConstraints(); bool HasExternConstraints();
bool HasThis(); bool HasThis();
bool IsVirtual();
BfType* GetThisType(); BfType* GetThisType();
int GetThisIdx(); int GetThisIdx();
bool HasExplicitThis(); bool HasExplicitThis();

View file

@ -133,9 +133,13 @@ class LibClassA
return 30; return 30;
} }
public extern int GetVal4();
public static LibClassA Create() public static LibClassA Create()
{ {
return new LibClassA(); LibClassA ca = new LibClassA();
Test.Assert(ca.GetVal4() == 29);
return ca;
} }
} }

View file

@ -42,6 +42,11 @@ extension LibClassA
{ {
return mB; return mB;
} }
public override int GetVal4()
{
return 29;
}
} }
static static