diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index 8e7aa5c7..0a661c82 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -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 (typeInst->mTypeDef->mIsCombinedPartial) { + typeInst->mTypeDef->PopulateMemberSets(); + bool hasUnimpChainMembers = false; impChainHeadMethods.Clear(); @@ -5342,6 +5344,35 @@ void BfCompiler::PopulateReified() if (!methodInstance->IsReifiedAndImplemented()) 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())) diff --git a/IDEHelper/Compiler/BfMangler.cpp b/IDEHelper/Compiler/BfMangler.cpp index c61f95e4..a092e329 100644 --- a/IDEHelper/Compiler/BfMangler.cpp +++ b/IDEHelper/Compiler/BfMangler.cpp @@ -2018,9 +2018,10 @@ void BfMSMangler::Mangle(StringImpl& name, bool is64Bit, BfMethodInstance* metho else AddStr(mangleContext, name, methodDef->mName); } - + 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; BF_ASSERT(methodInst->GetOwner()->mTypeDef->mIsCombinedPartial); @@ -2098,7 +2099,10 @@ void BfMSMangler::Mangle(StringImpl& name, bool is64Bit, BfMethodInstance* metho if ((methodDef->mIsStatic) || (doExplicitThis)) attrib += 2; - attrib += (methodDef->mIsVirtual ? 4 : 0); + + if ((methodDef->mIsVirtual) && (!methodDef->mIsOverride)) + attrib += 4; + name += attrib; auto bfSystem = methodInst->GetOwner()->mModule->mSystem; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index ea55514c..d63b7412 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -21517,12 +21517,6 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool 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 { if (!typeInstance->IsTypeMemberAccessible(checkMethod->mDeclaringType, methodDef->mDeclaringType)) @@ -21539,7 +21533,13 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool } 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())) { foundHiddenMethod = true; @@ -21764,10 +21764,13 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo auto propertyDeclaration = methodDef->GetPropertyDeclaration(); auto propertyMethodDeclaration = methodDef->GetPropertyMethodDeclaration(); + if (methodInstance->mIsInnerOverride) + return false; + BfAstNode* declaringNode = methodDeclaration; if (propertyMethodDeclaration != NULL) declaringNode = propertyMethodDeclaration->mNameNode; - + BfMethodInstance* methodOverriden = NULL; bool usedMethod = false; @@ -22128,30 +22131,11 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo } } + + if (methodOverriden != NULL) { - 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); - } + CheckOverridenMethod(methodInstance, methodOverriden); } } } @@ -22369,6 +22353,33 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo 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) { auto typeInstance = mCurTypeInstance; diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index eb5fdc01..43baa50a 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1851,6 +1851,7 @@ public: void UniqueSlotVirtualMethod(BfMethodInstance* methodInstance); void CompareDeclTypes(BfTypeDef* newDeclType, BfTypeDef* prevDeclType, bool& isBetter, bool& isWorse); bool SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityContext* ambiguityContext = NULL); + void CheckOverridenMethod(BfMethodInstance* methodInstance, BfMethodInstance* methodOverriden); bool SlotInterfaceMethod(BfMethodInstance* methodInstance); void SetMethodDependency(BfMethodInstance* methodInstance); BfModuleMethodInstance ReferenceExternalMethodInstance(BfMethodInstance* methodInstance, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index a974344e..08ef1f8c 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -787,6 +787,11 @@ bool BfMethodInstance::HasThis() return (!mMethodInstanceGroup->mOwner->IsValuelessType()); } +bool BfMethodInstance::IsVirtual() +{ + return mMethodDef->mIsVirtual && !mIsInnerOverride; +} + BfType* BfMethodInstance::GetThisType() { BF_ASSERT(!mMethodDef->mIsStatic); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 5ddf3160..4e1f6ddb 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -816,6 +816,7 @@ public: bool mIsIntrinsic:1; bool mHasMethodRefType:1; bool mDisallowCalling:1; + bool mIsInnerOverride:1; BfMethodChainType mChainType; BfCallingConvention mCallingConvention; BfMethodInstanceGroup* mMethodInstanceGroup; @@ -850,7 +851,8 @@ public: mAlwaysInline = false; mIsIntrinsic = false; mHasMethodRefType = false; - mDisallowCalling = false; + mDisallowCalling = false; + mIsInnerOverride = false; mChainType = BfMethodChainType_None; mCallingConvention = BfCallingConvention_Unspecified; mMethodInstanceGroup = NULL; @@ -882,6 +884,7 @@ public: bool IsOrInUnspecializedVariation(); bool HasExternConstraints(); bool HasThis(); + bool IsVirtual(); BfType* GetThisType(); int GetThisIdx(); bool HasExplicitThis(); diff --git a/IDEHelper/Tests/LibA/src/LibA0.bf b/IDEHelper/Tests/LibA/src/LibA0.bf index 1b8704b9..af90c78b 100644 --- a/IDEHelper/Tests/LibA/src/LibA0.bf +++ b/IDEHelper/Tests/LibA/src/LibA0.bf @@ -133,9 +133,13 @@ class LibClassA return 30; } + public extern int GetVal4(); + public static LibClassA Create() { - return new LibClassA(); + LibClassA ca = new LibClassA(); + Test.Assert(ca.GetVal4() == 29); + return ca; } } diff --git a/IDEHelper/Tests/LibB/src/LibB0.bf b/IDEHelper/Tests/LibB/src/LibB0.bf index 402b71c8..3542fd9b 100644 --- a/IDEHelper/Tests/LibB/src/LibB0.bf +++ b/IDEHelper/Tests/LibB/src/LibB0.bf @@ -42,6 +42,11 @@ extension LibClassA { return mB; } + + public override int GetVal4() + { + return 29; + } } static