diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 91b171db..5e915e42 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -3464,20 +3464,25 @@ void BfModule::AddDependency(BfType* usedType, BfType* userType, BfDependencyMap if (addType) { auto checkTypeInst = checkType->ToTypeInstance(); - auto hotTypeVersion = checkTypeInst->mHotTypeData->GetLatestVersion(); - BF_ASSERT(hotTypeVersion != NULL); + if (checkTypeInst->mHotTypeData != NULL) + { + auto hotTypeVersion = checkTypeInst->mHotTypeData->GetLatestVersion(); + BF_ASSERT(hotTypeVersion != NULL); + if (hotTypeVersion != NULL) + { + bool isAllocation = ((flags & BfDependencyMap::DependencyFlag_Allocates) != 0); + if (((flags & BfDependencyMap::DependencyFlag_LocalUsage) != 0) && + (checkType->IsComposite())) + isAllocation = true; - bool isAllocation = ((flags & BfDependencyMap::DependencyFlag_Allocates) != 0); - if (((flags & BfDependencyMap::DependencyFlag_LocalUsage) != 0) && - (checkType->IsComposite())) - isAllocation = true; - - if (isAllocation) - { - mCurMethodState->mHotDataReferenceBuilder->mAllocatedData.Add(hotTypeVersion); + if (isAllocation) + { + mCurMethodState->mHotDataReferenceBuilder->mAllocatedData.Add(hotTypeVersion); + } + else + mCurMethodState->mHotDataReferenceBuilder->mUsedData.Add(hotTypeVersion); + } } - else - mCurMethodState->mHotDataReferenceBuilder->mUsedData.Add(hotTypeVersion); } } @@ -6432,9 +6437,10 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin } } else if (fieldInstance->GetFieldDef()->mIsStatic) - { - auto refVal = ReferenceStaticField(fieldInstance); - + { + BfTypedValue refVal; + if (!mIsComptimeModule) // This can create circular reference issues for a `Self` static + refVal = ReferenceStaticField(fieldInstance); if (refVal.mValue.IsConst()) { auto constant = mBfIRBuilder->GetConstant(refVal.mValue); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 99248138..229f470e 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -1178,11 +1178,6 @@ void BfModule::PopulateType(BfType* resolvedTypeRef, BfPopulateType populateType else resolvedTypeRef->mTypeId = mCompiler->mCurTypeId++; - if (resolvedTypeRef->mTypeId == 2568) - { - NOP; - } - while (resolvedTypeRef->mTypeId >= (int)mContext->mTypes.size()) mContext->mTypes.Add(NULL); mContext->mTypes[resolvedTypeRef->mTypeId] = resolvedTypeRef; @@ -2158,6 +2153,9 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* auto result = ceContext->Call(customAttribute.mRef, this, methodInstance, args, CeEvalFlags_None, NULL); + if (typeInstance->mDefineState == BfTypeDefineState_DefinedAndMethodsSlotted) + return; + if (typeInstance->mDefineState != BfTypeDefineState_CETypeInit) { // We populated before we could finish @@ -2438,6 +2436,9 @@ void BfModule::DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers) ceEmitContext.mType = typeInstance; ExecuteCEOnCompile(&ceEmitContext, typeInstance, BfCEOnCompileKind_TypeInit); hadNewMembers = (typeInstance->mTypeDef->mEmitParent != NULL); + + if (ceEmitContext.mFailed) + TypeFailed(typeInstance); } void BfModule::DoCEEmit(BfMethodInstance* methodInstance) @@ -3939,26 +3940,46 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy } } + bool tryCE = true; if (typeInstance->mDefineState == BfTypeDefineState_CETypeInit) { if (populateType <= BfPopulateType_AllowStaticMethods) return; - String error = "OnCompile const evaluation creates a data dependency during TypeInit"; - if (mCompiler->mCEMachine->mCurBuilder != NULL) + int foundTypeCount = 0; + auto typeState = mContext->mCurTypeState; + while (typeState != NULL) { - error += StrFormat(" during const-eval generation of '%s'", MethodToString(mCompiler->mCEMachine->mCurBuilder->mCeFunction->mMethodInstance).c_str()); + if (typeState->mType == typeInstance) + { + foundTypeCount++; + if (foundTypeCount == 2) + break; + } + typeState = typeState->mPrevState; } - auto refNode = typeDef->GetRefNode(); - Fail(error, refNode); - if ((mCompiler->mCEMachine->mCurContext != NULL) && (mCompiler->mCEMachine->mCurContext->mCurFrame != NULL)) - mCompiler->mCEMachine->mCurContext->Fail(*mCompiler->mCEMachine->mCurContext->mCurFrame, error); - else if (mCompiler->mCEMachine->mCurContext != NULL) - mCompiler->mCEMachine->mCurContext->Fail(error); + 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()); + } + + auto refNode = typeDef->GetRefNode(); + Fail(error, refNode); + if ((mCompiler->mCEMachine->mCurContext != NULL) && (mCompiler->mCEMachine->mCurContext->mCurFrame != NULL)) + mCompiler->mCEMachine->mCurContext->Fail(*mCompiler->mCEMachine->mCurContext->mCurFrame, error); + else if (mCompiler->mCEMachine->mCurContext != NULL) + mCompiler->mCEMachine->mCurContext->Fail(error); + } } - else if (typeInstance->mDefineState < BfTypeDefineState_CEPostTypeInit) - { + + if ((typeInstance->mDefineState < BfTypeDefineState_CEPostTypeInit) && (tryCE)) + { + BF_ASSERT(!typeInstance->mTypeDef->IsEmitted()); + typeInstance->mDefineState = BfTypeDefineState_CETypeInit; bool hadNewMembers = false; DoCEEmit(typeInstance, hadNewMembers); @@ -3991,9 +4012,17 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy { if ((typeInstance->mCeTypeInfo->mHash != typeInstance->mCeTypeInfo->mNext->mHash) && (!typeInstance->mCeTypeInfo->mHash.IsZero())) { + int prevDeletedTypes = mCompiler->mStats.mTypesDeleted; if (mCompiler->mIsResolveOnly) mCompiler->mNeedsFullRefresh = true; + BfLogSysM("Type %p hash changed, rebuilding dependent types\n", typeInstance); mContext->RebuildDependentTypes(typeInstance); + + if (mCompiler->mStats.mTypesDeleted != prevDeletedTypes) + { + BfLogSysM("Type %p hash changed, rebuilding dependent types - updating after deleting types\n", typeInstance); + mContext->UpdateAfterDeletingTypes(); + } } typeInstance->mCeTypeInfo->mOnCompileMap = typeInstance->mCeTypeInfo->mNext->mOnCompileMap; typeInstance->mCeTypeInfo->mTypeIFaceMap = typeInstance->mCeTypeInfo->mNext->mTypeIFaceMap; @@ -6205,6 +6234,15 @@ void BfModule::AddMethodToWorkList(BfMethodInstance* methodInstance) auto typeInstance = methodInstance->GetOwner(); BfMethodProcessRequest* methodProcessRequest = mContext->mMethodWorkList.Alloc(); + if (mCompiler->mCompileState == BfCompiler::CompileState_Unreified) + { + if (methodInstance->mIsReified) + { + BfLogSysM("Marking method %d as unreified due to CompileState_Unreified\n", methodInstance); + methodInstance->mIsReified = false; + } + } + //BF_ASSERT(!methodInstance->mIsReified); methodProcessRequest->mType = typeInstance; methodProcessRequest->mMethodInstance = methodInstance; methodProcessRequest->mRevision = typeInstance->mRevision; @@ -9976,6 +10014,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula if (!inserted) { BF_ASSERT(resolvedEntry->mValue != NULL); + BF_ASSERT(!resolvedEntry->mValue->IsDeleting()); return ResolveTypeResult(typeRef, resolvedEntry->mValue, populateType, resolveFlags); } diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index a02f8971..0b9384c3 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -1120,7 +1120,7 @@ CeOperand CeBuilder::GetOperand(BeValue* value, bool allowAlloca, bool allowImme if (checkBuilder->mInnerFunctionMap.TryGetValue(beFunction, &innerFunctionIdx)) { auto innerFunction = checkBuilder->mCeFunction->mInnerFunctions[innerFunctionIdx]; - if (!innerFunction->mInitialized) + if (innerFunction->mInitializeState < CeFunction::InitializeState_Initialized) mCeMachine->PrepareFunction(innerFunction, checkBuilder); CeOperand result = FrameAlloc(mCeMachine->GetBeContext()->GetPrimitiveType((sizeof(BfMethodInstance*) == 8) ? BeTypeCode_Int64 : BeTypeCode_Int32)); @@ -1288,7 +1288,7 @@ void CeBuilder::Build() auto methodInstance = mCeFunction->mMethodInstance; if (methodInstance != NULL) - { + { BfMethodInstance dupMethodInstance; dupMethodInstance.CopyFrom(methodInstance); auto methodDef = methodInstance->mMethodDef; @@ -1313,7 +1313,9 @@ void CeBuilder::Build() int startFunctionCount = (int)beModule->mFunctions.size(); ProcessMethod(methodInstance, &dupMethodInstance); - + if (mCeFunction->mInitializeState == CeFunction::InitializeState_Initialized) + return; + if (!dupMethodInstance.mIRFunction) { mCeFunction->mFailed = true; @@ -2855,6 +2857,7 @@ void CeBuilder::Build() CeContext::CeContext() { + mPrevContext = NULL; mCurEvalFlags = CeEvalFlags_None; mCeMachine = NULL; mReflectTypeIdOffset = -1; @@ -2876,6 +2879,8 @@ CeContext::~CeContext() BfError* CeContext::Fail(const StringImpl& error) { + if (mCurEmitContext != NULL) + mCurEmitContext->mFailed = true; auto bfError = mCurModule->Fail(StrFormat("Unable to comptime %s", mCurModule->MethodToString(mCurMethodInstance).c_str()), mCurTargetSrc, (mCurEvalFlags & CeEvalFlags_PersistantError) != 0); if (bfError == NULL) return NULL; @@ -2885,6 +2890,8 @@ BfError* CeContext::Fail(const StringImpl& error) BfError* CeContext::Fail(const CeFrame& curFrame, const StringImpl& str) { + if (mCurEmitContext != NULL) + mCurEmitContext->mFailed = true; auto bfError = mCurModule->Fail(StrFormat("Unable to comptime %s", mCurModule->MethodToString(mCurMethodInstance).c_str()), mCurTargetSrc, (mCurEvalFlags & CeEvalFlags_PersistantError) != 0, ((mCurEvalFlags & CeEvalFlags_DeferIfNotOnlyError) != 0) && !mCurModule->mHadBuildError); @@ -2966,6 +2973,10 @@ BfError* CeContext::Fail(const CeFrame& curFrame, const StringImpl& str) moreInfo->mLocation = location; } } + else + { + auto moreInfo = passInstance->MoreInfo(err, mCeMachine->mCeModule->mCompiler->GetAutoComplete() != NULL); + } } return bfError; @@ -3939,6 +3950,7 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns AutoTimer autoTimer(mCeMachine->mRevisionExecuteTime); + SetAndRestoreValue curPrevContext(mPrevContext, mCeMachine->mCurContext); SetAndRestoreValue prevContext(mCeMachine->mCurContext, this); SetAndRestoreValue prevEvalFlags(mCurEvalFlags, flags); SetAndRestoreValue prevTargetSrc(mCurTargetSrc, targetSrc); @@ -4042,13 +4054,24 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns bool added = false; CeFunction* ceFunction = mCeMachine->GetFunction(methodInstance, BfIRValue(), added); - if (ceFunction->mGenerating) + if (ceFunction->mInitializeState == CeFunction::InitializeState_Initializing_ReEntry) { - Fail("Recursive var-inference"); + String error = "Comptime method preparation recursion"; + auto curContext = this; + while (curContext != NULL) + { + if (curContext->mCurMethodInstance != NULL) + error += StrFormat("\n %s", module->MethodToString(curContext->mCurMethodInstance).c_str()); + + curContext = curContext->mPrevContext; + if ((curContext != NULL) && (curContext->mCurMethodInstance == mCurMethodInstance)) + break; + } + Fail(error); return BfTypedValue(); } - if (!ceFunction->mInitialized) + if (ceFunction->mInitializeState < CeFunction::InitializeState_Initialized) mCeMachine->PrepareFunction(ceFunction, NULL); auto stackPtr = &mMemory[0] + BF_CE_STACK_SIZE; @@ -4926,7 +4949,7 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* if (!checkFunction->mFailed) return true; - auto error = Fail(_GetCurFrame(), StrFormat("Method call '%s' failed", ceModule->MethodToString(checkFunction->mMethodInstance).c_str())); + auto error = Fail(_GetCurFrame(), StrFormat("Method call preparation '%s' failed", ceModule->MethodToString(checkFunction->mMethodInstance).c_str())); if ((error != NULL) && (!checkFunction->mGenError.IsEmpty())) mCeMachine->mCompiler->mPassInstance->MoreInfo("Comptime method generation error: " + checkFunction->mGenError); return false; @@ -5394,7 +5417,7 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* bool added = false; ctorCallFunction = mCeMachine->GetFunction(moduleMethodInstance.mMethodInstance, moduleMethodInstance.mFunc, added); - if (!ctorCallFunction->mInitialized) + if (ctorCallFunction->mInitializeState < CeFunction::InitializeState_Initialized) mCeMachine->PrepareFunction(ctorCallFunction, NULL); } @@ -5469,11 +5492,11 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* } callEntry.mFunction = callEntry.mFunctionInfo->mCeFunction; - if (!callEntry.mFunction->mInitialized) + if (callEntry.mFunction->mInitializeState < CeFunction::InitializeState_Initialized) { auto curFrame = _GetCurFrame(); SetAndRestoreValue prevFrame(mCurFrame, &curFrame); - BF_ASSERT(!callEntry.mFunction->mInitialized); + BF_ASSERT(callEntry.mFunction->mInitializeState < CeFunction::InitializeState_Initialized); mCeMachine->PrepareFunction(callEntry.mFunction, NULL); } @@ -6912,7 +6935,7 @@ void CeMachine::CheckFunctionKind(CeFunction* ceFunction) ceFunction->mFunctionKind = CeFunctionKind_Math_Tanh; } - ceFunction->mInitialized = true; + ceFunction->mInitializeState = CeFunction::InitializeState_Initialized; return; } } @@ -6923,19 +6946,27 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder AutoTimer autoTimer(mRevisionExecuteTime); SetAndRestoreValue prevCEFunction(mPreparingFunction, ceFunction); - BF_ASSERT(!ceFunction->mInitialized); + BF_ASSERT(ceFunction->mInitializeState <= CeFunction::InitializeState_Initialized); if (ceFunction->mFunctionKind == CeFunctionKind_NotSet) { CheckFunctionKind(ceFunction); - if (ceFunction->mInitialized) + if (ceFunction->mInitializeState == CeFunction::InitializeState_Initialized) return; } - BF_ASSERT(!ceFunction->mInitialized); - ceFunction->mInitialized = true; - ceFunction->mGenerating = true; + BF_ASSERT(ceFunction->mInitializeState <= CeFunction::InitializeState_Initialized); + if (ceFunction->mInitializeState == CeFunction::InitializeState_Initializing_ReEntry) + { + //Fail("Function generation re-entry"); + return; + } + if (ceFunction->mInitializeState == CeFunction::InitializeState_Initializing) + ceFunction->mInitializeState = CeFunction::InitializeState_Initializing_ReEntry; + else + ceFunction->mInitializeState = CeFunction::InitializeState_Initializing; + CeBuilder ceBuilder; SetAndRestoreValue prevBuilder(mCurBuilder, &ceBuilder); ceBuilder.mParentBuilder = parentBuilder; @@ -6944,7 +6975,7 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder ceBuilder.mCeFunction = ceFunction; ceBuilder.Build(); - ceFunction->mGenerating = false; + ceFunction->mInitializeState = CeFunction::InitializeState_Initialized; /*if (!ceFunction->mCode.IsEmpty()) { @@ -6980,8 +7011,8 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f CeFunction* ceFunction = NULL; if (!mFunctions.TryAdd(methodInstance, NULL, &functionInfoPtr)) { - ceFunctionInfo = *functionInfoPtr; - BF_ASSERT(ceFunctionInfo->mCeFunction != NULL); + ceFunctionInfo = *functionInfoPtr; + BF_ASSERT(ceFunctionInfo->mCeFunction != NULL); return ceFunctionInfo->mCeFunction; } @@ -7048,7 +7079,7 @@ CeFunction* CeMachine::GetPreparedFunction(BfMethodInstance* methodInstance) auto ceFunction = GetFunction(methodInstance, BfIRValue(), added); if (ceFunction == NULL) return NULL; - if (!ceFunction->mInitialized) + if (ceFunction->mInitializeState < CeFunction::InitializeState_Initialized) PrepareFunction(ceFunction, NULL); return ceFunction; } diff --git a/IDEHelper/Compiler/CeMachine.h b/IDEHelper/Compiler/CeMachine.h index 0400e3e8..071b1e4a 100644 --- a/IDEHelper/Compiler/CeMachine.h +++ b/IDEHelper/Compiler/CeMachine.h @@ -395,14 +395,22 @@ public: class CeFunction { +public: + enum InitializeState + { + InitializeState_None, + InitializeState_Initializing, + InitializeState_Initializing_ReEntry, + InitializeState_Initialized + }; + public: CeMachine* mCeMachine; CeFunctionInfo* mCeFunctionInfo; CeInnerFunctionInfo* mCeInnerFunctionInfo; BfMethodInstance* mMethodInstance; - CeFunctionKind mFunctionKind; - bool mGenerating; - bool mInitialized; + CeFunctionKind mFunctionKind; + InitializeState mInitializeState; bool mFailed; bool mIsVarReturn; Array mCode; @@ -425,9 +433,8 @@ public: mCeMachine = NULL; mCeFunctionInfo = NULL; mCeInnerFunctionInfo = NULL; - mFunctionKind = CeFunctionKind_NotSet; - mGenerating = false; - mInitialized = false; + mFunctionKind = CeFunctionKind_NotSet; + mInitializeState = InitializeState_None; mMethodInstance = NULL; mFailed = false; mIsVarReturn = false; @@ -682,11 +689,13 @@ public: BfMethodInstance* mMethodInstance; String mEmitData; String mExitEmitData; + bool mFailed; CeEmitContext() { mType = NULL; mMethodInstance = NULL; + mFailed = false; } }; @@ -694,6 +703,7 @@ class CeContext { public: CeMachine* mCeMachine; + CeContext* mPrevContext; int mReflectTypeIdOffset; int mExecuteId; CeEvalFlags mCurEvalFlags; diff --git a/IDEHelper/Tests/src/Comptime.bf b/IDEHelper/Tests/src/Comptime.bf index 2fe333cd..385b6fa7 100644 --- a/IDEHelper/Tests/src/Comptime.bf +++ b/IDEHelper/Tests/src/Comptime.bf @@ -84,6 +84,8 @@ namespace Tests struct StructA { public int mA = 123; + public static StructA sSA; + public const StructA cSA = .(); [OnCompile(.TypeInit), Comptime] public static void Generate()