diff --git a/IDE/Tests/CompileFail001/src/Generics.bf b/IDE/Tests/CompileFail001/src/Generics.bf index 1e4d7db0..447928b4 100644 --- a/IDE/Tests/CompileFail001/src/Generics.bf +++ b/IDE/Tests/CompileFail001/src/Generics.bf @@ -109,5 +109,24 @@ namespace IDETest TestPreGen>(); Method7(); //FAIL The type 'int' must be a reference type in order to use it as parameter 'comptype(typeof(T))' for 'IDETest.Generics.Method7()' } + + public static void CircDepMethod() where T : T2 where T2 : T //FAIL + { + + } + + class CircDep where T : T //FAIL + { + + } } } + +namespace System.Collections +{ + extension List //FAIL + where T : T + { + + } +} diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 3db3507d..5e339d20 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -14316,7 +14316,7 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM { auto genericParamInstance = new BfGenericMethodParamInstance(methodDef, externConstraintIdx + (int)methodDef->mGenericParams.size()); methodInstance->GetMethodInfoEx()->mGenericParams.push_back(genericParamInstance); - } + } bool addToWorkList = !processNow; if (mCompiler->GetAutoComplete() != NULL) @@ -22953,6 +22953,13 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool for (auto typeRef : deferredResolveTypes) auto constraintType = ResolveTypeRef(typeRef, BfPopulateType_Declaration, BfResolveTypeRefFlag_None); + if (methodInstance->mMethodInfoEx != NULL) + { + ValidateGenericParams(BfGenericParamKind_Method, + Span((BfGenericParamInstance**)methodInstance->mMethodInfoEx->mGenericParams.mVals, + methodInstance->mMethodInfoEx->mGenericParams.mSize)); + } + for (auto genericParam : methodInstance->mMethodInfoEx->mGenericParams) AddDependency(genericParam, mCurTypeInstance); } diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 45425a21..c8e7bc52 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -16,6 +16,7 @@ #include "BeefySysLib/util/Hash.h" #include "BeefySysLib/util/HashSet.h" #include "BeefySysLib/util/SizedArray.h" +#include "BeefySysLib/Span.h" #include "BfSourceClassifier.h" #include "BfAst.h" #include "BfSystem.h" @@ -1756,6 +1757,7 @@ public: BfType* ResolveGenericMethodTypeRef(BfTypeReference* typeRef, BfMethodInstance* methodInstance, BfGenericParamInstance* genericParamInstance, BfTypeVector* methodGenericArgsOverride); bool AreConstraintsSubset(BfGenericParamInstance* checkInner, BfGenericParamInstance* checkOuter); bool CheckConstraintState(BfAstNode* refNode); + void ValidateGenericParams(BfGenericParamKind genericParamKind, Span genericParams); bool ShouldAllowMultipleDefinitions(BfTypeInstance* typeInst, BfTypeDef* firstDeclaringTypeDef, BfTypeDef* secondDeclaringTypeDef); void CheckInjectNewRevision(BfTypeInstance* typeInstance); void InitType(BfType* resolvedTypeRef, BfPopulateType populateType); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 37f7cb60..9bf5dd0e 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -110,6 +110,10 @@ BfGenericExtensionEntry* BfModule::BuildGenericExtensionInfo(BfTypeInstance* gen for (auto genericParam : genericExEntry->mGenericParams) AddDependency(genericParam, mCurTypeInstance); + ValidateGenericParams(BfGenericParamKind_Type, + Span((BfGenericParamInstance**)genericExEntry->mGenericParams.mVals, + genericExEntry->mGenericParams.mSize)); + return genericExEntry; } @@ -153,7 +157,7 @@ bool BfModule::InitGenericParams(BfType* resolvedTypeRef) } bool BfModule::FinishGenericParams(BfType* resolvedTypeRef) -{ +{ BfTypeState typeState; typeState.mPrevState = mContext->mCurTypeState; typeState.mResolveKind = BfTypeState::ResolveKind_BuildingGenericParams; @@ -326,6 +330,10 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef) for (auto typeRef : deferredResolveTypes) auto constraintType = ResolveTypeRef(typeRef, BfPopulateType_Declaration, BfResolveTypeRefFlag_None); + + ValidateGenericParams(BfGenericParamKind_Type, + Span((BfGenericParamInstance**)genericTypeInst->mGenericTypeInfo->mGenericParams.mVals, + genericTypeInst->mGenericTypeInfo->mGenericParams.mSize)); for (auto genericParam : genericTypeInst->mGenericTypeInfo->mGenericParams) AddDependency(genericParam, mCurTypeInstance); @@ -333,6 +341,58 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef) return true; } +void BfModule::ValidateGenericParams(BfGenericParamKind genericParamKind, Span genericParams) +{ + std::function&)> _CheckType = [&](BfType* type, Array& foundParams) + { + if (type == NULL) + return; + if (!type->IsGenericParam()) + return; + auto genericParamType = (BfGenericParamType*)type; + if (genericParamType->mGenericParamKind != genericParamKind) + return; + + auto genericParam = genericParams[genericParamType->mGenericParamIdx]; + if (genericParam->mTypeConstraint == NULL) + return; + + if (foundParams.Contains(genericParamType)) + { + String error = "Circular constraint dependency between "; + for (int i = 0; i < foundParams.mSize; i++) + { + auto foundParam = foundParams[i]; + if (i > 0) + error += " and "; + error += TypeToString(foundParam, BfTypeNameFlag_ResolveGenericParamNames); + + // Remove errored type constraint + genericParams[foundParam->mGenericParamIdx]->mTypeConstraint = NULL; + } + + if (foundParams.mSize == 1) + error += " and itself"; + + Fail(error, genericParams[genericParamType->mGenericParamIdx]->GetRefNode()); + return; + } + + foundParams.Add(genericParamType); + _CheckType(genericParam->mTypeConstraint, foundParams); + foundParams.pop_back(); + }; + + for (auto genericParam : genericParams) + { + if (genericParam->mTypeConstraint != NULL) + { + Array foundParams; + _CheckType(genericParam->mTypeConstraint, foundParams); + } + } +} + bool BfModule::ValidateGenericConstraints(BfAstNode* typeRef, BfTypeInstance* genericTypeInst, bool ignoreErrors) { if ((mCurTypeInstance != NULL) && (mCurTypeInstance->IsTypeAlias()) && (mCurTypeInstance->IsGenericTypeInstance())) diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 3ee4d82f..baf82411 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -1204,6 +1204,7 @@ public: virtual BfGenericParamDef* GetGenericParamDef() = 0; virtual BfExternalConstraintDef* GetExternConstraintDef() = 0; virtual String GetName() = 0; + virtual BfAstNode* GetRefNode() = NULL; bool IsEnum(); }; @@ -1255,6 +1256,13 @@ public: return mTypeDef->mGenericParamDefs[mGenericIdx]->mName; return mTypeDef->mExternalConstraints[mGenericIdx - (int)mTypeDef->mGenericParamDefs.size()].mTypeRef->ToString(); } + + virtual BfAstNode* GetRefNode() override + { + if (mGenericIdx < (int)mTypeDef->mGenericParamDefs.size()) + return mTypeDef->mGenericParamDefs[mGenericIdx]->mNameNodes[0]; + return mTypeDef->mExternalConstraints[mGenericIdx - (int)mTypeDef->mGenericParamDefs.size()].mTypeRef; + } }; class BfGenericMethodParamInstance : public BfGenericParamInstance @@ -1305,6 +1313,13 @@ public: return mMethodDef->mGenericParams[mGenericIdx]->mName; return mMethodDef->mExternalConstraints[mGenericIdx - (int)mMethodDef->mGenericParams.size()].mTypeRef->ToString(); } + + virtual BfAstNode* GetRefNode() override + { + if (mGenericIdx < (int)mMethodDef->mGenericParams.size()) + return mMethodDef->mGenericParams[mGenericIdx]->mNameNodes[0]; + return mMethodDef->mExternalConstraints[mGenericIdx - (int)mMethodDef->mGenericParams.size()].mTypeRef; + } }; #define BF_VALCOMP(val) if (val != 0) return val diff --git a/IDEHelper/HotScanner.cpp b/IDEHelper/HotScanner.cpp index 3a420146..5e8536df 100644 --- a/IDEHelper/HotScanner.cpp +++ b/IDEHelper/HotScanner.cpp @@ -297,7 +297,7 @@ void DbgHotScanner::ScanRoot(addr_target rootPtr, int memKind) continue; int expectedStartPage = (rootIdx * PageHeap::PageMap::LEAF_LENGTH) + leafIdx; - Span span; + TCFake::Span span; mDebugger->ReadMemory(spanAddr, sizeof(span), &span); ScanSpan(&span, expectedStartPage, memKind); } @@ -326,7 +326,7 @@ void DbgHotScanner::ScanRoot(addr_target rootPtr, int memKind) continue; int expectedStartPage = ((pageIdx1 * PageHeap::PageMap::INTERIOR_LENGTH) + pageIdx2) * PageHeap::PageMap::LEAF_LENGTH + pageIdx3; - Span span; + TCFake::Span span; mDebugger->ReadMemory(spanAddr, sizeof(span), &span); ScanSpan(&span, expectedStartPage, memKind); } diff --git a/IDEHelper/HotScanner.h b/IDEHelper/HotScanner.h index f6ce6bb9..d79f7274 100644 --- a/IDEHelper/HotScanner.h +++ b/IDEHelper/HotScanner.h @@ -8,7 +8,7 @@ NS_BF_DBG_BEGIN namespace TCFake { - struct Span; + struct Span; static const size_t kPageShift = 13; static const size_t kNumClasses = 88;