diff --git a/IDE/Tests/CompileFail001/src/LocalVars.bf b/IDE/Tests/CompileFail001/src/LocalVars.bf index 54361d2d..0cee7ef5 100644 --- a/IDE/Tests/CompileFail001/src/LocalVars.bf +++ b/IDE/Tests/CompileFail001/src/LocalVars.bf @@ -342,5 +342,79 @@ namespace IDETest int b3 = b; //FAIL int c3 = c; //FAIL } + + Result Read() + { + return 0; + } + + public void Local8() + { + int read; + loop: repeat + { + switch (Read()) + { + case .Err: return; + case .Ok(let val): read = val; + } + } + while (read > 0); + } + + public void Local9() + { + int read; + loop: repeat + { + switch (Read()) + { + case .Err: break loop; + case .Ok(let val): read = val; + } + int a = read; + } + while (read > 0); + } + + public void Local10() + { + int read; + loop: repeat + { + switch (Read()) + { + case .Err: break; + case .Ok(let val): read = val; + } + int a = read; //FAIL + } + while (read > 0); //FAIL + } + + public void Local11() + { + int a = 123; + + int read; + Loop: repeat + { + break; + } + while (read > 0); + } + + public void Local12() + { + int a = 123; + + int read; + Loop: repeat + { + if (a == 123) + break; + } + while (read > 0); //FAIL + } } } diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index b8687600..20fdfaca 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -18952,6 +18952,8 @@ void BfExprEvaluator::CheckResultForReading(BfTypedValue& typedValue) undefinedFieldFlags = 0; } } + if (deferredLocalAssignData->mLeftBlockUncond) + isAssigned = true; } if (fieldIdx == -1) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 42726396..8601c7f7 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -133,48 +133,61 @@ void BfDeferredLocalAssignData::BreakExtendChain() void BfDeferredLocalAssignData::SetIntersection(const BfDeferredLocalAssignData& otherLocalAssignData) { BreakExtendChain(); - - for (int i = 0; i < (int)mAssignedLocals.size(); ) + + if (otherLocalAssignData.mLeftBlockUncond) { - auto& local = mAssignedLocals[i]; - - bool wantRemove = true; - bool foundOtherFields = false; - for (auto& otherLocalAssignData : otherLocalAssignData.mAssignedLocals) + // Intersection of self and infinity is self + } + else if (mLeftBlockUncond) + { + // Intersection of infinity and other is other + mAssignedLocals = otherLocalAssignData.mAssignedLocals; + } + else + { + for (int i = 0; i < (int)mAssignedLocals.size(); ) { - if (otherLocalAssignData.mLocalVar == local.mLocalVar) - { - if ((otherLocalAssignData.mLocalVarField == local.mLocalVarField) || (otherLocalAssignData.mLocalVarField == -1)) - { - if (otherLocalAssignData.mAssignKind == BfLocalVarAssignKind_Conditional) - local.mAssignKind = BfLocalVarAssignKind_Conditional; - wantRemove = false; - } - else - foundOtherFields = true; - } - } + auto& local = mAssignedLocals[i]; - if ((wantRemove) && (foundOtherFields)) - { + bool wantRemove = true; + bool foundOtherFields = false; for (auto& otherLocalAssignData : otherLocalAssignData.mAssignedLocals) { if (otherLocalAssignData.mLocalVar == local.mLocalVar) { - mAssignedLocals.Add(otherLocalAssignData); + if ((otherLocalAssignData.mLocalVarField == local.mLocalVarField) || (otherLocalAssignData.mLocalVarField == -1)) + { + if (otherLocalAssignData.mAssignKind == BfLocalVarAssignKind_Conditional) + local.mAssignKind = BfLocalVarAssignKind_Conditional; + wantRemove = false; + } + else + foundOtherFields = true; } } - } - if (wantRemove) - { - mAssignedLocals.RemoveAt(i); + if ((wantRemove) && (foundOtherFields)) + { + for (auto& otherLocalAssignData : otherLocalAssignData.mAssignedLocals) + { + if (otherLocalAssignData.mLocalVar == local.mLocalVar) + { + mAssignedLocals.Add(otherLocalAssignData); + } + } + } + + if (wantRemove) + { + mAssignedLocals.RemoveAt(i); + } + else + i++; } - else - i++; } mHadFallthrough = mHadFallthrough && otherLocalAssignData.mHadFallthrough; + mLeftBlockUncond = mLeftBlockUncond && otherLocalAssignData.mLeftBlockUncond; } void BfDeferredLocalAssignData::Validate() const @@ -191,7 +204,7 @@ void BfDeferredLocalAssignData::SetUnion(const BfDeferredLocalAssignData& otherL Validate(); otherLocalAssignData.Validate(); - + auto otherItr = otherLocalAssignData.mAssignedLocals.begin(); while (otherItr != otherLocalAssignData.mAssignedLocals.end()) { @@ -200,6 +213,7 @@ void BfDeferredLocalAssignData::SetUnion(const BfDeferredLocalAssignData& otherL ++otherItr; } mHadFallthrough = mHadFallthrough || otherLocalAssignData.mHadFallthrough; + mLeftBlockUncond = mLeftBlockUncond || otherLocalAssignData.mLeftBlockUncond; } BfMethodState::~BfMethodState() @@ -311,9 +325,36 @@ void BfMethodState::ApplyDeferredLocalAssignData(const BfDeferredLocalAssignData { BF_ASSERT(&deferredLocalAssignData != mDeferredLocalAssignData); - for (auto& assignedLocal : deferredLocalAssignData.mAssignedLocals) + if (deferredLocalAssignData.mLeftBlockUncond) { - LocalDefined(assignedLocal.mLocalVar, assignedLocal.mLocalVarField, assignedLocal.mAssignKind, true); + if (mLeftBlockUncond) + { + for (int localIdx = 0; localIdx < (int)mLocals.size(); localIdx++) + { + auto localDef = mLocals[localIdx]; + if (localDef->mAssignedKind == BfLocalVarAssignKind_None) + { + bool hadAssignment = false; + if (mDeferredLocalAssignData != NULL) + { + for (auto& entry : mDeferredLocalAssignData->mAssignedLocals) + if (entry.mLocalVar == localDef) + hadAssignment = true; + } + if (!hadAssignment) + { + LocalDefined(localDef); + } + } + } + } + } + else + { + for (auto& assignedLocal : deferredLocalAssignData.mAssignedLocals) + { + LocalDefined(assignedLocal.mLocalVar, assignedLocal.mLocalVarField, assignedLocal.mAssignKind, true); + } } } diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index c13606d4..f76d5d03 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -378,6 +378,7 @@ public: bool mIsIfCondition; bool mIfMayBeSkipped; bool mLeftBlock; + bool mLeftBlockUncond; public: BfDeferredLocalAssignData(BfScopeData* scopeData = NULL) @@ -393,6 +394,7 @@ public: mIsIfCondition = false; mIfMayBeSkipped = false; mLeftBlock = false; + mLeftBlockUncond = false; } bool Contains(const BfAssignedLocal& val) @@ -448,6 +450,7 @@ public: bool mInInitBlock; bool mSupressNextUnreachable; bool mInConstIgnore; + bool mIsSharedTempBlock; BfMixinState* mMixinState; BfBlock* mAstBlock; BfAstNode* mCloseNode; @@ -488,6 +491,7 @@ public: mAllowVariableDeclarations = true; mInInitBlock = false; mInConstIgnore = false; + mIsSharedTempBlock = false; mMixinDepth = 0; mScopeDepth = 0; mScopeLocalId = -1; @@ -1668,7 +1672,7 @@ public: void AddBasicBlock(BfIRBlock bb, bool activate = true); void VisitEmbeddedStatement(BfAstNode* stmt, BfExprEvaluator* exprEvaluator = NULL, BfEmbeddedStatementFlags flags = BfEmbeddedStatementFlags_None); void VisitCodeBlock(BfBlock* block); - void VisitCodeBlock(BfBlock* block, BfIRBlock continueBlock, BfIRBlock breakBlock, BfIRBlock fallthroughBlock, bool defaultBreak, bool* hadReturn = NULL, BfLabelNode* labelNode = NULL, bool closeScope = false); + void VisitCodeBlock(BfBlock* block, BfIRBlock continueBlock, BfIRBlock breakBlock, BfIRBlock fallthroughBlock, bool defaultBreak, bool* hadReturn = NULL, BfLabelNode* labelNode = NULL, bool closeScope = false, BfEmbeddedStatementFlags flags = BfEmbeddedStatementFlags_None); void DoForLess(BfForEachStatement* forEachStmt); // Util diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index db1b8e9b..a646c735 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/IDEHelper/Compiler/BfStmtEvaluator.cpp @@ -3297,7 +3297,7 @@ void BfModule::VisitEmbeddedStatement(BfAstNode* stmt, BfExprEvaluator* exprEval mCurMethodState->mCurScope->mOuterIsConditional = (flags & BfEmbeddedStatementFlags_IsConditional) != 0; mCurMethodState->mCurScope->mIsDeferredBlock = (flags & BfEmbeddedStatementFlags_IsDeferredBlock) != 0; mCurMethodState->mCurScope->mExprEvaluator = exprEvaluator; - + // { SetAndRestoreValue inDeferredBlock(mCurMethodState->mInDeferredBlock, mCurMethodState->mInDeferredBlock || mCurMethodState->mCurScope->mIsDeferredBlock); @@ -3345,7 +3345,7 @@ void BfModule::VisitEmbeddedStatement(BfAstNode* stmt, BfExprEvaluator* exprEval } } -void BfModule::VisitCodeBlock(BfBlock* block, BfIRBlock continueBlock, BfIRBlock breakBlock, BfIRBlock fallthroughBlock, bool defaultBreak, bool* hadReturn, BfLabelNode* labelNode, bool closeScope) +void BfModule::VisitCodeBlock(BfBlock* block, BfIRBlock continueBlock, BfIRBlock breakBlock, BfIRBlock fallthroughBlock, bool defaultBreak, bool* hadReturn, BfLabelNode* labelNode, bool closeScope, BfEmbeddedStatementFlags flags) { BfBreakData breakData; breakData.mIRContinueBlock = continueBlock; @@ -3355,7 +3355,7 @@ void BfModule::VisitCodeBlock(BfBlock* block, BfIRBlock continueBlock, BfIRBlock breakData.mPrevBreakData = mCurMethodState->mBreakData; SetAndRestoreValue prevBreakData(mCurMethodState->mBreakData, &breakData); - Visit(block); + VisitEmbeddedStatement(block, NULL, flags); if (closeScope) RestoreScopeState(); @@ -3843,7 +3843,8 @@ void BfModule::DoIfStatement(BfIfStatement* ifStmt, bool includeTrueStmt, bool i ignoredLastBlock = false; VisitEmbeddedStatement(ifStmt->mTrueStatement); } - prevDLA.Restore(); + prevDLA.Restore(); + if (mCurMethodState->mDeferredLocalAssignData != NULL) mCurMethodState->mDeferredLocalAssignData->mHadBreak |= deferredLocalAssignData.mHadBreak; @@ -3858,7 +3859,10 @@ void BfModule::DoIfStatement(BfIfStatement* ifStmt, bool includeTrueStmt, bool i mBfIRBuilder->CreateBr_NoCollapse(contBB); if (mCurMethodState->mLeftBlockUncond) + { + deferredLocalAssignData.mLeftBlockUncond = true; mCurMethodState->mLeftBlockCond = true; + } mCurMethodState->mLeftBlockUncond = false; mCurMethodState->SetHadReturn(false); @@ -3908,7 +3912,10 @@ void BfModule::DoIfStatement(BfIfStatement* ifStmt, bool includeTrueStmt, bool i } falseHadReturn = mCurMethodState->mHadReturn; if (mCurMethodState->mLeftBlockUncond) + { + falseDeferredLocalAssignData.mLeftBlockUncond = true; mCurMethodState->mLeftBlockCond = true; + } mCurMethodState->mLeftBlockUncond = false; mCurMethodState->SetHadReturn(false); @@ -4633,6 +4640,7 @@ void BfModule::Visit(BfSwitchStatement* switchStmt) openedScope = true; caseScopeData.mOuterIsConditional = true; + caseScopeData.mIsSharedTempBlock = true; mCurMethodState->AddScope(&caseScopeData); NewScopeState(); UpdateSrcPos(caseExpr); @@ -4915,7 +4923,8 @@ void BfModule::Visit(BfSwitchStatement* switchStmt) { UpdateSrcPos(switchCase->mCodeBlock); - VisitCodeBlock(switchCase->mCodeBlock, BfIRBlock(), endBlock, fallthroughBlock, true, &hadReturn, switchStmt->mLabelNode, openedScope); + VisitCodeBlock(switchCase->mCodeBlock, BfIRBlock(), endBlock, fallthroughBlock, true, &hadReturn, switchStmt->mLabelNode, openedScope /*, BfEmbeddedStatementFlags_RescopeDLA*/); + openedScope = false; deferredLocalAssignDataVec[blockIdx].mHadReturn = hadReturn; caseCount++; @@ -4953,7 +4962,7 @@ void BfModule::Visit(BfSwitchStatement* switchStmt) mBfIRBuilder->SetInsertPoint(prevInsertBlock); - prevHadFallthrough = mCurMethodState->mDeferredLocalAssignData->mHadFallthrough; + prevHadFallthrough = mCurMethodState->mDeferredLocalAssignData->mHadFallthrough; blockIdx++; } @@ -5053,7 +5062,7 @@ void BfModule::Visit(BfSwitchStatement* switchStmt) mCurMethodState->mDeferredLocalAssignData->mVarIdBarrier = startingLocalVarId; bool hadReturn = false; - VisitCodeBlock(switchCase->mCodeBlock, BfIRBlock(), endBlock, BfIRBlock(), true, &hadReturn, switchStmt->mLabelNode); + VisitCodeBlock(switchCase->mCodeBlock, BfIRBlock(), endBlock, BfIRBlock(), true, &hadReturn, switchStmt->mLabelNode); deferredLocalAssignDataVec[blockIdx].mHadReturn = hadReturn; caseCount++; if (!hadReturn) @@ -5381,18 +5390,7 @@ void BfModule::Visit(BfBreakStatement* breakStmt) checkScope = checkScope->mPrevScope; } } - - auto checkLocalAssignData = mCurMethodState->mDeferredLocalAssignData; - while (checkLocalAssignData != NULL) - { - if ((checkLocalAssignData->mScopeData != NULL) && (checkLocalAssignData->mScopeData->mScopeDepth >= breakData->mScope->mScopeDepth)) - { - checkLocalAssignData->mLeftBlock = true; - checkLocalAssignData->mHadBreak = true; - } - checkLocalAssignData = checkLocalAssignData->mChainedAssignData; - } - + if (HasDeferredScopeCalls(breakData->mScope)) { EmitDeferredScopeCalls(true, breakData->mScope, breakData->mIRBreakBlock); @@ -5403,16 +5401,41 @@ void BfModule::Visit(BfBreakStatement* breakStmt) } mCurMethodState->mLeftBlockUncond = true; + bool isCond = false; + int uncondScopeDepth = 0; + if (mCurMethodState->mCurScope != NULL) + uncondScopeDepth = mCurMethodState->mCurScope->mScopeDepth + 1; + BfIRValue earliestValueScopeStart; auto checkScope = mCurMethodState->mCurScope; while (checkScope != NULL) - { + { + if (!isCond) + uncondScopeDepth = checkScope->mScopeDepth; + if ((checkScope->mOuterIsConditional) && (!checkScope->mIsSharedTempBlock)) + isCond = true; + if (checkScope->mValueScopeStart) earliestValueScopeStart = checkScope->mValueScopeStart; if (checkScope == breakData->mScope) break; + checkScope = checkScope->mPrevScope; } + + auto checkLocalAssignData = mCurMethodState->mDeferredLocalAssignData; + while (checkLocalAssignData != NULL) + { + if ((checkLocalAssignData->mScopeData != NULL) && (checkLocalAssignData->mScopeData->mScopeDepth >= breakData->mScope->mScopeDepth)) + { + if (checkLocalAssignData->mScopeData->mScopeDepth >= uncondScopeDepth) + checkLocalAssignData->mLeftBlockUncond = true; + checkLocalAssignData->mLeftBlock = true; + checkLocalAssignData->mHadBreak = true; + } + checkLocalAssignData = checkLocalAssignData->mChainedAssignData; + } + MarkScopeLeft(breakData->mScope); ValueScopeEnd(earliestValueScopeStart); @@ -5734,11 +5757,18 @@ void BfModule::Visit(BfRepeatStatement* repeatStmt) mBfIRBuilder->CreateBr(bodyBB); mBfIRBuilder->SetInsertPoint(bodyBB); - scopeData.mIsLoop = true; - VisitEmbeddedStatement(repeatStmt->mEmbeddedStatement); + scopeData.mIsLoop = true; + + BfDeferredLocalAssignData deferredLocalAssignData(mCurMethodState->mCurScope); + deferredLocalAssignData.ExtendFrom(mCurMethodState->mDeferredLocalAssignData, false); + deferredLocalAssignData.mVarIdBarrier = mCurMethodState->GetRootMethodState()->mCurLocalVarId; + SetAndRestoreValue prevDLA(mCurMethodState->mDeferredLocalAssignData, &deferredLocalAssignData); + + VisitEmbeddedStatement(repeatStmt->mEmbeddedStatement); + if (!mCurMethodState->mLeftBlockUncond) mBfIRBuilder->CreateBr(condBB); - mCurMethodState->SetHadReturn(false); + mCurMethodState->SetHadReturn(false); mCurMethodState->mLeftBlockUncond = false; mCurMethodState->mLeftBlockCond = false;