2
0
Эх сурвалжийг харах

Circular dependency checking between generic constraints

Brian Fiete 3 жил өмнө
parent
commit
2bbe66cecc

+ 19 - 0
IDE/Tests/CompileFail001/src/Generics.bf

@@ -109,5 +109,24 @@ namespace IDETest
 			TestPreGen<List<int>>();
 			Method7<int>(); //FAIL The type 'int' must be a reference type in order to use it as parameter 'comptype(typeof(T))' for 'IDETest.Generics.Method7<int>()'
 		}
+
+		public static void CircDepMethod<T, T2>() where T : T2 where T2 : T //FAIL
+		{
+
+		}
+
+		class CircDep<T> where T : T //FAIL
+		{
+
+		}
 	}
 }
+
+namespace System.Collections
+{
+    extension List<T> //FAIL
+        where T : T
+    {
+
+    }
+}

+ 8 - 1
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*>((BfGenericParamInstance**)methodInstance->mMethodInfoEx->mGenericParams.mVals,
+					methodInstance->mMethodInfoEx->mGenericParams.mSize));
+		}
+
 		for (auto genericParam : methodInstance->mMethodInfoEx->mGenericParams)
 			AddDependency(genericParam, mCurTypeInstance);
 	}

+ 2 - 0
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<BfGenericParamInstance*> genericParams);
 	bool ShouldAllowMultipleDefinitions(BfTypeInstance* typeInst, BfTypeDef* firstDeclaringTypeDef, BfTypeDef* secondDeclaringTypeDef);
 	void CheckInjectNewRevision(BfTypeInstance* typeInstance);
 	void InitType(BfType* resolvedTypeRef, BfPopulateType populateType);

+ 61 - 1
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*>((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*>((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<BfGenericParamInstance*> genericParams)
+{		
+	std::function<void(BfType*, Array<BfGenericParamType*>&)> _CheckType = [&](BfType* type, Array<BfGenericParamType*>& 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<BfGenericParamType*> foundParams;
+			_CheckType(genericParam->mTypeConstraint, foundParams);
+		}
+	}
+}
+
 bool BfModule::ValidateGenericConstraints(BfAstNode* typeRef, BfTypeInstance* genericTypeInst, bool ignoreErrors)
 {
 	if ((mCurTypeInstance != NULL) && (mCurTypeInstance->IsTypeAlias()) && (mCurTypeInstance->IsGenericTypeInstance()))

+ 15 - 0
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

+ 2 - 2
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);
 			}

+ 1 - 1
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;