浏览代码

Improved comptime circular data reference issues

Brian Fiete 8 月之前
父节点
当前提交
79e98fe9f7

+ 3 - 0
IDEHelper/Compiler/BfContext.h

@@ -160,6 +160,7 @@ public:
 	BfTypeInstance* mCurBaseType;
 	BfTypeReference* mCurAttributeTypeRef;
 	BfFieldDef* mCurFieldDef;
+	BfMethodDef* mCurMethodDef;
 	BfTypeDef* mCurTypeDef;
 	BfTypeDef* mForceActiveTypeDef;
 	BfProject* mActiveProject;
@@ -179,6 +180,7 @@ public:
 		mCurBaseTypeRef = NULL;
 		mCurBaseType = NULL;
 		mCurFieldDef = NULL;
+		mCurMethodDef = NULL;
 		mCurAttributeTypeRef = NULL;
 		mCurTypeDef = NULL;
 		mForceActiveTypeDef = NULL;
@@ -199,6 +201,7 @@ public:
 		mCurBaseTypeRef = NULL;
 		mCurBaseType = NULL;
 		mCurFieldDef = NULL;
+		mCurMethodDef = NULL;
 		mCurAttributeTypeRef = NULL;
 		mCurTypeDef = NULL;
 		mForceActiveTypeDef = NULL;

+ 4 - 4
IDEHelper/Compiler/BfMangler.cpp

