mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 03:28:20 +02:00
Improved circular mixin check, isconst(expr), [ConstSkip]
This commit is contained in:
parent
cab9b3d9c7
commit
75333a0928
19 changed files with 241 additions and 60 deletions
|
@ -172,6 +172,12 @@ namespace System
|
|||
|
||||
}
|
||||
|
||||
|
||||
[AttributeUsage(.Block)]
|
||||
public struct ConstSkipAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(.Block)]
|
||||
public struct IgnoreErrorsAttribute : Attribute
|
||||
{
|
||||
|
@ -316,7 +322,7 @@ namespace System
|
|||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(.Method /*2*/)]
|
||||
public struct IntrinsicAttribute : Attribute
|
||||
|
|
|
@ -1042,7 +1042,7 @@ namespace System
|
|||
{
|
||||
if (object == null)
|
||||
return;
|
||||
Append(object.ToString(.. scope .()));
|
||||
Append(object.ToString(.. scope .(128)));
|
||||
}
|
||||
|
||||
public void operator+=(String str)
|
||||
|
|
|
@ -145,6 +145,11 @@ namespace System
|
|||
|
||||
}
|
||||
|
||||
[AttributeUsage(.Block)]
|
||||
public struct ConstSkipAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(.Block)]
|
||||
public struct IgnoreErrorsAttribute : Attribute
|
||||
{
|
||||
|
|
|
@ -356,6 +356,11 @@ void BfStructuralVisitor::Visit(BfOffsetOfExpression* offsetOfExpr)
|
|||
Visit(offsetOfExpr->ToBase());
|
||||
}
|
||||
|
||||
void BfStructuralVisitor::Visit(BfIsConstExpression* isConstExpr)
|
||||
{
|
||||
Visit(isConstExpr->ToBase());
|
||||
}
|
||||
|
||||
void BfStructuralVisitor::Visit(BfDefaultExpression* defaultExpr)
|
||||
{
|
||||
Visit(defaultExpr->ToBase());
|
||||
|
@ -1398,6 +1403,8 @@ const char* Beefy::BfTokenToString(BfToken token)
|
|||
return "internal";
|
||||
case BfToken_Is:
|
||||
return "is";
|
||||
case BfToken_IsConst:
|
||||
return "isconst";
|
||||
case BfToken_Let:
|
||||
return "let";
|
||||
case BfToken_Mixin:
|
||||
|
|
|
@ -158,6 +158,7 @@ enum BfToken : uint8
|
|||
BfToken_Interface,
|
||||
BfToken_Internal,
|
||||
BfToken_Is,
|
||||
BfToken_IsConst,
|
||||
BfToken_Let,
|
||||
BfToken_Mixin,
|
||||
BfToken_Mut,
|
||||
|
@ -380,6 +381,7 @@ class BfSizeOfExpression;
|
|||
class BfAlignOfExpression;
|
||||
class BfOffsetOfExpression;
|
||||
class BfStrideOfExpression;
|
||||
class BfIsConstExpression;
|
||||
class BfDefaultExpression;
|
||||
class BfUninitializedExpression;
|
||||
class BfConditionalExpression;
|
||||
|
@ -504,6 +506,7 @@ public:
|
|||
virtual void Visit(BfAlignOfExpression* alignOfExpr);
|
||||
virtual void Visit(BfStrideOfExpression* strideOfExpr);
|
||||
virtual void Visit(BfOffsetOfExpression* offsetOfExpr);
|
||||
virtual void Visit(BfIsConstExpression* isConstExpr);
|
||||
virtual void Visit(BfDefaultExpression* defaultExpr);
|
||||
virtual void Visit(BfUninitializedExpression* uninitializedExpr);
|
||||
virtual void Visit(BfCheckTypeExpression* checkTypeExpr);
|
||||
|
@ -2688,9 +2691,10 @@ public:
|
|||
class BfStrideOfExpression : public BfTypeAttrExpression
|
||||
{
|
||||
public:
|
||||
BF_AST_TYPE(BfStrideOfExpression, BfTypeAttrExpression);
|
||||
BF_AST_TYPE(BfStrideOfExpression, BfTypeAttrExpression);
|
||||
}; BF_AST_DECL(BfStrideOfExpression, BfTypeAttrExpression);
|
||||
|
||||
|
||||
class BfOffsetOfExpression : public BfTypeAttrExpression
|
||||
{
|
||||
public:
|
||||
|
@ -2700,6 +2704,17 @@ public:
|
|||
BfIdentifierNode* mMemberName;
|
||||
}; BF_AST_DECL(BfOffsetOfExpression, BfTypeAttrExpression);
|
||||
|
||||
class BfIsConstExpression : public BfExpression
|
||||
{
|
||||
public:
|
||||
BF_AST_TYPE(BfIsConstExpression, BfTypeAttrExpression);
|
||||
|
||||
BfTokenNode* mIsConstToken;
|
||||
BfTokenNode* mOpenParen;
|
||||
BfExpression* mExpression;
|
||||
BfTokenNode* mCloseParen;
|
||||
}; BF_AST_DECL(BfIsConstExpression, BfTypeAttrExpression);
|
||||
|
||||
class BfDefaultExpression : public BfExpression
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -1718,7 +1718,7 @@ void BfAutoComplete::CheckIdentifier(BfAstNode* identifierNode, bool isInExpress
|
|||
{
|
||||
"alignof", "as", "asm", "base", "break", "case", "catch", "checked", "continue", "default", "defer",
|
||||
"delegate", "delete", "do", "else", "false", "finally",
|
||||
"fixed", "for", "function", "if", "implicit", "in", "internal", "is", "new", "mixin", "null",
|
||||
"fixed", "for", "function", "if", "implicit", "in", "internal", "is", "isconst", "new", "mixin", "null",
|
||||
"offsetof", "out", "params", "ref", "rettype", "return",
|
||||
"sealed", "sizeof", "scope", "static", "strideof", "struct", "switch", /*"this",*/ "try", "true", "typeof", "unchecked",
|
||||
"using", "var", "virtual", "volatile", "where", "while",
|
||||
|
@ -3570,6 +3570,8 @@ String BfAutoComplete::ConstantToString(BfIRConstHolder* constHolder, BfIRValue
|
|||
auto constant = constHolder->GetConstant(id);
|
||||
switch (constant->mTypeCode)
|
||||
{
|
||||
case BfTypeCode_Boolean:
|
||||
return StrFormat(":(bool) %s", constant->mBool ? "true" : "false");
|
||||
case BfTypeCode_UInt8:
|
||||
return StrFormat(":(uint8) %llu", constant->mUInt64);
|
||||
case BfTypeCode_UInt16:
|
||||
|
|
|
@ -474,6 +474,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
|
|||
mObsoleteAttributeTypeDef = NULL;
|
||||
mErrorAttributeTypeDef = NULL;
|
||||
mWarnAttributeTypeDef = NULL;
|
||||
mConstSkipAttributeTypeDef = NULL;
|
||||
mIgnoreErrorsAttributeTypeDef = NULL;
|
||||
mReflectAttributeTypeDef = NULL;
|
||||
mOnCompileAttributeTypeDef = NULL;
|
||||
|
@ -7104,6 +7105,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
|
|||
mObsoleteAttributeTypeDef = _GetRequiredType("System.ObsoleteAttribute");
|
||||
mErrorAttributeTypeDef = _GetRequiredType("System.ErrorAttribute");
|
||||
mWarnAttributeTypeDef = _GetRequiredType("System.WarnAttribute");
|
||||
mConstSkipAttributeTypeDef = _GetRequiredType("System.ConstSkipAttribute");
|
||||
mIgnoreErrorsAttributeTypeDef = _GetRequiredType("System.IgnoreErrorsAttribute");
|
||||
mReflectAttributeTypeDef = _GetRequiredType("System.ReflectAttribute");
|
||||
mOnCompileAttributeTypeDef = _GetRequiredType("System.OnCompileAttribute");
|
||||
|
|
|
@ -454,6 +454,7 @@ public:
|
|||
BfTypeDef* mObsoleteAttributeTypeDef;
|
||||
BfTypeDef* mErrorAttributeTypeDef;
|
||||
BfTypeDef* mWarnAttributeTypeDef;
|
||||
BfTypeDef* mConstSkipAttributeTypeDef;
|
||||
BfTypeDef* mIgnoreErrorsAttributeTypeDef;
|
||||
BfTypeDef* mReflectAttributeTypeDef;
|
||||
BfTypeDef* mOnCompileAttributeTypeDef;
|
||||
|
|
|
@ -528,6 +528,16 @@ void BfElementVisitor::Visit(BfDefaultExpression* defaultExpr)
|
|||
VisitChild(defaultExpr->mCloseParen);
|
||||
}
|
||||
|
||||
void BfElementVisitor::Visit(BfIsConstExpression* isConstExpr)
|
||||
{
|
||||
Visit(isConstExpr->ToBase());
|
||||
|
||||
VisitChild(isConstExpr->mIsConstToken);
|
||||
VisitChild(isConstExpr->mOpenParen);
|
||||
VisitChild(isConstExpr->mExpression);
|
||||
VisitChild(isConstExpr->mCloseParen);
|
||||
}
|
||||
|
||||
void BfElementVisitor::Visit(BfUninitializedExpression* uninitializedExpr)
|
||||
{
|
||||
Visit(uninitializedExpr->ToBase());
|
||||
|
|
|
@ -72,6 +72,7 @@ public:
|
|||
virtual void Visit(BfTypeAttrExpression* typeAttrExpr);
|
||||
virtual void Visit(BfOffsetOfExpression* offsetOfExpr);
|
||||
virtual void Visit(BfDefaultExpression* defaultExpr);
|
||||
virtual void Visit(BfIsConstExpression* isConstExpr);
|
||||
virtual void Visit(BfUninitializedExpression* uninitializedExpr);
|
||||
virtual void Visit(BfCheckTypeExpression* checkTypeExpr);
|
||||
virtual void Visit(BfDynamicCastExpression* dynCastExpr);
|
||||
|
|
|
@ -3317,7 +3317,7 @@ void BfExprEvaluator::Visit(BfAttributedExpression* attribExpr)
|
|||
attributeState.mSrc = attribExpr->mAttributes;
|
||||
attributeState.mTarget = (BfAttributeTargets)(BfAttributeTargets_Invocation | BfAttributeTargets_MemberAccess);
|
||||
if (auto block = BfNodeDynCast<BfBlock>(attribExpr->mExpression))
|
||||
attributeState.mTarget = BfAttributeTargets_Block;
|
||||
attributeState.mTarget = BfAttributeTargets_Block;
|
||||
|
||||
attributeState.mCustomAttributes = mModule->GetCustomAttributes(attribExpr->mAttributes, attributeState.mTarget);
|
||||
SetAndRestoreValue<BfAttributeState*> prevAttributeState(mModule->mAttributeState, &attributeState);
|
||||
|
@ -3344,6 +3344,19 @@ void BfExprEvaluator::Visit(BfAttributedExpression* attribExpr)
|
|||
mResult = mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Boolean));
|
||||
}
|
||||
}
|
||||
else if (attributeState.mCustomAttributes->Contains(mModule->mCompiler->mConstSkipAttributeTypeDef))
|
||||
{
|
||||
if ((mModule->mCurMethodState == NULL) || (mModule->mCurMethodState->mCurScope == NULL) || (!mModule->mCurMethodState->mCurScope->mInConstIgnore))
|
||||
{
|
||||
VisitChild(attribExpr->mExpression);
|
||||
}
|
||||
else
|
||||
{
|
||||
BF_ASSERT(mModule->mBfIRBuilder->mIgnoreWrites);
|
||||
mResult = mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Var));
|
||||
}
|
||||
attributeState.mUsed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
VisitChild(attribExpr->mExpression);
|
||||
|
@ -11480,7 +11493,6 @@ void BfExprEvaluator::DoTypeIntAttr(BfTypeReference* typeRef, BfTokenNode* comma
|
|||
{
|
||||
auto autoComplete = GetAutoComplete();
|
||||
|
||||
|
||||
auto type = mModule->ResolveTypeRef(typeRef, BfPopulateType_Data, BfResolveTypeRefFlag_AutoComplete);
|
||||
if (type == NULL)
|
||||
return;
|
||||
|
@ -11612,6 +11624,30 @@ void BfExprEvaluator::Visit(BfOffsetOfExpression* offsetOfExpr)
|
|||
DoTypeIntAttr(offsetOfExpr->mTypeRef, offsetOfExpr->mCommaToken, offsetOfExpr->mMemberName, BfToken_OffsetOf);
|
||||
}
|
||||
|
||||
void BfExprEvaluator::Visit(BfIsConstExpression* isConstExpr)
|
||||
{
|
||||
if (isConstExpr->mExpression == NULL)
|
||||
{
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), mModule->GetPrimitiveType(BfTypeCode_Boolean));
|
||||
return;
|
||||
}
|
||||
|
||||
BfMethodState methodState;
|
||||
SetAndRestoreValue<BfMethodState*> prevMethodState(mModule->mCurMethodState, &methodState, false);
|
||||
if (mModule->mCurMethodState == NULL)
|
||||
prevMethodState.Set();
|
||||
methodState.mTempKind = BfMethodState::TempKind_NonStatic;
|
||||
|
||||
SetAndRestoreValue<bool> ignoreWrites(mModule->mBfIRBuilder->mIgnoreWrites, true);
|
||||
SetAndRestoreValue<bool> allowUninitReads(mModule->mCurMethodState->mAllowUinitReads, true);
|
||||
|
||||
BfEvalExprFlags exprFlags = BfEvalExprFlags_None;
|
||||
|
||||
auto result = mModule->CreateValueFromExpression(isConstExpr->mExpression, NULL, BfEvalExprFlags_DeclType);
|
||||
bool isConst = mModule->mBfIRBuilder->IsConstValue(result.mValue);
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, isConst ? 1 : 0), mModule->GetPrimitiveType(BfTypeCode_Boolean));
|
||||
}
|
||||
|
||||
void BfExprEvaluator::Visit(BfDefaultExpression* defaultExpr)
|
||||
{
|
||||
auto autoComplete = GetAutoComplete();
|
||||
|
@ -11669,7 +11705,7 @@ void BfExprEvaluator::Visit(BfCheckTypeExpression* checkTypeExpr)
|
|||
if (autoComplete != NULL)
|
||||
autoComplete->CheckTypeRef(checkTypeExpr->mTypeRef, false, true);
|
||||
|
||||
auto targetType = mModule->ResolveTypeRef(checkTypeExpr->mTypeRef);
|
||||
auto targetType = mModule->ResolveTypeRef(checkTypeExpr->mTypeRef, BfPopulateType_Declaration);
|
||||
if (!targetType)
|
||||
{
|
||||
mModule->AssertErrorState();
|
||||
|
@ -16442,41 +16478,6 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo
|
|||
}
|
||||
|
||||
auto curMethodState = mModule->mCurMethodState;
|
||||
//
|
||||
|
||||
// Why was this required? It doesn't check for matching generic args (we only want to throw an error if we call back into a mixin with the same generic args as before)
|
||||
// {
|
||||
// bool hasCircularRef = false;
|
||||
//
|
||||
// auto checkMethodState = curMethodState;
|
||||
// while (checkMethodState != NULL)
|
||||
// {
|
||||
// auto curMixinState = checkMethodState->mMixinState;
|
||||
// while (curMixinState != NULL)
|
||||
// {
|
||||
// if (curMixinState->mSource == targetSrc)
|
||||
// hasCircularRef = true;
|
||||
// curMixinState = curMixinState->mPrevMixinState;
|
||||
// }
|
||||
//
|
||||
// if ((checkMethodState->mClosureState != NULL) && (checkMethodState->mClosureState->mActiveDeferredLocalMethod != NULL))
|
||||
// {
|
||||
// for (auto& mixinRecord : checkMethodState->mClosureState->mActiveDeferredLocalMethod->mMixinStateRecords)
|
||||
// {
|
||||
// if (mixinRecord.mSource == targetSrc)
|
||||
// hasCircularRef = true;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// checkMethodState = checkMethodState->mPrevMethodState;
|
||||
// }
|
||||
//
|
||||
// if (hasCircularRef)
|
||||
// {
|
||||
// mModule->Fail("Circular reference detected between mixins", targetSrc);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
auto moduleMethodInstance = GetSelectedMethod(targetSrc, methodMatcher.mBestMethodTypeInstance, methodMatcher.mBestMethodDef, methodMatcher);
|
||||
if (!moduleMethodInstance)
|
||||
|
@ -16522,30 +16523,78 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo
|
|||
}
|
||||
}
|
||||
|
||||
// Check circular ref based on methodInstance
|
||||
if (curMethodState->mCurScope->mMixinDepth >= 128)
|
||||
{
|
||||
mModule->Fail("Maximum nested mixin depth exceeded", targetSrc);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check circular ref based on methodInstance. We must check the arg types since we could be making progress in mixin evaluation
|
||||
// based on method selection within the mixin dependent on args
|
||||
{
|
||||
bool hasCircularRef = false;
|
||||
|
||||
BfMixinState* checkMixinState = NULL;
|
||||
|
||||
auto checkMethodState = curMethodState;
|
||||
while (checkMethodState != NULL)
|
||||
{
|
||||
if (checkMethodState->mMethodInstance == methodInstance)
|
||||
hasCircularRef = true;
|
||||
|
||||
{
|
||||
auto curMixinState = checkMethodState->mMixinState;
|
||||
while (curMixinState != NULL)
|
||||
{
|
||||
if (curMixinState->mMixinMethodInstance == methodInstance)
|
||||
hasCircularRef = true;
|
||||
if ((curMixinState->mDoCircularVarResult) && (curMixinState->mMixinMethodInstance == methodInstance))
|
||||
{
|
||||
mResult = mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Var));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((!curMixinState->mCheckedCircularRef) && (curMixinState->mMixinMethodInstance == methodInstance))
|
||||
{
|
||||
checkMixinState = curMixinState;
|
||||
checkMixinState->mCheckedCircularRef = true;
|
||||
}
|
||||
else if (checkMixinState != NULL)
|
||||
{
|
||||
if ((curMixinState->mMixinMethodInstance == checkMixinState->mMixinMethodInstance) &&
|
||||
(curMixinState->mArgTypes == checkMixinState->mArgTypes) &&
|
||||
(curMixinState->mArgConsts.mSize == checkMixinState->mArgConsts.mSize))
|
||||
{
|
||||
bool constsMatch = true;
|
||||
|
||||
for (int i = 0; i < curMixinState->mArgConsts.mSize; i++)
|
||||
{
|
||||
if (!mModule->mBfIRBuilder->CheckConstEquality(curMixinState->mArgConsts[i], checkMixinState->mArgConsts[i]))
|
||||
{
|
||||
constsMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (constsMatch)
|
||||
hasCircularRef = true;
|
||||
}
|
||||
}
|
||||
|
||||
curMixinState = curMixinState->mPrevMixinState;
|
||||
}
|
||||
|
||||
|
||||
checkMethodState = checkMethodState->mPrevMethodState;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasCircularRef)
|
||||
{
|
||||
for (auto argType : checkMixinState->mArgTypes)
|
||||
{
|
||||
if (argType->IsVar())
|
||||
checkMixinState->mDoCircularVarResult = true;
|
||||
}
|
||||
|
||||
if (checkMixinState->mDoCircularVarResult)
|
||||
{
|
||||
mResult = mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Var));
|
||||
return;
|
||||
}
|
||||
|
||||
mModule->Fail("Circular reference detected between mixins", targetSrc);
|
||||
return;
|
||||
}
|
||||
|
@ -16981,6 +17030,9 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo
|
|||
}
|
||||
|
||||
newLocalVar->mParamIdx = -3;
|
||||
mixinState->mArgTypes.Add(newLocalVar->mResolvedType);
|
||||
if (mModule->mBfIRBuilder->IsConstValue(newLocalVar->mConstValue))
|
||||
mixinState->mArgConsts.Add(newLocalVar->mConstValue);
|
||||
};
|
||||
|
||||
argExprEvaluatorItr = argExprEvaluators.begin();
|
||||
|
@ -18993,13 +19045,14 @@ void BfExprEvaluator::Visit(BfConditionalExpression* condExpr)
|
|||
{
|
||||
auto curBlock = mModule->mBfIRBuilder->GetInsertBlock();
|
||||
SetAndRestoreValue<bool> ignoreWrites(mModule->mBfIRBuilder->mIgnoreWrites, true);
|
||||
SetAndRestoreValue<bool> prevInConstIgnore(mModule->mCurMethodState->mCurScope->mInConstIgnore, true);
|
||||
ignoredValue = mModule->CreateValueFromExpression(ignoredExpr, mExpectingType, (BfEvalExprFlags)((mBfEvalExprFlags & BfEvalExprFlags_InheritFlags) | BfEvalExprFlags_NoCast));
|
||||
mModule->mBfIRBuilder->SetInsertPoint(curBlock);
|
||||
}
|
||||
|
||||
if (!actualValue)
|
||||
return;
|
||||
if ((ignoredValue) && (ignoredValue.mType != actualValue.mType))
|
||||
if ((ignoredValue) && (ignoredValue.mType != actualValue.mType) && (!ignoredValue.mType->IsVar()))
|
||||
{
|
||||
// Cast to more specific 'ignored' type if applicable
|
||||
if (mModule->CanCast(actualValue, ignoredValue.mType))
|
||||
|
@ -19078,7 +19131,7 @@ void BfExprEvaluator::Visit(BfConditionalExpression* condExpr)
|
|||
{
|
||||
BfTypedValue trueToFalse;
|
||||
{
|
||||
SetAndRestoreValue<bool> prevIgnoreError(mModule->mIgnoreErrors, true);
|
||||
SetAndRestoreValue<bool> prevIgnoreError(mModule->mIgnoreErrors, true);
|
||||
mModule->mBfIRBuilder->SetInsertPoint(trueBlockPos);
|
||||
trueToFalse = mModule->Cast(condExpr->mTrueExpression, trueValue, falseValue.mType);
|
||||
}
|
||||
|
@ -22078,7 +22131,8 @@ void BfExprEvaluator::PerformBinaryOperation(BfExpression* leftExpression, BfExp
|
|||
else
|
||||
{
|
||||
// Always false
|
||||
SetAndRestoreValue<bool> prevIgnoreWrites(mModule->mBfIRBuilder->mIgnoreWrites, true);
|
||||
SetAndRestoreValue<bool> prevIgnoreWrites(mModule->mBfIRBuilder->mIgnoreWrites, true);
|
||||
SetAndRestoreValue<bool> prevInConstIgnore(mModule->mCurMethodState->mCurScope->mInConstIgnore, true);
|
||||
rightValue = mModule->CreateValueFromExpression(rightExpression, boolType, (BfEvalExprFlags)(mBfEvalExprFlags & BfEvalExprFlags_InheritFlags));
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), boolType);
|
||||
}
|
||||
|
@ -22131,6 +22185,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfExpression* leftExpression, BfExp
|
|||
{
|
||||
// Always true
|
||||
SetAndRestoreValue<bool> prevIgnoreWrites(mModule->mBfIRBuilder->mIgnoreWrites, true);
|
||||
SetAndRestoreValue<bool> prevInConstIgnore(mModule->mCurMethodState->mCurScope->mInConstIgnore, true);
|
||||
rightValue = mModule->CreateValueFromExpression(rightExpression, boolType, (BfEvalExprFlags)(mBfEvalExprFlags & BfEvalExprFlags_InheritFlags));
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 1), boolType);
|
||||
}
|
||||
|
@ -22208,6 +22263,7 @@ bool BfExprEvaluator::PerformBinaryOperation_NullCoalesce(BfTokenNode* opToken,
|
|||
|
||||
// Already have a value, we don't need the right side
|
||||
SetAndRestoreValue<bool> prevIgnoreWrites(mModule->mBfIRBuilder->mIgnoreWrites, true);
|
||||
SetAndRestoreValue<bool> prevInConstIgnore(mModule->mCurMethodState->mCurScope->mInConstIgnore, true);
|
||||
mModule->CreateValueFromExpression(rightExpression, wantType, (BfEvalExprFlags)((mBfEvalExprFlags & BfEvalExprFlags_InheritFlags) | BfEvalExprFlags_CreateConditionalScope));
|
||||
mResult = leftValue;
|
||||
return true;
|
||||
|
|
|
@ -547,8 +547,9 @@ public:
|
|||
virtual void Visit(BfTypeOfExpression* typeOfExpr) override;
|
||||
virtual void Visit(BfSizeOfExpression* sizeOfExpr) override;
|
||||
virtual void Visit(BfAlignOfExpression* alignOfExpr) override;
|
||||
virtual void Visit(BfStrideOfExpression* strideOfExpr) override;
|
||||
virtual void Visit(BfStrideOfExpression* strideOfExpr) override;
|
||||
virtual void Visit(BfOffsetOfExpression* offsetOfExpr) override;
|
||||
virtual void Visit(BfIsConstExpression* isConstExpr) override;
|
||||
virtual void Visit(BfDefaultExpression* defaultExpr) override;
|
||||
virtual void Visit(BfUninitializedExpression* uninitialziedExpr) override;
|
||||
virtual void Visit(BfCheckTypeExpression* checkTypeExpr) override;
|
||||
|
|
|
@ -445,6 +445,7 @@ public:
|
|||
bool mAllowVariableDeclarations;
|
||||
bool mInInitBlock;
|
||||
bool mSupressNextUnreachable;
|
||||
bool mInConstIgnore;
|
||||
BfMixinState* mMixinState;
|
||||
BfBlock* mAstBlock;
|
||||
BfAstNode* mCloseNode;
|
||||
|
@ -484,6 +485,7 @@ public:
|
|||
mAllowTargeting = true;
|
||||
mAllowVariableDeclarations = true;
|
||||
mInInitBlock = false;
|
||||
mInConstIgnore = false;
|
||||
mMixinDepth = 0;
|
||||
mScopeDepth = 0;
|
||||
mScopeLocalId = -1;
|
||||
|
@ -794,7 +796,7 @@ public:
|
|||
|
||||
class BfMixinState
|
||||
{
|
||||
public:
|
||||
public:
|
||||
BfMixinState* mPrevMixinState;
|
||||
BfAstNode* mSource;
|
||||
BfScopeData* mCallerScope;
|
||||
|
@ -802,15 +804,30 @@ public:
|
|||
BfFilePosition mInjectFilePosition;
|
||||
BfMethodInstance* mMixinMethodInstance;
|
||||
BfAstNode* mResultExpr;
|
||||
SizedArray<BfType*, 8> mArgTypes;
|
||||
SizedArray<BfIRValue, 8> mArgConsts;
|
||||
int mLocalsStartIdx;
|
||||
bool mUsedInvocationScope;
|
||||
bool mHasDeferredUsage;
|
||||
bool mCheckedCircularRef;
|
||||
bool mDoCircularVarResult;
|
||||
BfTypedValue mTarget;
|
||||
int mLastTargetAccessId;
|
||||
|
||||
public:
|
||||
BfMixinState()
|
||||
{
|
||||
mPrevMixinState = NULL;
|
||||
mSource = NULL;
|
||||
mCallerScope = NULL;
|
||||
mTarget = NULL;
|
||||
mMixinMethodInstance = NULL;
|
||||
mResultExpr = NULL;
|
||||
mLocalsStartIdx = 0;
|
||||
mUsedInvocationScope = false;
|
||||
mHasDeferredUsage = false;
|
||||
mCheckedCircularRef = false;
|
||||
mDoCircularVarResult = false;
|
||||
mLastTargetAccessId = -1;
|
||||
}
|
||||
|
||||
|
@ -1126,6 +1143,7 @@ public:
|
|||
newScopeData->mPrevScope = mCurScope;
|
||||
newScopeData->mMixinDepth = mCurScope->mMixinDepth;
|
||||
newScopeData->mScopeDepth = mCurScope->mScopeDepth + 1;
|
||||
newScopeData->mInConstIgnore = mCurScope->mInConstIgnore;
|
||||
mCurScope = newScopeData;
|
||||
mTailScope = mCurScope;
|
||||
}
|
||||
|
|
|
@ -3143,6 +3143,10 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate, bool disablePrepro
|
|||
if ((!mCompatMode) && (SrcPtrHasToken("is")))
|
||||
mToken = BfToken_Is;
|
||||
break;
|
||||
case TOKEN_HASH('i', 's', 'c', 'o'):
|
||||
if ((!mCompatMode) && (SrcPtrHasToken("isconst")))
|
||||
mToken = BfToken_IsConst;
|
||||
break;
|
||||
case TOKEN_HASH('l', 'e', 't', 0):
|
||||
if ((!mCompatMode) && (SrcPtrHasToken("let")))
|
||||
mToken = BfToken_Let;
|
||||
|
|
|
@ -1764,6 +1764,16 @@ void BfPrinter::Visit(BfDefaultExpression* defaultExpr)
|
|||
VisitChild(defaultExpr->mCloseParen);
|
||||
}
|
||||
|
||||
void BfPrinter::Visit(BfIsConstExpression* isConstExpr)
|
||||
{
|
||||
Visit(isConstExpr->ToBase());
|
||||
|
||||
VisitChild(isConstExpr->mIsConstToken);
|
||||
VisitChild(isConstExpr->mOpenParen);
|
||||
VisitChild(isConstExpr->mExpression);
|
||||
VisitChild(isConstExpr->mCloseParen);
|
||||
}
|
||||
|
||||
void BfPrinter::Visit(BfCheckTypeExpression* checkTypeExpr)
|
||||
{
|
||||
Visit(checkTypeExpr->ToBase());
|
||||
|
|
|
@ -175,6 +175,7 @@ public:
|
|||
virtual void Visit(BfSizeOfExpression* sizeOfExpr) override;
|
||||
virtual void Visit(BfOffsetOfExpression* offsetOfExpr) override;
|
||||
virtual void Visit(BfDefaultExpression* defaultExpr) override;
|
||||
virtual void Visit(BfIsConstExpression* isConstExpr) override;
|
||||
virtual void Visit(BfCheckTypeExpression* checkTypeExpr) override;
|
||||
virtual void Visit(BfDynamicCastExpression* dynCastExpr) override;
|
||||
virtual void Visit(BfCastExpression* castExpr) override;
|
||||
|
|
|
@ -1998,6 +1998,19 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
|
|||
|
||||
exprLeft = defaultExpr;
|
||||
}
|
||||
else if (token == BfToken_IsConst)
|
||||
{
|
||||
auto isConstExpr = mAlloc->Alloc<BfIsConstExpression>();
|
||||
ReplaceNode(tokenNode, isConstExpr);
|
||||
isConstExpr->mIsConstToken = tokenNode;
|
||||
tokenNode = ExpectTokenAfter(isConstExpr, BfToken_LParen);
|
||||
MEMBER_SET_CHECKED(isConstExpr, mOpenParen, tokenNode);
|
||||
auto expr = CreateExpressionAfter(isConstExpr);
|
||||
MEMBER_SET_CHECKED(isConstExpr, mExpression, expr);
|
||||
tokenNode = ExpectTokenAfter(isConstExpr, BfToken_RParen);
|
||||
MEMBER_SET_CHECKED(isConstExpr, mCloseParen, tokenNode);
|
||||
exprLeft = isConstExpr;
|
||||
}
|
||||
else if (token == BfToken_Question)
|
||||
{
|
||||
auto uninitExpr = mAlloc->Alloc<BfUninitializedExpression>();
|
||||
|
|
|
@ -3221,6 +3221,7 @@ void BfResolvedTypeSet::HashGenericArguments(BfTypeReference* typeRef, LookupCon
|
|||
}
|
||||
else
|
||||
{
|
||||
ctx->mModule->Fail("Generic argument expected", genericTypeRef->mOpenChevron);
|
||||
ctx->mFailed = true;
|
||||
return;
|
||||
}
|
||||
|
@ -3807,7 +3808,7 @@ int BfResolvedTypeSet::DoHash(BfTypeReference* typeRef, LookupContext* ctx, BfHa
|
|||
else
|
||||
{
|
||||
result = ctx->mModule->CreateValueFromExpression(exprModTypeRef->mTarget, NULL, BfEvalExprFlags_DeclType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((result) && (exprModTypeRef->mToken->mToken == BfToken_Comptype))
|
||||
|
|
|
@ -3742,11 +3742,16 @@ void BfModule::DoIfStatement(BfIfStatement* ifStmt, bool includeTrueStmt, bool i
|
|||
|
||||
if (includeTrueStmt)
|
||||
{
|
||||
SetAndRestoreValue<bool> ignoreWrites(mBfIRBuilder->mIgnoreWrites);
|
||||
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites);
|
||||
SetAndRestoreValue<bool> prevInConstIgnore(mCurMethodState->mCurScope->mInConstIgnore);
|
||||
|
||||
if (trueBB)
|
||||
mBfIRBuilder->SetInsertPoint(trueBB);
|
||||
if ((isConstBranch) && (constResult != true))
|
||||
{
|
||||
mBfIRBuilder->mIgnoreWrites = true;
|
||||
mCurMethodState->mCurScope->mInConstIgnore = true;
|
||||
}
|
||||
else
|
||||
ignoredLastBlock = false;
|
||||
VisitEmbeddedStatement(ifStmt->mTrueStatement);
|
||||
|
@ -3785,9 +3790,14 @@ void BfModule::DoIfStatement(BfIfStatement* ifStmt, bool includeTrueStmt, bool i
|
|||
ignoredLastBlock = true;
|
||||
//
|
||||
{
|
||||
SetAndRestoreValue<bool> ignoreWrites(mBfIRBuilder->mIgnoreWrites);
|
||||
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites);
|
||||
SetAndRestoreValue<bool> prevInConstIgnore(mCurMethodState->mCurScope->mInConstIgnore);
|
||||
|
||||
if ((isConstBranch) && (constResult != false))
|
||||
{
|
||||
mBfIRBuilder->mIgnoreWrites = true;
|
||||
mCurMethodState->mCurScope->mInConstIgnore = true;
|
||||
}
|
||||
else
|
||||
ignoredLastBlock = false;
|
||||
falseDeferredLocalAssignData.ExtendFrom(mCurMethodState->mDeferredLocalAssignData);
|
||||
|
@ -3898,6 +3908,18 @@ void BfModule::Visit(BfAttributedStatement* attribStmt)
|
|||
VisitChild(attribStmt->mStatement);
|
||||
attributeState.mUsed = true;
|
||||
}
|
||||
else if (attributeState.mCustomAttributes->Contains(mCompiler->mConstSkipAttributeTypeDef))
|
||||
{
|
||||
if ((mCurMethodState == NULL) || (mCurMethodState->mCurScope == NULL) || (!mCurMethodState->mCurScope->mInConstIgnore))
|
||||
{
|
||||
VisitChild(attribStmt->mStatement);
|
||||
}
|
||||
else
|
||||
{
|
||||
BF_ASSERT(mBfIRBuilder->mIgnoreWrites);
|
||||
}
|
||||
attributeState.mUsed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
VisitChild(attribStmt->mStatement);
|
||||
|
@ -4755,7 +4777,9 @@ void BfModule::Visit(BfSwitchStatement* switchStmt)
|
|||
|
||||
auto prevInsertBlock = mBfIRBuilder->GetInsertBlock();
|
||||
|
||||
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true, !mayHaveMatch && !prevHadFallthrough);
|
||||
bool isConstIgnore = !mayHaveMatch && !prevHadFallthrough;
|
||||
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true, isConstIgnore);
|
||||
SetAndRestoreValue<bool> prevInConstIgnore(mCurMethodState->mCurScope->mInConstIgnore, true, isConstIgnore);
|
||||
|
||||
mBfIRBuilder->AddBlock(caseBlock);
|
||||
mBfIRBuilder->SetInsertPoint(caseBlock);
|
||||
|
@ -4921,6 +4945,7 @@ void BfModule::Visit(BfSwitchStatement* switchStmt)
|
|||
if (switchStmt->mDefaultCase != NULL)
|
||||
{
|
||||
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true, hadConstMatch);
|
||||
SetAndRestoreValue<bool> prevInConstIgnore(mCurMethodState->mCurScope->mInConstIgnore, true, hadConstMatch);
|
||||
|
||||
mBfIRBuilder->AddBlock(defaultBlock);
|
||||
mBfIRBuilder->SetInsertPoint(defaultBlock);
|
||||
|
@ -5742,6 +5767,7 @@ void BfModule::Visit(BfWhileStatement* whileStmt)
|
|||
if (isFalseLoop)
|
||||
{
|
||||
SetAndRestoreValue<bool> ignoreWrites(mBfIRBuilder->mIgnoreWrites, true);
|
||||
SetAndRestoreValue<bool> prevInConstIgnore(mCurMethodState->mCurScope->mInConstIgnore, true);
|
||||
VisitEmbeddedStatement(whileStmt->mEmbeddedStatement);
|
||||
}
|
||||
else
|
||||
|
@ -6693,6 +6719,8 @@ void BfModule::Visit(BfForEachStatement* forEachStmt)
|
|||
{
|
||||
if (!isVarEnumerator)
|
||||
AssertErrorState();
|
||||
|
||||
mBfIRBuilder->CreateBr(endBB);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue