diff --git a/IDEHelper/Compiler/BfContext.h b/IDEHelper/Compiler/BfContext.h index fc662dfc..7b3e05e5 100644 --- a/IDEHelper/Compiler/BfContext.h +++ b/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; diff --git a/IDEHelper/Compiler/BfMangler.cpp b/IDEHelper/Compiler/BfMangler.cpp index e9f7dd66..40285887 100644 --- a/IDEHelper/Compiler/BfMangler.cpp +++ b/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"; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index faf36589..05e2d7c5 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/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 prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, mWantsIRIgnoreWrites || mCurMethodInstance->mIsUnspecialized || mCurTypeInstance->mResolvingVarField); SetAndRestoreValue prevIsCapturingMethodMatchInfo; SetAndRestoreValue prevAllowLockYield(mContext->mAllowLockYield, false); BfTypeState typeState(mCurTypeInstance); + typeState.mPrevState = mContext->mCurTypeState; + typeState.mForceActiveTypeDef = methodDef->mDeclaringType; + typeState.mCurMethodDef = methodDef; SetAndRestoreValue 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('_')) { diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index aff341f4..0cc761fc 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/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); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 984a88be..c2fd1137 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/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 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()); diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index cc602aef..6e9ef87a 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/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 moduleCurMethodInstance(module->mCurMethodInstance, methodInstance); SetAndRestoreValue moduleCurTypeInstance(module->mCurTypeInstance, methodInstance->GetOwner()); - SetAndRestoreValue prevCurExecuteId(mCurModule->mCompiler->mCurCEExecuteId, mCeMachine->mExecuteId); + SetAndRestoreValue prevCurExecuteId(mCurModule->mCompiler->mCurCEExecuteId, mCeMachine->mExecuteId); // Reentrancy may occur as methods need defining //SetAndRestoreValue 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 prevBuilder(mCurBuilder, &ceBuilder); - ceBuilder.mParentBuilder = parentBuilder; + ceBuilder.mParentBuilder = parentBuilder; ceBuilder.mPtrSize = mCeModule->mCompiler->mSystem->mPtrSize; ceBuilder.mCeMachine = this; ceBuilder.mCeFunction = ceFunction; + SetAndRestoreValue 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& args, CeEvalFlags flags, BfType* expectingType) { - auto ceContext = AllocContext(); + auto ceContext = AllocContext(); + SetAndRestoreValue prevRecursiveDepth(mCurRecursiveDepth, mCurRecursiveDepth + 1); + ceContext->mRecursiveDepth = mCurRecursiveDepth; auto result = ceContext->Call(callSource, module, methodInstance, args, flags, expectingType); ReleaseContext(ceContext); return result; -} \ No newline at end of file +} + +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) +{ +} diff --git a/IDEHelper/Compiler/CeMachine.h b/IDEHelper/Compiler/CeMachine.h index 3c50c3a4..e7ceb672 100644 --- a/IDEHelper/Compiler/CeMachine.h +++ b/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& args, CeEvalFlags flags, BfType* expectingType); + + BfError* FailCurrent(BfModule* srcModule, const StringImpl& error, BfAstNode* refNode); + void FailCurrentMoreInfo(const StringImpl& error, BfAstNode* refNode); }; NS_BF_END