@@ -1183,10 +1183,10 @@ void BfMSMangler::AddTypeStart(MangleContext& mangleContext, StringImpl& name, B
 	if ((type->IsEnum()) && (type->IsTypedPrimitive()))
 	{
 		auto unreifiedModule = mangleContext.GetUnreifiedModule();
-		if (unreifiedModule != NULL)
-			unreifiedModule->PopulateType(type, BfPopulateType_Data);
-
-		BF_ASSERT(type->mSize >= 0);
+		if (type->mDefineState >= BfTypeDefineState_Defined)
+		{
+			BF_ASSERT(type->mSize >= 0);
+		}
 
 		// The enum size is supposed to be encoded, but VC always uses '4'
 		//name += "W";

+ 8 - 5
IDEHelper/Compiler/BfModule.cpp

@@ -24124,12 +24124,19 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 
 	BP_ZONE("BfModule::DoMethodDeclaration");
 	
+	auto typeInstance = mCurTypeInstance;
+	auto typeDef = typeInstance->mTypeDef;
+	auto methodDef = mCurMethodInstance->mMethodDef;
+
 	// We could trigger a DoMethodDeclaration from a const resolver or other location, so we reset it here
 	//  to effectively make mIgnoreWrites method-scoped
 	SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, mWantsIRIgnoreWrites || mCurMethodInstance->mIsUnspecialized || mCurTypeInstance->mResolvingVarField);
 	SetAndRestoreValue<bool> prevIsCapturingMethodMatchInfo;
 	SetAndRestoreValue<bool> prevAllowLockYield(mContext->mAllowLockYield, false);
 	BfTypeState typeState(mCurTypeInstance);
+	typeState.mPrevState = mContext->mCurTypeState;
+	typeState.mForceActiveTypeDef = methodDef->mDeclaringType;
+	typeState.mCurMethodDef = methodDef;
 	SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
 
 	BfModule* resolveModule = mContext->mUnreifiedModule;
@@ -24158,11 +24165,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 //  	}
 
 	if ((mAwaitingInitFinish) && (!mBfIRBuilder->mIgnoreWrites))
-		FinishInit();
-
-	auto typeInstance = mCurTypeInstance;
-	auto typeDef = typeInstance->mTypeDef;
-	auto methodDef = mCurMethodInstance->mMethodDef;
+		FinishInit();	
 
 	if (methodDef->mName.StartsWith('_'))
 	{

+ 1 - 1
IDEHelper/Compiler/BfModule.h

@@ -1635,7 +1635,7 @@ public:
 	BfError* Warn(int warningNum, const StringImpl& warning, BfAstNode* refNode = NULL, bool isPersistent = false, bool showInSpecialized = false);
 	void CheckErrorAttributes(BfTypeInstance* typeInstance, BfMethodInstance* methodInstance, BfFieldInstance* fieldInstance, BfCustomAttributes* customAttributes, BfAstNode* targetSrc);
 	void CheckRangeError(BfType* type, BfAstNode* refNode);
-	bool CheckCircularDataError(bool failTypes = true);
+	bool CheckCircularDataError(bool failTypes = true, bool forceFail = false);
 	BfFileInstance* GetFileFromNode(BfAstNode* astNode);
 	//void UpdateSrcPos(BfAstNode* astNode, bool setDebugLoc = true, int debugLocOffset = 0, bool force = false);
 	void UpdateSrcPos(BfAstNode* astNode, BfSrcPosFlags flags = BfSrcPosFlag_None, int debugLocOffset = 0);

+ 93 - 10
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -1044,8 +1044,12 @@ void BfModule::TypeFailed(BfTypeInstance* typeInstance)
 	mHadBuildError = true;
 }
 
-bool BfModule::CheckCircularDataError(bool failTypes)
+bool BfModule::CheckCircularDataError(bool failTypes, bool forceFail)
 {
+	// First check to see if the forceFail is necessary
+	if ((forceFail) && (CheckCircularDataError(failTypes, false)))
+		return true;
+
 	// Find two loops of mCurTypeInstance. Just finding one loop can give some false errors.
 
 	BfTypeState* circularTypeStateEnd = NULL;
@@ -1055,6 +1059,9 @@ bool BfModule::CheckCircularDataError(bool failTypes)
 	bool isPreBaseCheck = checkTypeState->mPopulateType == BfPopulateType_Declaration;
 	while (true)
 	{
+		if (forceFail)
+			break;
+
 		if (checkTypeState == NULL)
 			return false;
 
@@ -1090,7 +1097,9 @@ bool BfModule::CheckCircularDataError(bool failTypes)
 	}
 
 	bool hadError = false;
-	checkTypeState = mContext->mCurTypeState->mPrevState;
+	checkTypeState = mContext->mCurTypeState;
+	if (!forceFail)
+		checkTypeState = checkTypeState->mPrevState;
 	while (true)
 	{
 		if (checkTypeState == NULL)
@@ -1106,7 +1115,12 @@ bool BfModule::CheckCircularDataError(bool failTypes)
 			continue;
 		}
 
-		if ((checkTypeState->mCurAttributeTypeRef == NULL) && (checkTypeState->mCurBaseTypeRef == NULL) && (checkTypeState->mCurFieldDef == NULL) &&
+		if (forceFail)
+		{
+			// Go all the way through
+			NOP;
+		}
+		else if ((checkTypeState->mCurAttributeTypeRef == NULL) && (checkTypeState->mCurBaseTypeRef == NULL) && (checkTypeState->mCurFieldDef == NULL) &&
 			((checkTypeState->mType == NULL) || (checkTypeState->mType->IsTypeInstance())))
 			return hadError;
 
@@ -1130,6 +1144,11 @@ bool BfModule::CheckCircularDataError(bool failTypes)
 			Fail(StrFormat("Field '%s.%s' causes a data cycle", TypeToString(checkTypeState->mType).c_str(), checkTypeState->mCurFieldDef->mName.c_str()),
 				checkTypeState->mCurFieldDef->mTypeRef, true);
 		}
+		else if ((checkTypeState->mCurMethodDef != NULL) && (checkTypeState->mCurMethodDef->mMethodDeclaration != NULL))
+		{
+			Fail(StrFormat("Method '%s.%s' causes a data cycle", TypeToString(checkTypeState->mType).c_str(), checkTypeState->mCurMethodDef->mName.c_str()),
+				checkTypeState->mCurMethodDef->GetRefNode(), true);
+		}
 		else if (checkTypeState->mCurFieldDef != NULL)
 		{
 			BfAstNode* refNode = checkTypeState->mCurFieldDef->GetRefNode();
@@ -2838,6 +2857,11 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance*
 			continue;
 		}
 
+		if (typeInstance->mTypeDef->mName->ToString() == "AssetType")
+		{
+			NOP;
+		}	
+
 		SetAndRestoreValue<CeEmitContext*> prevEmitContext(mCompiler->mCeMachine->mCurEmitContext);
 		if (onCompileKind == BfCEOnCompileKind_TypeInit)
 		{
@@ -5217,21 +5241,80 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 			if ((foundTypeCount >= 2) || (typeInstance->mTypeDef->IsEmitted()))
 			{
 				String error = "OnCompile const evaluation creates a data dependency during TypeInit";
-				if (mCompiler->mCeMachine->mCurBuilder != NULL)
-				{
-					error += StrFormat(" during const-eval generation of '%s'", MethodToString(mCompiler->mCeMachine->mCurBuilder->mCeFunction->mMethodInstance).c_str());
-				}
+				
+
+// 				if (mCompiler->mCeMachine->mCurBuilder != NULL)
+// 				{
+// 					error += StrFormat(" during const-eval generation of '%s'", MethodToString(mCompiler->mCeMachine->mCurBuilder->mCeFunction->mMethodInstance).c_str());
+// 				}
+
+				BfError* bfError = NULL;
 
 				auto refNode = typeDef->GetRefNode();
-				Fail(error, refNode);
+				//Fail(error, refNode);
+				mCompiler->mCeMachine->FailCurrent(this, error, refNode);
+
 				if ((mCompiler->mCeMachine->mCurContext != NULL) && (mCompiler->mCeMachine->mCurContext->mCurFrame != NULL))
-					mCompiler->mCeMachine->mCurContext->Fail(*mCompiler->mCeMachine->mCurContext->mCurFrame, error);
+					bfError = mCompiler->mCeMachine->mCurContext->Fail(*mCompiler->mCeMachine->mCurContext->mCurFrame, error);
 				else if (mCompiler->mCeMachine->mCurContext != NULL)
-					mCompiler->mCeMachine->mCurContext->Fail(error);
+					bfError = mCompiler->mCeMachine->mCurContext->Fail(error);
 				tryCE = false;
+
+				if (bfError != NULL)
+				{
+					auto passInstance = mCompiler->mPassInstance;
+
+					int foundTypeCount = 0;
+					auto typeState = mContext->mCurTypeState;
+					while (typeState != NULL)
+					{
+						if (typeState->mCurAttributeTypeRef != NULL)
+						{
+							passInstance->MoreInfo(StrFormat("Attribute type '%s' causes a data cycle", BfTypeUtils::TypeToString(typeState->mCurAttributeTypeRef).c_str()), typeState->mCurAttributeTypeRef);
+						}
+						else if (typeState->mCurBaseTypeRef != NULL)
+						{
+							passInstance->MoreInfo(StrFormat("Base type '%s' causes a data cycle", BfTypeUtils::TypeToString(typeState->mCurBaseTypeRef).c_str()), typeState->mCurBaseTypeRef);
+						}
+						else if ((typeState->mCurFieldDef != NULL) && (typeState->mCurFieldDef->mFieldDeclaration != NULL))
+						{
+							passInstance->MoreInfo(StrFormat("Field '%s.%s' causes a data cycle", TypeToString(typeState->mType).c_str(), typeState->mCurFieldDef->mName.c_str()),
+								typeState->mCurFieldDef->mTypeRef);
+						}
+						else if ((typeState->mCurMethodDef != NULL) && (typeState->mCurMethodDef->mMethodDeclaration != NULL))
+						{
+							passInstance->MoreInfo(StrFormat("Method '%s.%s' causes a data cycle", TypeToString(typeState->mType).c_str(), typeState->mCurMethodDef->mName.c_str()),
+								typeState->mCurMethodDef->GetRefNode());
+						}						
+						else
+						{
+							BfAstNode* refNode = NULL;
+							if (typeState->mCurTypeDef != NULL)
+								refNode = typeState->mCurTypeDef->GetRefNode();
+							passInstance->MoreInfo(StrFormat("Type '%s' causes a data cycle", TypeToString(typeState->mType).c_str()), refNode);
+						}
+
+						if (typeState->mType == typeInstance)
+						{
+							foundTypeCount++;
+							if (foundTypeCount == 2)
+								break;
+						}
+						typeState = typeState->mPrevState;
+					}
+				}
 			}
  		}
 
+		if ((typeInstance->mDefineState == BfTypeDefineState_CETypeInit) && (tryCE))
+		{
+			if (!CheckCircularDataError())
+			{
+				Fail(StrFormat("Unexpected comptime circular data error detected in type '%s'", TypeToString(typeInstance).c_str()), typeDef->GetRefNode());
+				CheckCircularDataError(true, true);
+			}
+		}
+		
 		if ((typeInstance->mDefineState < BfTypeDefineState_CEPostTypeInit) && (tryCE))
  		{
 			BF_ASSERT(!typeInstance->mTypeDef->IsEmitted());

+ 44 - 4
IDEHelper/Compiler/CeMachine.cpp

@@ -3587,6 +3587,7 @@ CeContext::CeContext()
 	mReflectTypeIdOffset = -1;
 	mExecuteId = -1;
 	mStackSize = -1;
+	mRecursiveDepth = -1;
 
 	mCurCallSource = NULL;
 	mHeap = new	ContiguousHeap();
@@ -5194,7 +5195,7 @@ BfTypedValue CeContext::Call(CeCallSource callSource, BfModule* module, BfMethod
 	SetAndRestoreValue<BfMethodInstance*> moduleCurMethodInstance(module->mCurMethodInstance, methodInstance);
 	SetAndRestoreValue<BfTypeInstance*> moduleCurTypeInstance(module->mCurTypeInstance, methodInstance->GetOwner());
 
-	SetAndRestoreValue<int> prevCurExecuteId(mCurModule->mCompiler->mCurCEExecuteId, mCeMachine->mExecuteId);
+	SetAndRestoreValue<int> prevCurExecuteId(mCurModule->mCompiler->mCurCEExecuteId, mCeMachine->mExecuteId);	
 
 	// Reentrancy may occur as methods need defining
 	//SetAndRestoreValue<BfMethodState*> prevMethodStateInConstEval(module->mCurMethodState, NULL);
@@ -9414,6 +9415,7 @@ CeMachine::CeMachine(BfCompiler* compiler)
 	mCurContext = NULL;
 	mCurCallSource = NULL;
 	mExecuteId = -1;
+	mCurRecursiveDepth = 0;
 
 	mCurFunctionId = 0;
 	mRevisionExecuteTime = 0;
@@ -10305,10 +10307,12 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder
 
 	CeBuilder ceBuilder;
 	SetAndRestoreValue<CeBuilder*> prevBuilder(mCurBuilder, &ceBuilder);
-	ceBuilder.mParentBuilder = parentBuilder;
+	ceBuilder.mParentBuilder = parentBuilder;	
 	ceBuilder.mPtrSize = mCeModule->mCompiler->mSystem->mPtrSize;
 	ceBuilder.mCeMachine = this;
 	ceBuilder.mCeFunction = ceFunction;
+	SetAndRestoreValue<int> prevRecursiveDepth(mCurRecursiveDepth, mCurRecursiveDepth + 1);
+	ceBuilder.mRecursiveDepth = mCurRecursiveDepth;
 	ceBuilder.Build();
 
 	ceFunction->mInitializeState = CeFunction::InitializeState_Initialized;
@@ -10599,8 +10603,44 @@ void CeMachine::ReleaseContext(CeContext* ceContext)
 
 BfTypedValue CeMachine::Call(CeCallSource callSource, BfModule* module, BfMethodInstance* methodInstance, const BfSizedArray<BfIRValue>& args, CeEvalFlags flags, BfType* expectingType)
 {
-	auto ceContext = AllocContext();
+	auto ceContext = AllocContext();	
+	SetAndRestoreValue<int> prevRecursiveDepth(mCurRecursiveDepth, mCurRecursiveDepth + 1);
+	ceContext->mRecursiveDepth = mCurRecursiveDepth;
 	auto result = ceContext->Call(callSource, module, methodInstance, args, flags, expectingType);
 	ReleaseContext(ceContext);
 	return result;
-}
+}
+
+BfError* CeMachine::FailCurrent(BfModule* srcModule, const StringImpl& error, BfAstNode* refNode)
+{
+	BfError* bfError = NULL;
+
+	if ((mCurBuilder != NULL) &&
+		((mCurContext != NULL) || (mCurBuilder->mRecursiveDepth > mCurContext->mRecursiveDepth)))
+	{
+		String useError = error;
+		useError += StrFormat(" during const-eval generation of '%s'", srcModule->MethodToString(mCurBuilder->mCeFunction->mMethodInstance).c_str());		
+		bfError = srcModule->Fail(error, refNode);
+
+		if (bfError != NULL)
+		{
+			auto filePos = mCurBuilder->mCeMachine->mCeModule->mCurFilePosition;
+			auto parser = filePos.mFileInstance->mParser;
+			if (parser != NULL)
+			{
+				srcModule->mCompiler->mPassInstance->MoreInfoAt(
+					StrFormat("See comptime method '%s' processing location", srcModule->MethodToString(mCurBuilder->mCeFunction->mMethodInstance).c_str()),
+					parser, filePos.mCurSrcPos, 1, BfFailFlag_None);
+			}
+		}
+	}
+	else
+	{
+		bfError = srcModule->Fail(error, refNode);
+	}	
+	return bfError;
+}
+
+void CeMachine::FailCurrentMoreInfo(const StringImpl& error, BfAstNode* refNode)
+{
+}

+ 8 - 1
IDEHelper/Compiler/CeMachine.h

@@ -833,12 +833,13 @@ class CeBuilder
 {
 public:
 	CeBuilder* mParentBuilder;
-	CeMachine* mCeMachine;
+	CeMachine* mCeMachine;	
 	CeFunction* mCeFunction;
 	BeFunction* mBeFunction;
 	CeOperand mReturnVal;
 	BeType* mIntPtrType;
 	int mPtrSize;
+	int mRecursiveDepth;
 
 	String mError;
 	BeDbgLoc* mCurDbgLoc;
@@ -862,6 +863,7 @@ public:
 	{
 		mParentBuilder = NULL;
 		mPtrSize = 0;
+		mRecursiveDepth = -1;
 		mCeFunction = NULL;
 		mBeFunction = NULL;
 		mCeMachine = NULL;
@@ -1126,6 +1128,7 @@ public:
 	int mReflectTypeIdOffset;
 	int mExecuteId;
 	CeEvalFlags mCurEvalFlags;
+	int mRecursiveDepth;
 
 	// These are only valid for the current execution
 	ContiguousHeap* mHeap;
@@ -1248,6 +1251,7 @@ public:
 	int mRevisionExecuteTime;
 	int mCurFunctionId;
 	int mExecuteId;
+	int mCurRecursiveDepth;
 	CeAppendAllocInfo* mAppendAllocInfo;
 
 	CeContext* mCurContext;
@@ -1308,6 +1312,9 @@ public:
 	CeContext* AllocContext();
 	void ReleaseContext(CeContext* context);
 	BfTypedValue Call(CeCallSource callSource, BfModule* module, BfMethodInstance* methodInstance, const BfSizedArray<BfIRValue>& args, CeEvalFlags flags, BfType* expectingType);
+
+	BfError* FailCurrent(BfModule* srcModule, const StringImpl& error, BfAstNode* refNode);
+	void FailCurrentMoreInfo(const StringImpl& error, BfAstNode* refNode);
 };
 
 NS_BF_END