From 75dd1a42138aa7abfe33f6e030b8238c3706beab Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 1 Jul 2020 12:06:28 -0700 Subject: [PATCH] Added 'visibleProjectSet', changed visibility rules for generics --- IDEHelper/Compiler/BfExprEvaluator.cpp | 53 +++++++++++--------- IDEHelper/Compiler/BfModule.cpp | 56 ++++++++++++++++++++++ IDEHelper/Compiler/BfModule.h | 4 +- IDEHelper/Compiler/BfResolvedTypeUtils.cpp | 7 +++ IDEHelper/Compiler/BfResolvedTypeUtils.h | 4 +- IDEHelper/Compiler/BfSystem.h | 1 + 6 files changed, 100 insertions(+), 25 deletions(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index c2f98575..9ea3227b 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -612,11 +612,6 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp bool prevChainSkip = (prevMethodInstance->mChainType == BfMethodChainType_ChainMember) || (prevMethodInstance->mChainType == BfMethodChainType_ChainSkip); RETURN_BETTER_OR_WORSE(!chainSkip, !prevChainSkip); - // If one of these methods is local to the current extension then choose that one - auto activeDef = mModule->GetActiveTypeDef(); - RETURN_BETTER_OR_WORSE(newMethodDef->mDeclaringType == activeDef, prevMethodDef->mDeclaringType == activeDef); - RETURN_BETTER_OR_WORSE(newMethodDef->mDeclaringType->IsExtension(), prevMethodDef->mDeclaringType->IsExtension()); - if ((!isBetter) && (!isWorse)) { bool betterByGenericParam = false; @@ -948,6 +943,11 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp RETURN_BETTER_OR_WORSE(newMethodDef->mCheckedKind == mCheckedKind, prevMethodDef->mCheckedKind == mCheckedKind); RETURN_BETTER_OR_WORSE(newMethodDef->mCommutableKind != BfCommutableKind_Reverse, prevMethodDef->mCommutableKind != BfCommutableKind_Reverse); + // If one of these methods is local to the current extension then choose that one + auto activeDef = mModule->GetActiveTypeDef(); + RETURN_BETTER_OR_WORSE(newMethodDef->mDeclaringType == activeDef, prevMethodDef->mDeclaringType == activeDef); + RETURN_BETTER_OR_WORSE(newMethodDef->mDeclaringType->IsExtension(), prevMethodDef->mDeclaringType->IsExtension()); + RETURN_RESULTS; } @@ -1877,7 +1877,12 @@ bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue targe auto curTypeDef = typeInstance->mTypeDef; int checkInterfaceIdx = 0; - + + if (mMethodName == "Handle") + { + NOP; + } + bool targetIsBase = target.IsBase(); bool checkExtensionBase = false; if (targetIsBase) @@ -1915,6 +1920,7 @@ bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue targe { bool allowExplicitInterface = curTypeInst->IsInterface() && mBypassVirtual; auto activeTypeDef = mModule->GetActiveTypeDef(); + auto visibleProjectSet = mModule->GetVisibleProjectSet(); bool isDelegate = typeInstance->IsDelegate(); auto checkMethod = nextMethodDef; @@ -1970,7 +1976,7 @@ bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue targe if (!isDelegate) { if ((!curTypeInst->IsTypeMemberIncluded(checkMethod->mDeclaringType, activeTypeDef, mModule)) || - (!curTypeInst->IsTypeMemberAccessible(checkMethod->mDeclaringType, activeTypeDef))) + (!curTypeInst->IsTypeMemberAccessible(checkMethod->mDeclaringType, visibleProjectSet))) continue; } @@ -5353,9 +5359,11 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu if (!target) { FinishDeferredEvals(argValues); - mModule->Fail(StrFormat("An instance reference is required to %s the non-static method '%s'", + auto error = mModule->Fail(StrFormat("An instance reference is required to %s the non-static method '%s'", (prevBindResult.mPrevVal != NULL) ? "bind" : "invoke", mModule->MethodToString(methodInstance).c_str()), targetSrc); + if ((error != NULL) && (methodInstance->mMethodDef->GetRefNode() != NULL)) + mModule->mCompiler->mPassInstance->MoreInfo(StrFormat("See method declaration"), methodInstance->mMethodDef->GetRefNode()); return mModule->GetDefaultTypedValue(returnType); } @@ -6023,6 +6031,7 @@ BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBou BfProtectionCheckFlags protectionCheckFlags = BfProtectionCheckFlag_None; auto activeTypeDef = mModule->GetActiveTypeDef(); + auto visibleProjectSet = mModule->GetVisibleProjectSet(); bool isFailurePass = false; for (int pass = 0; pass < 2; pass++) { @@ -6047,7 +6056,7 @@ BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBou if (!mModule->IsInSpecializedSection()) { if ((!curTypeInst->IsTypeMemberIncluded(checkMethod->mDeclaringType, activeTypeDef, mModule)) || - (!curTypeInst->IsTypeMemberAccessible(checkMethod->mDeclaringType, activeTypeDef))) + (!curTypeInst->IsTypeMemberAccessible(checkMethod->mDeclaringType, visibleProjectSet))) continue; } @@ -7233,7 +7242,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp } } - // Look in globals. Always check for extension methods. + // Look in globals. Always check for extension methods. if ((methodDef == NULL) || (wantsExtensionCheck)) { if (mModule->mContext->mCurTypeState != NULL) @@ -7251,10 +7260,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp { isFailurePass = false; curTypeInst = methodMatcher.mBestMethodTypeInstance; - methodDef = methodMatcher.mBestMethodDef; - // Extension check must check all possible extensions, no early bailout - if (!wantsExtensionCheck) - break; + methodDef = methodMatcher.mBestMethodDef; } } } @@ -7273,10 +7279,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp { isFailurePass = false; curTypeInst = methodMatcher.mBestMethodTypeInstance; - methodDef = methodMatcher.mBestMethodDef; - // Extension check must check all possible extensions, no early bailout - if (!wantsExtensionCheck) - break; + methodDef = methodMatcher.mBestMethodDef; } } } @@ -13001,7 +13004,7 @@ void BfExprEvaluator::CheckLocalMethods(BfAstNode* targetSrc, BfTypeInstance* ty { ctxClosureInstanceInfo = mModule->mCurMethodState->mClosureState->mClosureInstanceInfo; ctxMethodState = mModule->mCurMethodState; - } + } bool atCtxMethodState = false; auto checkMethodState = mModule->mCurMethodState; @@ -13324,16 +13327,20 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo if (!target) { - mModule->Fail(StrFormat("An instance reference is required to invoke the non-static mixin '%s'", + BfError* error = mModule->Fail(StrFormat("An instance reference is required to invoke the non-static mixin '%s'", mModule->MethodToString(methodInstance).c_str()), targetSrc); + if ((error != NULL) && (methodInstance->mMethodDef->GetRefNode() != NULL)) + mModule->mCompiler->mPassInstance->MoreInfo(StrFormat("See method declaration"), methodInstance->mMethodDef->GetRefNode()); } } else { if (target) { - mModule->Fail(StrFormat("Mixin '%s' cannot be accessed with an instance reference; qualify it with a type name instead", + BfError* error = mModule->Fail(StrFormat("Mixin '%s' cannot be accessed with an instance reference; qualify it with a type name instead", mModule->MethodToString(methodInstance).c_str()), targetSrc); + if ((error != NULL) && (methodInstance->mMethodDef->GetRefNode() != NULL)) + mModule->mCompiler->mPassInstance->MoreInfo(StrFormat("See method declaration"), methodInstance->mMethodDef->GetRefNode()); } } @@ -13354,14 +13361,14 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo if ((int)args.size() < explicitParamCount) { BfError* error = mModule->Fail(StrFormat("Not enough arguments specified, expected %d more.", explicitParamCount - (int)arguments.size()), targetSrc); - if ((error != NULL) && (methodInstance->mMethodDef->mMethodDeclaration != NULL)) + if ((error != NULL) && (methodInstance->mMethodDef->GetRefNode() != NULL)) mModule->mCompiler->mPassInstance->MoreInfo(StrFormat("See method declaration"), methodInstance->mMethodDef->GetRefNode()); return; } else if ((int)args.size() > explicitParamCount) { BfError* error = mModule->Fail(StrFormat("Too many arguments specified, expected %d fewer.", (int)arguments.size() - explicitParamCount), targetSrc); - if ((error != NULL) && (methodInstance->mMethodDef->mMethodDeclaration != NULL)) + if ((error != NULL) && (methodInstance->mMethodDef->GetRefNode() != NULL)) mModule->mCompiler->mPassInstance->MoreInfo(StrFormat("See method declaration"), methodInstance->mMethodDef->GetRefNode()); return; } diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index b6f3887e..56727f49 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -2204,6 +2204,62 @@ void BfModule::ValueScopeEnd(BfIRValue valueScopeStart) mBfIRBuilder->CreateValueScopeHardEnd(valueScopeStart); } +BfProjectSet* BfModule::GetVisibleProjectSet() +{ + if (mCurMethodState == NULL) + return NULL; + + if (mCurMethodState->mVisibleProjectSet.IsEmpty()) + { + HashSet seenTypes; + + std::function _AddProject = [&](BfProject* project) + { + if (mCurMethodState->mVisibleProjectSet.Add(project)) + { + for (auto dep : project->mDependencies) + _AddProject(dep); + } + }; + + std::function _AddType = [&](BfType* type) + { + auto typeInstance = type->ToTypeInstance(); + if (typeInstance == NULL) + return; + _AddProject(typeInstance->mTypeDef->mProject); + if (typeInstance->mGenericTypeInfo == NULL) + return; + for (auto type : typeInstance->mGenericTypeInfo->mTypeGenericArguments) + { + if (seenTypes.Add(type)) + _AddType(type); + } + }; + + if (mCurTypeInstance != NULL) + _AddType(mCurTypeInstance); + + auto methodState = mCurMethodState; + while (methodState != NULL) + { + if (methodState->mMethodInstance != NULL) + { + _AddProject(methodState->mMethodInstance->mMethodDef->mDeclaringType->mProject); + if (methodState->mMethodInstance->mMethodInfoEx != NULL) + { + for (auto type : methodState->mMethodInstance->mMethodInfoEx->mMethodGenericArguments) + _AddType(type); + } + } + + methodState = methodState->mPrevMethodState; + } + } + + return &mCurMethodState->mVisibleProjectSet; +} + BfFileInstance* BfModule::GetFileFromNode(BfAstNode* astNode) { auto bfParser = astNode->GetSourceData()->ToParserData(); diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index c77355e0..46053130 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -895,6 +895,7 @@ public: Array mDeferredLambdaInstances; Array mSplatDecompAddrs; BfDeferredLocalAssignData* mDeferredLocalAssignData; + BfProjectSet mVisibleProjectSet; int mDeferredLoopListCount; int mDeferredLoopListEntryCount; HashSet mSkipObjectAccessChecks; // Indexed by BfIRValue value id @@ -1468,6 +1469,7 @@ public: void SaveStackState(BfScopeData* scope); BfIRValue ValueScopeStart(); void ValueScopeEnd(BfIRValue valueScopeStart); + BfProjectSet* GetVisibleProjectSet(); void AddBasicBlock(BfIRBlock bb, bool activate = true); void VisitEmbeddedStatement(BfAstNode* stmt, BfExprEvaluator* exprEvaluator = NULL, BfEmbeddedStatementFlags flags = BfEmbeddedStatementFlags_None); @@ -1682,7 +1684,7 @@ public: BfType* ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTypeRef, BfPopulateType populateType, BfResolveTypeRefFlags resolveFlags); void ShowAmbiguousTypeError(BfAstNode* refNode, BfTypeDef* typeDef, BfTypeDef* otherTypeDef); void ShowGenericArgCountError(BfTypeReference* typeRef, int wantedGenericParams); - BfTypeDef* GetActiveTypeDef(BfTypeInstance* typeInstanceOverride = NULL, bool useMixinDecl = false); // useMixinDecl is useful for type lookup, but we don't want the decl project to limit what methods the user can call + BfTypeDef* GetActiveTypeDef(BfTypeInstance* typeInstanceOverride = NULL, bool useMixinDecl = false); // useMixinDecl is useful for type lookup, but we don't want the decl project to limit what methods the user can call BfTypeDef* FindTypeDefRaw(const BfAtomComposite& findName, int numGenericArgs, BfTypeInstance* typeInstance, BfTypeDef* useTypeDef, BfTypeLookupError* error); BfTypeDef* FindTypeDef(const BfAtomComposite& findName, int numGenericArgs = 0, BfTypeInstance* typeInstanceOverride = NULL, BfTypeLookupError* error = NULL); BfTypeDef* FindTypeDef(const StringImpl& typeName, int numGenericArgs = 0, BfTypeInstance* typeInstanceOverride = NULL, BfTypeLookupError* error = NULL); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index c416e608..cbd14e82 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -1698,6 +1698,13 @@ bool BfTypeInstance::IsTypeMemberAccessible(BfTypeDef* declaringTypeDef, BfProje return curProject->ContainsReference(declaringTypeDef->mProject); } +bool BfTypeInstance::IsTypeMemberAccessible(BfTypeDef* declaringTypeDef, BfProjectSet* visibleProjectSet) +{ + if (visibleProjectSet == NULL) + return false; + return visibleProjectSet->Contains(declaringTypeDef->mProject); +} + bool BfTypeInstance::WantsGCMarking() { if (IsObjectOrInterface()) diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index b66e4170..8e76d605 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -552,7 +552,8 @@ public: virtual bool HasWrappedRepresentation() { return IsWrappableType(); } virtual bool IsTypeMemberIncluded(BfTypeDef* declaringTypeDef, BfTypeDef* activeTypeDef = NULL, BfModule* module = NULL) { return true; } // May be 'false' only for generic extensions with constraints virtual bool IsTypeMemberAccessible(BfTypeDef* declaringTypeDef, BfTypeDef* activeTypeDef) { return true; } - virtual bool IsTypeMemberAccessible(BfTypeDef* declaringTypeDef, BfProject* curProject) { return true; } + virtual bool IsTypeMemberAccessible(BfTypeDef* declaringTypeDef, BfProject* curProject) { return true; } + virtual bool IsTypeMemberAccessible(BfTypeDef* declaringTypeDef, BfProjectSet* visibleProjectSet) { return true; } virtual void ReportMemory(MemReporter* memReporter); }; @@ -1836,6 +1837,7 @@ public: virtual bool HasPackingHoles() override { return mHasPackingHoles; } virtual bool IsTypeMemberAccessible(BfTypeDef* declaringTypeDef, BfTypeDef* activeTypeDef) override; virtual bool IsTypeMemberAccessible(BfTypeDef* declaringTypeDef, BfProject* curProject) override; + virtual bool IsTypeMemberAccessible(BfTypeDef* declaringTypeDef, BfProjectSet* visibleProjectSet) override; virtual bool WantsGCMarking() override; virtual bool GetLoweredType(BfTypeUsage typeUsage, BfTypeCode* outTypeCode = NULL, BfTypeCode* outTypeCode2 = NULL) override; diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 45ea94d3..1559f110 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -44,6 +44,7 @@ class BfProject; struct BfTypeDefMapFuncs; typedef MultiHashSet BfTypeDefMap; +typedef HashSet BfProjectSet; class BfAtom {