1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 12:32:20 +02:00

Improved variable assignment detection

This commit is contained in:
Brian Fiete 2022-07-05 08:04:38 -07:00
parent a42e0fad60
commit 5277797d73
5 changed files with 206 additions and 55 deletions

View file

@ -342,5 +342,79 @@ namespace IDETest
int b3 = b; //FAIL int b3 = b; //FAIL
int c3 = c; //FAIL int c3 = c; //FAIL
} }
Result<int> 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
}
} }
} }

View file

@ -18952,6 +18952,8 @@ void BfExprEvaluator::CheckResultForReading(BfTypedValue& typedValue)
undefinedFieldFlags = 0; undefinedFieldFlags = 0;
} }
} }
if (deferredLocalAssignData->mLeftBlockUncond)
isAssigned = true;
} }
if (fieldIdx == -1) if (fieldIdx == -1)

View file

@ -133,48 +133,61 @@ void BfDeferredLocalAssignData::BreakExtendChain()
void BfDeferredLocalAssignData::SetIntersection(const BfDeferredLocalAssignData& otherLocalAssignData) void BfDeferredLocalAssignData::SetIntersection(const BfDeferredLocalAssignData& otherLocalAssignData)
{ {
BreakExtendChain(); BreakExtendChain();
for (int i = 0; i < (int)mAssignedLocals.size(); ) if (otherLocalAssignData.mLeftBlockUncond)
{ {
auto& local = mAssignedLocals[i]; // Intersection of self and infinity is self
}
bool wantRemove = true; else if (mLeftBlockUncond)
bool foundOtherFields = false; {
for (auto& otherLocalAssignData : otherLocalAssignData.mAssignedLocals) // Intersection of infinity and other is other
mAssignedLocals = otherLocalAssignData.mAssignedLocals;
}
else
{
for (int i = 0; i < (int)mAssignedLocals.size(); )
{ {
if (otherLocalAssignData.mLocalVar == local.mLocalVar) auto& local = mAssignedLocals[i];
{
if ((otherLocalAssignData.mLocalVarField == local.mLocalVarField) || (otherLocalAssignData.mLocalVarField == -1))
{
if (otherLocalAssignData.mAssignKind == BfLocalVarAssignKind_Conditional)
local.mAssignKind = BfLocalVarAssignKind_Conditional;
wantRemove = false;
}
else
foundOtherFields = true;
}
}
if ((wantRemove) && (foundOtherFields)) bool wantRemove = true;
{ bool foundOtherFields = false;
for (auto& otherLocalAssignData : otherLocalAssignData.mAssignedLocals) for (auto& otherLocalAssignData : otherLocalAssignData.mAssignedLocals)
{ {
if (otherLocalAssignData.mLocalVar == local.mLocalVar) 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) if ((wantRemove) && (foundOtherFields))
{ {
mAssignedLocals.RemoveAt(i); 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; mHadFallthrough = mHadFallthrough && otherLocalAssignData.mHadFallthrough;
mLeftBlockUncond = mLeftBlockUncond && otherLocalAssignData.mLeftBlockUncond;
} }
void BfDeferredLocalAssignData::Validate() const void BfDeferredLocalAssignData::Validate() const
@ -191,7 +204,7 @@ void BfDeferredLocalAssignData::SetUnion(const BfDeferredLocalAssignData& otherL
Validate(); Validate();
otherLocalAssignData.Validate(); otherLocalAssignData.Validate();
auto otherItr = otherLocalAssignData.mAssignedLocals.begin(); auto otherItr = otherLocalAssignData.mAssignedLocals.begin();
while (otherItr != otherLocalAssignData.mAssignedLocals.end()) while (otherItr != otherLocalAssignData.mAssignedLocals.end())
{ {
@ -200,6 +213,7 @@ void BfDeferredLocalAssignData::SetUnion(const BfDeferredLocalAssignData& otherL
++otherItr; ++otherItr;
} }
mHadFallthrough = mHadFallthrough || otherLocalAssignData.mHadFallthrough; mHadFallthrough = mHadFallthrough || otherLocalAssignData.mHadFallthrough;
mLeftBlockUncond = mLeftBlockUncond || otherLocalAssignData.mLeftBlockUncond;
} }
BfMethodState::~BfMethodState() BfMethodState::~BfMethodState()
@ -311,9 +325,36 @@ void BfMethodState::ApplyDeferredLocalAssignData(const BfDeferredLocalAssignData
{ {
BF_ASSERT(&deferredLocalAssignData != mDeferredLocalAssignData); 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);
}
} }
} }

View file

@ -378,6 +378,7 @@ public:
bool mIsIfCondition; bool mIsIfCondition;
bool mIfMayBeSkipped; bool mIfMayBeSkipped;
bool mLeftBlock; bool mLeftBlock;
bool mLeftBlockUncond;
public: public:
BfDeferredLocalAssignData(BfScopeData* scopeData = NULL) BfDeferredLocalAssignData(BfScopeData* scopeData = NULL)
@ -393,6 +394,7 @@ public:
mIsIfCondition = false; mIsIfCondition = false;
mIfMayBeSkipped = false; mIfMayBeSkipped = false;
mLeftBlock = false; mLeftBlock = false;
mLeftBlockUncond = false;
} }
bool Contains(const BfAssignedLocal& val) bool Contains(const BfAssignedLocal& val)
@ -448,6 +450,7 @@ public:
bool mInInitBlock; bool mInInitBlock;
bool mSupressNextUnreachable; bool mSupressNextUnreachable;
bool mInConstIgnore; bool mInConstIgnore;
bool mIsSharedTempBlock;
BfMixinState* mMixinState; BfMixinState* mMixinState;
BfBlock* mAstBlock; BfBlock* mAstBlock;
BfAstNode* mCloseNode; BfAstNode* mCloseNode;
@ -488,6 +491,7 @@ public:
mAllowVariableDeclarations = true; mAllowVariableDeclarations = true;
mInInitBlock = false; mInInitBlock = false;
mInConstIgnore = false; mInConstIgnore = false;
mIsSharedTempBlock = false;
mMixinDepth = 0; mMixinDepth = 0;
mScopeDepth = 0; mScopeDepth = 0;
mScopeLocalId = -1; mScopeLocalId = -1;
@ -1668,7 +1672,7 @@ public:
void AddBasicBlock(BfIRBlock bb, bool activate = true); void AddBasicBlock(BfIRBlock bb, bool activate = true);
void VisitEmbeddedStatement(BfAstNode* stmt, BfExprEvaluator* exprEvaluator = NULL, BfEmbeddedStatementFlags flags = BfEmbeddedStatementFlags_None); void VisitEmbeddedStatement(BfAstNode* stmt, BfExprEvaluator* exprEvaluator = NULL, BfEmbeddedStatementFlags flags = BfEmbeddedStatementFlags_None);
void VisitCodeBlock(BfBlock* block); 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); void DoForLess(BfForEachStatement* forEachStmt);
// Util // Util

View file

@ -3297,7 +3297,7 @@ void BfModule::VisitEmbeddedStatement(BfAstNode* stmt, BfExprEvaluator* exprEval
mCurMethodState->mCurScope->mOuterIsConditional = (flags & BfEmbeddedStatementFlags_IsConditional) != 0; mCurMethodState->mCurScope->mOuterIsConditional = (flags & BfEmbeddedStatementFlags_IsConditional) != 0;
mCurMethodState->mCurScope->mIsDeferredBlock = (flags & BfEmbeddedStatementFlags_IsDeferredBlock) != 0; mCurMethodState->mCurScope->mIsDeferredBlock = (flags & BfEmbeddedStatementFlags_IsDeferredBlock) != 0;
mCurMethodState->mCurScope->mExprEvaluator = exprEvaluator; mCurMethodState->mCurScope->mExprEvaluator = exprEvaluator;
// //
{ {
SetAndRestoreValue<bool> inDeferredBlock(mCurMethodState->mInDeferredBlock, mCurMethodState->mInDeferredBlock || mCurMethodState->mCurScope->mIsDeferredBlock); SetAndRestoreValue<bool> 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; BfBreakData breakData;
breakData.mIRContinueBlock = continueBlock; breakData.mIRContinueBlock = continueBlock;
@ -3355,7 +3355,7 @@ void BfModule::VisitCodeBlock(BfBlock* block, BfIRBlock continueBlock, BfIRBlock
breakData.mPrevBreakData = mCurMethodState->mBreakData; breakData.mPrevBreakData = mCurMethodState->mBreakData;
SetAndRestoreValue<BfBreakData*> prevBreakData(mCurMethodState->mBreakData, &breakData); SetAndRestoreValue<BfBreakData*> prevBreakData(mCurMethodState->mBreakData, &breakData);
Visit(block); VisitEmbeddedStatement(block, NULL, flags);
if (closeScope) if (closeScope)
RestoreScopeState(); RestoreScopeState();
@ -3843,7 +3843,8 @@ void BfModule::DoIfStatement(BfIfStatement* ifStmt, bool includeTrueStmt, bool i
ignoredLastBlock = false; ignoredLastBlock = false;
VisitEmbeddedStatement(ifStmt->mTrueStatement); VisitEmbeddedStatement(ifStmt->mTrueStatement);
} }
prevDLA.Restore(); prevDLA.Restore();
if (mCurMethodState->mDeferredLocalAssignData != NULL) if (mCurMethodState->mDeferredLocalAssignData != NULL)
mCurMethodState->mDeferredLocalAssignData->mHadBreak |= deferredLocalAssignData.mHadBreak; mCurMethodState->mDeferredLocalAssignData->mHadBreak |= deferredLocalAssignData.mHadBreak;
@ -3858,7 +3859,10 @@ void BfModule::DoIfStatement(BfIfStatement* ifStmt, bool includeTrueStmt, bool i
mBfIRBuilder->CreateBr_NoCollapse(contBB); mBfIRBuilder->CreateBr_NoCollapse(contBB);
if (mCurMethodState->mLeftBlockUncond) if (mCurMethodState->mLeftBlockUncond)
{
deferredLocalAssignData.mLeftBlockUncond = true;
mCurMethodState->mLeftBlockCond = true; mCurMethodState->mLeftBlockCond = true;
}
mCurMethodState->mLeftBlockUncond = false; mCurMethodState->mLeftBlockUncond = false;
mCurMethodState->SetHadReturn(false); mCurMethodState->SetHadReturn(false);
@ -3908,7 +3912,10 @@ void BfModule::DoIfStatement(BfIfStatement* ifStmt, bool includeTrueStmt, bool i
} }
falseHadReturn = mCurMethodState->mHadReturn; falseHadReturn = mCurMethodState->mHadReturn;
if (mCurMethodState->mLeftBlockUncond) if (mCurMethodState->mLeftBlockUncond)
{
falseDeferredLocalAssignData.mLeftBlockUncond = true;
mCurMethodState->mLeftBlockCond = true; mCurMethodState->mLeftBlockCond = true;
}
mCurMethodState->mLeftBlockUncond = false; mCurMethodState->mLeftBlockUncond = false;
mCurMethodState->SetHadReturn(false); mCurMethodState->SetHadReturn(false);
@ -4633,6 +4640,7 @@ void BfModule::Visit(BfSwitchStatement* switchStmt)
openedScope = true; openedScope = true;
caseScopeData.mOuterIsConditional = true; caseScopeData.mOuterIsConditional = true;
caseScopeData.mIsSharedTempBlock = true;
mCurMethodState->AddScope(&caseScopeData); mCurMethodState->AddScope(&caseScopeData);
NewScopeState(); NewScopeState();
UpdateSrcPos(caseExpr); UpdateSrcPos(caseExpr);
@ -4915,7 +4923,8 @@ void BfModule::Visit(BfSwitchStatement* switchStmt)
{ {
UpdateSrcPos(switchCase->mCodeBlock); 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; openedScope = false;
deferredLocalAssignDataVec[blockIdx].mHadReturn = hadReturn; deferredLocalAssignDataVec[blockIdx].mHadReturn = hadReturn;
caseCount++; caseCount++;
@ -4953,7 +4962,7 @@ void BfModule::Visit(BfSwitchStatement* switchStmt)
mBfIRBuilder->SetInsertPoint(prevInsertBlock); mBfIRBuilder->SetInsertPoint(prevInsertBlock);
prevHadFallthrough = mCurMethodState->mDeferredLocalAssignData->mHadFallthrough; prevHadFallthrough = mCurMethodState->mDeferredLocalAssignData->mHadFallthrough;
blockIdx++; blockIdx++;
} }
@ -5053,7 +5062,7 @@ void BfModule::Visit(BfSwitchStatement* switchStmt)
mCurMethodState->mDeferredLocalAssignData->mVarIdBarrier = startingLocalVarId; mCurMethodState->mDeferredLocalAssignData->mVarIdBarrier = startingLocalVarId;
bool hadReturn = false; 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; deferredLocalAssignDataVec[blockIdx].mHadReturn = hadReturn;
caseCount++; caseCount++;
if (!hadReturn) if (!hadReturn)
@ -5381,18 +5390,7 @@ void BfModule::Visit(BfBreakStatement* breakStmt)
checkScope = checkScope->mPrevScope; 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)) if (HasDeferredScopeCalls(breakData->mScope))
{ {
EmitDeferredScopeCalls(true, breakData->mScope, breakData->mIRBreakBlock); EmitDeferredScopeCalls(true, breakData->mScope, breakData->mIRBreakBlock);
@ -5403,16 +5401,41 @@ void BfModule::Visit(BfBreakStatement* breakStmt)
} }
mCurMethodState->mLeftBlockUncond = true; mCurMethodState->mLeftBlockUncond = true;
bool isCond = false;
int uncondScopeDepth = 0;
if (mCurMethodState->mCurScope != NULL)
uncondScopeDepth = mCurMethodState->mCurScope->mScopeDepth + 1;
BfIRValue earliestValueScopeStart; BfIRValue earliestValueScopeStart;
auto checkScope = mCurMethodState->mCurScope; auto checkScope = mCurMethodState->mCurScope;
while (checkScope != NULL) while (checkScope != NULL)
{ {
if (!isCond)
uncondScopeDepth = checkScope->mScopeDepth;
if ((checkScope->mOuterIsConditional) && (!checkScope->mIsSharedTempBlock))
isCond = true;
if (checkScope->mValueScopeStart) if (checkScope->mValueScopeStart)
earliestValueScopeStart = checkScope->mValueScopeStart; earliestValueScopeStart = checkScope->mValueScopeStart;
if (checkScope == breakData->mScope) if (checkScope == breakData->mScope)
break; break;
checkScope = checkScope->mPrevScope; 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); MarkScopeLeft(breakData->mScope);
ValueScopeEnd(earliestValueScopeStart); ValueScopeEnd(earliestValueScopeStart);
@ -5734,11 +5757,18 @@ void BfModule::Visit(BfRepeatStatement* repeatStmt)
mBfIRBuilder->CreateBr(bodyBB); mBfIRBuilder->CreateBr(bodyBB);
mBfIRBuilder->SetInsertPoint(bodyBB); mBfIRBuilder->SetInsertPoint(bodyBB);
scopeData.mIsLoop = true; scopeData.mIsLoop = true;
VisitEmbeddedStatement(repeatStmt->mEmbeddedStatement);
BfDeferredLocalAssignData deferredLocalAssignData(mCurMethodState->mCurScope);
deferredLocalAssignData.ExtendFrom(mCurMethodState->mDeferredLocalAssignData, false);
deferredLocalAssignData.mVarIdBarrier = mCurMethodState->GetRootMethodState()->mCurLocalVarId;
SetAndRestoreValue<BfDeferredLocalAssignData*> prevDLA(mCurMethodState->mDeferredLocalAssignData, &deferredLocalAssignData);
VisitEmbeddedStatement(repeatStmt->mEmbeddedStatement);
if (!mCurMethodState->mLeftBlockUncond) if (!mCurMethodState->mLeftBlockUncond)
mBfIRBuilder->CreateBr(condBB); mBfIRBuilder->CreateBr(condBB);
mCurMethodState->SetHadReturn(false); mCurMethodState->SetHadReturn(false);
mCurMethodState->mLeftBlockUncond = false; mCurMethodState->mLeftBlockUncond = false;
mCurMethodState->mLeftBlockCond = false; mCurMethodState->mLeftBlockCond = false;