mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 11:38:21 +02:00
Initial const eval feature release
This commit is contained in:
parent
be929c3626
commit
ff1f8aff3f
27 changed files with 887 additions and 178 deletions
|
@ -260,6 +260,12 @@ namespace System
|
|||
|
||||
}
|
||||
|
||||
[AttributeUsage(.Method | .Invocation)]
|
||||
public struct ConstEvalAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[AttributeUsage(.Method /*2*/)]
|
||||
public struct IntrinsicAttribute : Attribute
|
||||
{
|
||||
|
|
|
@ -34,5 +34,21 @@ namespace System
|
|||
|
||||
[LinkName("#IsConstEval")]
|
||||
public static extern bool IsConstEval;
|
||||
|
||||
[LinkName("#IsBuilding")]
|
||||
public static extern bool IsBuilding;
|
||||
|
||||
[LinkName("#IsReified")]
|
||||
public static extern bool IsReified;
|
||||
|
||||
[LinkName("#CompileRev")]
|
||||
public static extern int32 CompileRev;
|
||||
|
||||
[ConstEval]
|
||||
public static void Assert(bool cond)
|
||||
{
|
||||
if (!cond)
|
||||
Runtime.FatalError("Assert failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,30 @@ namespace System.Reflection
|
|||
}
|
||||
}
|
||||
|
||||
public bool IsConst
|
||||
{
|
||||
get
|
||||
{
|
||||
return mFieldData.mFlags.HasFlag(.Const);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsStatic
|
||||
{
|
||||
get
|
||||
{
|
||||
return mFieldData.mFlags.HasFlag(.Static);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsInstanceField
|
||||
{
|
||||
get
|
||||
{
|
||||
return !mFieldData.mFlags.HasFlag(.Static) && !mFieldData.mFlags.HasFlag(.Const);
|
||||
}
|
||||
}
|
||||
|
||||
public StringView Name
|
||||
{
|
||||
get
|
||||
|
@ -520,6 +544,14 @@ namespace System.Reflection
|
|||
}
|
||||
}
|
||||
|
||||
public int32 Index
|
||||
{
|
||||
get
|
||||
{
|
||||
return mIdx;
|
||||
}
|
||||
}
|
||||
|
||||
public Result<FieldInfo> GetNext() mut
|
||||
{
|
||||
if (!MoveNext())
|
||||
|
|
|
@ -455,13 +455,19 @@ namespace System
|
|||
return (int32)mTypeId;
|
||||
}
|
||||
|
||||
static extern Type ConstEval_GetTypeById(int32 typeId);
|
||||
|
||||
protected static Type GetType(TypeId typeId)
|
||||
{
|
||||
if (Compiler.IsConstEval)
|
||||
return ConstEval_GetTypeById((.)typeId);
|
||||
return sTypes[(int32)typeId];
|
||||
}
|
||||
|
||||
protected static Type GetType_(int32 typeId)
|
||||
{
|
||||
if (Compiler.IsConstEval)
|
||||
return ConstEval_GetTypeById(typeId);
|
||||
return sTypes[typeId];
|
||||
}
|
||||
|
||||
|
|
|
@ -148,6 +148,24 @@ public:
|
|||
~AutoPerfRecordAndPrint();
|
||||
};
|
||||
|
||||
class AutoTimer
|
||||
{
|
||||
public:
|
||||
uint32 mStartTick;
|
||||
int* mTimePtr;
|
||||
|
||||
public:
|
||||
AutoTimer(int& timeRef)
|
||||
{
|
||||
mTimePtr = &timeRef;
|
||||
mStartTick = BFTickCount();
|
||||
}
|
||||
|
||||
~AutoTimer()
|
||||
{
|
||||
*mTimePtr += BFTickCount() - mStartTick;
|
||||
}
|
||||
};
|
||||
|
||||
class DebugTimeGuard
|
||||
{
|
||||
|
|
|
@ -231,6 +231,12 @@ namespace System
|
|||
|
||||
}
|
||||
|
||||
[AttributeUsage(.Method | .Invocation)]
|
||||
public struct ConstEvalAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[AttributeUsage(.Method /*2*/)]
|
||||
public struct IntrinsicAttribute : Attribute
|
||||
{
|
||||
|
|
|
@ -11781,6 +11781,9 @@ namespace IDE
|
|||
bool didClean = false;
|
||||
if (mWantsBeefClean)
|
||||
{
|
||||
mBfBuildCompiler?.CancelBackground();
|
||||
mBfResolveCompiler?.CancelBackground();
|
||||
|
||||
if ((!mBfBuildCompiler.HasQueuedCommands()) &&
|
||||
((mBfResolveCompiler == null) || (!mBfResolveCompiler.HasQueuedCommands())))
|
||||
{
|
||||
|
@ -11857,6 +11860,9 @@ namespace IDE
|
|||
|
||||
if (mWantsClean)
|
||||
{
|
||||
mBfBuildCompiler?.CancelBackground();
|
||||
mBfResolveCompiler?.CancelBackground();
|
||||
|
||||
if ((!mBfBuildCompiler.HasQueuedCommands()) && (!mBfResolveCompiler.HasQueuedCommands())
|
||||
#if IDE_C_SUPPORT
|
||||
&& (!mDepClang.HasQueuedCommands()) && (!mResolveClang.HasQueuedCommands())
|
||||
|
|
|
@ -1027,6 +1027,18 @@ namespace IDE.ui
|
|||
doBackground = true;
|
||||
}
|
||||
|
||||
// If there's a long-running const eval then cancel that first
|
||||
if (!mDeferredResolveResults.IsEmpty)
|
||||
{
|
||||
for (var result in mDeferredResolveResults)
|
||||
{
|
||||
if (result.mResolveType == .ClassifyFullRefresh)
|
||||
{
|
||||
bfCompiler.RequestCancelBackground();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mIsClang)
|
||||
{
|
||||
#if !IDE_C_SUPPORT
|
||||
|
|
|
@ -26,6 +26,9 @@ namespace IDE.ui
|
|||
public int mDirtyDelay;
|
||||
public int mStatusBoxUpdateCnt = -1;
|
||||
|
||||
public int32 mResolveStuckTicks;
|
||||
public float mResolveLastPct = -1;
|
||||
|
||||
public this()
|
||||
{
|
||||
mConfigComboBox = new DarkComboBox();
|
||||
|
@ -225,8 +228,19 @@ namespace IDE.ui
|
|||
#endif
|
||||
)
|
||||
{
|
||||
float completionPct = gApp.mBfResolveCompiler.GetCompletionPercentage();
|
||||
if (completionPct != mResolveLastPct)
|
||||
{
|
||||
mResolveStuckTicks = 0;
|
||||
mResolveLastPct = completionPct;
|
||||
}
|
||||
else
|
||||
mResolveStuckTicks++;
|
||||
|
||||
MarkDirtyEx();
|
||||
}
|
||||
else
|
||||
mResolveStuckTicks = 0;
|
||||
}
|
||||
|
||||
public override void Draw(Graphics g)
|
||||
|
@ -380,6 +394,10 @@ namespace IDE.ui
|
|||
{
|
||||
DrawStatusBox("Custom Build Commands...", gApp.mBuildContext.mUpdateCnt);
|
||||
}
|
||||
else if (mResolveStuckTicks > 300)
|
||||
{
|
||||
DrawStatusBox("Const Evaluation");
|
||||
}
|
||||
else
|
||||
mStatusBoxUpdateCnt = -1;
|
||||
|
||||
|
|
|
@ -471,7 +471,7 @@ void BfAutoComplete::AddMethod(BfTypeInstance* typeInstance, BfMethodDef* method
|
|||
{
|
||||
if (methodDecl != NULL)
|
||||
{
|
||||
if ((methodInstance != NULL) && (methodInstance->mMethodDef->mIsLocalMethod) && (GetCursorIdx(methodDecl) == methodDecl->mReturnType->mSrcEnd))
|
||||
if ((methodInstance != NULL) && (methodInstance->mMethodDef->mIsLocalMethod) && (methodDecl->mReturnType != NULL) && (GetCursorIdx(methodDecl) == methodDecl->mReturnType->mSrcEnd))
|
||||
{
|
||||
// This isn't really a local method decl, it just looks like one
|
||||
return;
|
||||
|
|
|
@ -397,6 +397,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
|
|||
mActionTypeDef = NULL;
|
||||
mEnumTypeDef = NULL;
|
||||
mFriendAttributeTypeDef = NULL;
|
||||
mConstEvalAttributeTypeDef = NULL;
|
||||
mNoExtensionAttributeTypeDef = NULL;
|
||||
mCheckedAttributeTypeDef = NULL;
|
||||
mUncheckedAttributeTypeDef = NULL;
|
||||
|
@ -406,6 +407,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
|
|||
mGenericIEnumeratorTypeDef = NULL;
|
||||
mGenericIRefEnumeratorTypeDef = NULL;
|
||||
mInlineAttributeTypeDef = NULL;
|
||||
mThreadTypeDef = NULL;
|
||||
mInternalTypeDef = NULL;
|
||||
mDiagnosticsDebugTypeDef = NULL;
|
||||
mIDisposableTypeDef = NULL;
|
||||
|
@ -6596,6 +6598,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
|
|||
mActionTypeDef = _GetRequiredType("System.Action");
|
||||
mEnumTypeDef = _GetRequiredType("System.Enum");
|
||||
mFriendAttributeTypeDef = _GetRequiredType("System.FriendAttribute");
|
||||
mConstEvalAttributeTypeDef = _GetRequiredType("System.ConstEvalAttribute");
|
||||
mNoExtensionAttributeTypeDef = _GetRequiredType("System.NoExtensionAttribute");
|
||||
mCheckedAttributeTypeDef = _GetRequiredType("System.CheckedAttribute");
|
||||
mUncheckedAttributeTypeDef = _GetRequiredType("System.UncheckedAttribute");
|
||||
|
@ -6606,6 +6609,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
|
|||
mGenericIEnumeratorTypeDef = _GetRequiredType("System.Collections.IEnumerator", 1);
|
||||
mGenericIRefEnumeratorTypeDef = _GetRequiredType("System.Collections.IRefEnumerator", 1);
|
||||
mInlineAttributeTypeDef = _GetRequiredType("System.InlineAttribute");
|
||||
mThreadTypeDef = _GetRequiredType("System.Threading.Thread");
|
||||
mInternalTypeDef = _GetRequiredType("System.Internal");
|
||||
mDiagnosticsDebugTypeDef = _GetRequiredType("System.Diagnostics.Debug");
|
||||
mIDisposableTypeDef = _GetRequiredType("System.IDisposable");
|
||||
|
@ -7259,6 +7263,11 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
|
|||
numModulesWritten, (numModulesWritten != 1) ? "s" : "",
|
||||
numObjFilesWritten, (numObjFilesWritten != 1) ? "s" : ""));
|
||||
|
||||
if ((mCEMachine != NULL) && (!mIsResolveOnly) && (mCEMachine->mRevisionExecuteTime > 0))
|
||||
{
|
||||
mPassInstance->OutputLine(StrFormat(":med Const evaluation time: %0.2fs", mCEMachine->mRevisionExecuteTime / 1000.0f));
|
||||
}
|
||||
|
||||
BpLeave();
|
||||
mPassInstance->WriteErrorSummary();
|
||||
|
||||
|
|
|
@ -359,6 +359,7 @@ public:
|
|||
BfTypeDef* mGenericIEnumeratorTypeDef;
|
||||
BfTypeDef* mGenericIRefEnumeratorTypeDef;
|
||||
|
||||
BfTypeDef* mThreadTypeDef;
|
||||
BfTypeDef* mInternalTypeDef;
|
||||
BfTypeDef* mDiagnosticsDebugTypeDef;
|
||||
BfTypeDef* mIDisposableTypeDef;
|
||||
|
@ -401,6 +402,7 @@ public:
|
|||
BfTypeDef* mDisableChecksAttributeTypeDef;
|
||||
BfTypeDef* mDisableObjectAccessChecksAttributeTypeDef;
|
||||
BfTypeDef* mFriendAttributeTypeDef;
|
||||
BfTypeDef* mConstEvalAttributeTypeDef;
|
||||
BfTypeDef* mNoExtensionAttributeTypeDef;
|
||||
BfTypeDef* mCheckedAttributeTypeDef;
|
||||
BfTypeDef* mUncheckedAttributeTypeDef;
|
||||
|
|
|
@ -36,7 +36,7 @@ BfConstResolver::BfConstResolver(BfModule* bfModule) : BfExprEvaluator(bfModule)
|
|||
|
||||
BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfConstResolveFlags flags)
|
||||
{
|
||||
mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_ConstExpr);
|
||||
mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_ConstEval);
|
||||
|
||||
// Handle the 'int[?] val = .(1, 2, 3)' case
|
||||
if ((flags & BfConstResolveFlag_ArrayInitSize) != 0)
|
||||
|
@ -76,7 +76,7 @@ BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfCo
|
|||
}
|
||||
else
|
||||
{
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(BfTypeCode_IntPtr), mModule->GetPrimitiveType(BfTypeCode_IntPtr));
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->GetPrimitiveType(BfTypeCode_IntPtr)), mModule->GetPrimitiveType(BfTypeCode_IntPtr));
|
||||
return mResult;
|
||||
}
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfCo
|
|||
BfTypedValue result;
|
||||
result.mKind = BfTypedValueKind_Value;
|
||||
result.mType = genericTypeConstraint;
|
||||
result.mValue = mModule->mBfIRBuilder->GetUndefConstValue(primType->mTypeDef->mTypeCode);
|
||||
result.mValue = mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->GetPrimitiveType(primType->mTypeDef->mTypeCode));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -821,6 +821,8 @@ void BfDefBuilder::ParseAttributes(BfAttributeDirective* attributes, BfMethodDef
|
|||
methodDef->mIsNoReturn = true;
|
||||
else if (typeRefName == "SkipCall")
|
||||
methodDef->mIsSkipCall = true;
|
||||
else if (typeRefName == "ConstEval")
|
||||
methodDef->mIsConstEval = true;
|
||||
else if (typeRefName == "NoShow")
|
||||
methodDef->mIsNoShow = true;
|
||||
else if (typeRefName == "NoDiscard")
|
||||
|
|
|
@ -2630,14 +2630,14 @@ BfAutoComplete* BfExprEvaluator::GetAutoComplete()
|
|||
|
||||
bool BfExprEvaluator::IsConstEval()
|
||||
{
|
||||
return (mModule->mIsConstModule) || ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0);
|
||||
return (mModule->mIsConstModule) || ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0);
|
||||
}
|
||||
|
||||
bool BfExprEvaluator::IsConstEvalEntry()
|
||||
{
|
||||
if (mModule->mIsConstModule)
|
||||
return false;
|
||||
return ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0);
|
||||
return ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0);
|
||||
}
|
||||
|
||||
int BfExprEvaluator::GetStructRetIdx(BfMethodInstance* methodInstance, bool forceStatic)
|
||||
|
@ -3263,6 +3263,11 @@ void BfExprEvaluator::Visit(BfLiteralExpression* literalExpr)
|
|||
|
||||
void BfExprEvaluator::Visit(BfStringInterpolationExpression* stringInterpolationExpression)
|
||||
{
|
||||
if (IsConstEvalEntry())
|
||||
{
|
||||
mModule->Fail("Const evaluation of string interpolation not allowed", stringInterpolationExpression);
|
||||
}
|
||||
|
||||
if ((mBfEvalExprFlags & BfEvalExprFlags_StringInterpolateFormat) != 0)
|
||||
{
|
||||
BfVariant variant;
|
||||
|
@ -4993,6 +4998,20 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance*
|
|||
}
|
||||
}
|
||||
|
||||
if ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0)
|
||||
{
|
||||
if (methodInstance->mReturnType->IsInstanceOf(mModule->mCompiler->mSpanTypeDef))
|
||||
{
|
||||
if (mExpectingType->IsSizedArray())
|
||||
{
|
||||
return BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->MapType(mExpectingType)), mExpectingType);
|
||||
}
|
||||
}
|
||||
if (methodInstance->mReturnType->IsValuelessType())
|
||||
return BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), methodInstance->mReturnType);
|
||||
return BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->MapType(methodInstance->mReturnType)), methodInstance->mReturnType);
|
||||
}
|
||||
|
||||
BfTypedValue result;
|
||||
if (sret != NULL)
|
||||
result = *sret;
|
||||
|
@ -5009,15 +5028,15 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance*
|
|||
{
|
||||
mModule->mCompiler->mCEMachine->QueueMethod(methodInstance, func);
|
||||
}
|
||||
else if ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0)
|
||||
else if ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0)
|
||||
{
|
||||
if (mFunctionBindResult != NULL)
|
||||
{
|
||||
forceBind = true;
|
||||
}
|
||||
else if (mUsedAsStatement)
|
||||
else if ((mBfEvalExprFlags & BfEvalExprFlags_InCascade) != 0)
|
||||
{
|
||||
// Don't allow use in a cascade
|
||||
mModule->Fail("Const evaluation not allowed with cascade operator", targetSrc);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5648,7 +5667,7 @@ void BfExprEvaluator::PushArg(BfTypedValue argVal, SizedArrayImpl<BfIRValue>& ir
|
|||
{
|
||||
if (argVal.mType->IsComposite())
|
||||
{
|
||||
if ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0)
|
||||
if ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0)
|
||||
{
|
||||
// Const eval entry - we want any incoming consts as they are
|
||||
}
|
||||
|
@ -6121,7 +6140,24 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
|||
if (methodDef->mMethodType == BfMethodType_Extension)
|
||||
numElements++;
|
||||
|
||||
if (wantType->IsArray())
|
||||
if (IsConstEvalEntry())
|
||||
{
|
||||
if ((wantType->IsArray()) || (wantType->IsInstanceOf(mModule->mCompiler->mSpanTypeDef)))
|
||||
{
|
||||
auto genericTypeInst = wantType->ToGenericTypeInstance();
|
||||
expandedParamsElementType = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[0];
|
||||
|
||||
auto irSizedArrayType = mModule->mBfIRBuilder->GetSizedArrayType(mModule->mBfIRBuilder->MapType(expandedParamsElementType), numElements);
|
||||
|
||||
Array<BfIRValue> values;
|
||||
for (int i = 0; i < numElements; i++)
|
||||
values.Add(mModule->mBfIRBuilder->GetFakeVal());
|
||||
expandedParamsArray = BfTypedValue(mModule->mBfIRBuilder->CreateConstAgg(irSizedArrayType, values), wantType);
|
||||
|
||||
PushArg(expandedParamsArray, irArgs);
|
||||
}
|
||||
}
|
||||
else if (wantType->IsArray())
|
||||
{
|
||||
BfArrayType* arrayType = (BfArrayType*)wantType;
|
||||
mModule->PopulateType(arrayType, BfPopulateType_DataAndMethods);
|
||||
|
@ -6152,7 +6188,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
|||
|
||||
PushArg(expandedParamsArray, irArgs);
|
||||
}
|
||||
else
|
||||
else if (wantType->IsInstanceOf(mModule->mCompiler->mSpanTypeDef))
|
||||
{
|
||||
auto genericTypeInst = wantType->ToGenericTypeInstance();
|
||||
expandedParamsElementType = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[0];
|
||||
|
@ -6538,7 +6574,14 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
|||
{
|
||||
if (argValue)
|
||||
{
|
||||
if (expandedParamAlloca)
|
||||
if (IsConstEvalEntry())
|
||||
{
|
||||
auto constant = mModule->mBfIRBuilder->GetConstant(expandedParamsArray.mValue);
|
||||
BF_ASSERT(constant->mConstType == BfConstType_Agg);
|
||||
auto constAgg = (BfConstantAgg*)constant;
|
||||
constAgg->mValues[extendedParamIdx] = argValue.mValue;
|
||||
}
|
||||
else if (expandedParamAlloca)
|
||||
{
|
||||
argValue = mModule->LoadValue(argValue);
|
||||
auto addr = mModule->mBfIRBuilder->CreateInBoundsGEP(expandedParamAlloca, extendedParamIdx);
|
||||
|
@ -7965,7 +8008,9 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
|||
mResultLocalVar = NULL;
|
||||
mResultFieldInstance = NULL;
|
||||
mResultLocalVarRefNode = NULL;
|
||||
MatchConstructor(targetSrc, methodBoundExpr, structInst, resolvedTypeInstance, argValues, false, false);
|
||||
auto result = MatchConstructor(targetSrc, methodBoundExpr, structInst, resolvedTypeInstance, argValues, false, false);
|
||||
if ((result) && (!result.mType->IsVoid()))
|
||||
return result;
|
||||
mModule->ValidateAllocation(resolvedTypeInstance, targetSrc);
|
||||
|
||||
mModule->AddDependency(resolvedTypeInstance, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_LocalUsage);
|
||||
|
@ -8368,7 +8413,26 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
|||
mModule->MethodToString(moduleMethodInstance.mMethodInstance).c_str(), mModule->MethodToString(mModule->mCurMethodInstance).c_str()), targetSrc);
|
||||
}
|
||||
|
||||
auto result = CreateCall(targetSrc, callTarget, origTarget, methodDef, moduleMethodInstance, bypassVirtual, argValues.mResolvedArgs, skipThis);
|
||||
|
||||
BfTypedValue result;
|
||||
|
||||
//
|
||||
{
|
||||
SetAndRestoreValue<BfEvalExprFlags> prevEvalExprFlag(mBfEvalExprFlags);
|
||||
|
||||
if ((mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL) && (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mConstEvalAttributeTypeDef)))
|
||||
{
|
||||
mModule->mAttributeState->mUsed = true;
|
||||
mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_ConstEval);
|
||||
}
|
||||
else if (moduleMethodInstance.mMethodInstance->mMethodDef->mIsConstEval)
|
||||
{
|
||||
mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_ConstEval);
|
||||
}
|
||||
|
||||
result = CreateCall(targetSrc, callTarget, origTarget, methodDef, moduleMethodInstance, bypassVirtual, argValues.mResolvedArgs, skipThis);
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
if (result.mType->IsRef())
|
||||
|
@ -9474,7 +9538,7 @@ void BfExprEvaluator::DoTypeIntAttr(BfTypeReference* typeRef, BfToken token)
|
|||
// We do this so we know it's a constant but we can't assume anything about its value
|
||||
// We make the value an Int32 which doesn't match the IntPtr type, but it allows us to
|
||||
// assume it can be implicitly cased to int32
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(BfTypeCode_Int32), sizeType);
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->MapType(sizeType)), sizeType);
|
||||
}
|
||||
else
|
||||
mResult = BfTypedValue(mModule->GetConstValue(attrVal, sizeType), sizeType);
|
||||
|
@ -12022,6 +12086,8 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam
|
|||
mModule->mCurMethodState->mHotDataReferenceBuilder->mInnerMethods.Add(dtorMethodInstance->mHotMethod);
|
||||
lambdaInstance->mDtorMethodInstance = dtorMethodInstance;
|
||||
lambdaInstance->mDtorFunc = dtorFunc;
|
||||
|
||||
dtorMethodInstance->mMethodInstanceGroup = NULL;
|
||||
}
|
||||
|
||||
prevClosureState.Restore();
|
||||
|
@ -13199,7 +13265,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs
|
|||
{
|
||||
allocValue = mModule->AllocFromType(resolvedTypeRef, allocTarget, appendSizeValue, BfIRValue(), 0, BfAllocFlags_None, allocAlign);
|
||||
}
|
||||
if (((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0) && (mModule->mCompiler->mCEMachine != NULL))
|
||||
if (((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0) && (mModule->mCompiler->mCEMachine != NULL))
|
||||
{
|
||||
mModule->mCompiler->mCEMachine->SetAppendAllocInfo(mModule, allocValue, appendSizeValue);
|
||||
}
|
||||
|
@ -13250,7 +13316,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs
|
|||
{
|
||||
mModule->AssertErrorState();
|
||||
}
|
||||
else if ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) == 0)
|
||||
else if ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) == 0)
|
||||
{
|
||||
SizedArray<BfIRValue, 1> irArgs;
|
||||
irArgs.push_back(mResult.mValue);
|
||||
|
@ -13328,7 +13394,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs
|
|||
}
|
||||
}
|
||||
|
||||
if (((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0) && (mModule->mCompiler->mCEMachine != NULL))
|
||||
if (((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0) && (mModule->mCompiler->mCEMachine != NULL))
|
||||
{
|
||||
mModule->mCompiler->mCEMachine->ClearAppendAllocInfo();
|
||||
}
|
||||
|
@ -15362,6 +15428,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
|
|||
|
||||
int methodCount = 0;
|
||||
bool mayBeSkipCall = false;
|
||||
bool mayBeConstEvalCall = false;
|
||||
if (thisValue.mType != NULL)
|
||||
{
|
||||
if (thisValue.mType->IsAllocType())
|
||||
|
@ -15379,6 +15446,8 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
|
|||
{
|
||||
if (methodDef->mIsSkipCall)
|
||||
mayBeSkipCall = true;
|
||||
if (methodDef->mIsConstEval)
|
||||
mayBeConstEvalCall = true;
|
||||
methodDef = methodDef->mNextWithSameName;
|
||||
}
|
||||
}
|
||||
|
@ -15404,7 +15473,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
|
|||
|
||||
BfResolveArgFlags resolveArgsFlags = (BfResolveArgFlags)(BfResolveArgFlag_DeferFixits | BfResolveArgFlag_AllowUnresolvedTypes);
|
||||
resolveArgsFlags = (BfResolveArgFlags)(resolveArgsFlags | BfResolveArgFlag_DeferParamEval);
|
||||
if (mayBeSkipCall)
|
||||
if ((mayBeSkipCall) || (mayBeConstEvalCall))
|
||||
resolveArgsFlags = (BfResolveArgFlags)(resolveArgsFlags | BfResolveArgFlag_DeferParamValues);
|
||||
|
||||
static int sCallIdx = 0;
|
||||
|
@ -15430,10 +15499,13 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
|
|||
}
|
||||
}
|
||||
|
||||
if ((isCascade) && (cascadeOperatorToken != NULL) && ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0))
|
||||
if ((isCascade) && (cascadeOperatorToken != NULL) && ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0))
|
||||
mModule->Fail("Cascade operator cannot be used in const evaluation", cascadeOperatorToken);
|
||||
|
||||
SetAndRestoreValue<bool> prevUsedAsStatement(mUsedAsStatement, mUsedAsStatement || isCascade);
|
||||
SetAndRestoreValue<BfEvalExprFlags> prevEvalExprFlags(mBfEvalExprFlags);
|
||||
if (isCascade)
|
||||
mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_InCascade);
|
||||
ResolveArgValues(argValues, resolveArgsFlags);
|
||||
mResult = MatchMethod(methodNodeSrc, methodBoundExpr, thisValue, allowImplicitThis, bypassVirtual, targetFunctionName, argValues, methodGenericArguments, checkedKind);
|
||||
argValues.HandleFixits(mModule);
|
||||
|
@ -15840,7 +15912,7 @@ BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericTyp
|
|||
else
|
||||
{
|
||||
BF_ASSERT(mModule->mCurMethodInstance->mIsUnspecialized);
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(BfTypeCode_IntPtr), mModule->GetPrimitiveType(BfTypeCode_IntPtr));
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->GetPrimitiveType(BfTypeCode_IntPtr)), mModule->GetPrimitiveType(BfTypeCode_IntPtr));
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
@ -17166,8 +17238,8 @@ void BfExprEvaluator::InitializedSizedArray(BfSizedArrayType* arrayType, BfToken
|
|||
{
|
||||
if (checkArrayType->mElementCount == -1)
|
||||
{
|
||||
mModule->Fail("Initializers not supported for unknown-sized arrays", valueExprs[0]);
|
||||
failedAt.Add(depth);
|
||||
// mModule->Fail("Initializers not supported for unknown-sized arrays", valueExprs[0]);
|
||||
// failedAt.Add(depth);
|
||||
}
|
||||
else if (initCountDiff > 0)
|
||||
{
|
||||
|
@ -17453,6 +17525,10 @@ void BfExprEvaluator::InitializedSizedArray(BfSizedArrayType* arrayType, BfToken
|
|||
members.push_back(defaultVal.mValue);
|
||||
}
|
||||
|
||||
auto allocArrayType = checkArrayType;
|
||||
if (checkArrayType->IsUndefSizedArray())
|
||||
allocArrayType = mModule->CreateSizedArrayType(checkArrayType->GetUnderlyingType(), (int)members.size());
|
||||
|
||||
if (checkArrayType->mElementType->IsStruct())
|
||||
{
|
||||
// This fixed cases where we have non-size-aligned initializers. Assume zero-initialized
|
||||
|
@ -17632,16 +17708,60 @@ void BfExprEvaluator::Visit(BfTupleExpression* tupleExpr)
|
|||
}
|
||||
else
|
||||
{
|
||||
int valueIdx = -1;
|
||||
bool isExactConst = true;
|
||||
|
||||
for (int fieldIdx = 0; fieldIdx < (int)tupleType->mFieldInstances.size(); fieldIdx++)
|
||||
{
|
||||
BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[fieldIdx];
|
||||
if (fieldInstance->mDataIdx < 0)
|
||||
continue;
|
||||
++valueIdx;
|
||||
auto typedValue = typedValues[valueIdx];
|
||||
if (typedValue.mType != fieldInstance->mResolvedType)
|
||||
{
|
||||
isExactConst = false;
|
||||
break;
|
||||
}
|
||||
if (!typedValue.mValue.IsConst())
|
||||
{
|
||||
isExactConst = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isExactConst)
|
||||
{
|
||||
mModule->PopulateType(tupleType);
|
||||
|
||||
Array<BfIRValue> irValues;
|
||||
irValues.Resize(typedValues.mSize + 1);
|
||||
irValues[0] = mModule->mBfIRBuilder->CreateConstStructZero(mModule->mBfIRBuilder->MapType(tupleType->mBaseType));
|
||||
|
||||
for (int fieldIdx = 0; fieldIdx < (int)tupleType->mFieldInstances.size(); fieldIdx++)
|
||||
{
|
||||
BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[fieldIdx];
|
||||
if (fieldInstance->mDataIdx < 0)
|
||||
continue;
|
||||
irValues[fieldInstance->mDataIdx] = typedValues[fieldIdx].mValue;
|
||||
}
|
||||
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConstAgg(mModule->mBfIRBuilder->MapType(tupleType), irValues), tupleType);
|
||||
return;
|
||||
}
|
||||
|
||||
curTupleValue = mModule->CreateAlloca(tupleType);
|
||||
mResultIsTempComposite = true;
|
||||
mResult = BfTypedValue(curTupleValue, tupleType, BfTypedValueKind_TempAddr);
|
||||
}
|
||||
|
||||
for (int valueIdx = 0; valueIdx < (int)typedValues.size(); valueIdx++)
|
||||
int valueIdx = -1;
|
||||
for (int fieldIdx = 0; fieldIdx < (int)tupleType->mFieldInstances.size(); fieldIdx++)
|
||||
{
|
||||
BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[valueIdx];
|
||||
BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[fieldIdx];
|
||||
if (fieldInstance->mResolvedType->IsValuelessType())
|
||||
continue;
|
||||
++valueIdx;
|
||||
auto typedVal = typedValues[valueIdx];
|
||||
if (!typedVal)
|
||||
{
|
||||
|
@ -20511,6 +20631,20 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
|
|||
|
||||
if (!handled)
|
||||
{
|
||||
if ((leftValue.mType->IsUndefSizedArray()) || (rightValue.mType->IsUndefSizedArray()))
|
||||
{
|
||||
if ((leftValue.mType->IsSizedArray()) && (rightValue.mType->IsSizedArray() &&
|
||||
(leftValue.mType->GetUnderlyingType() == rightValue.mType->GetUnderlyingType())))
|
||||
{
|
||||
if (BfBinOpEqualityCheck(binaryOp))
|
||||
{
|
||||
auto boolType = mModule->GetPrimitiveType(BfTypeCode_Boolean);
|
||||
mResult = mModule->GetDefaultTypedValue(boolType, false, BfDefaultValueKind_Undef);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mModule->Fail(StrFormat("Operator '%s' cannot be applied to operands of type '%s' and '%s'",
|
||||
BfGetOpName(binaryOp),
|
||||
mModule->TypeToString(leftValue.mType).c_str(),
|
||||
|
|
|
@ -175,9 +175,7 @@ USING_NS_BF;
|
|||
auto constRHS = GetConstantById(rhs.mId); \
|
||||
if ((constLHS->mConstType == BfConstType_Undef) || (constRHS->mConstType == BfConstType_Undef)) \
|
||||
{ \
|
||||
if (((constLHS->mConstType == BfConstType_Undef) || (constLHS->mTypeCode < BfTypeCode_Length)) && \
|
||||
((constRHS->mConstType == BfConstType_Undef) || (constRHS->mTypeCode < BfTypeCode_Length))) \
|
||||
return GetUndefConstValue(BfTypeCode_Boolean); \
|
||||
return GetUndefConstValue(MapType(mModule->GetPrimitiveType(BfTypeCode_Boolean))); \
|
||||
} \
|
||||
if ((constLHS->mTypeCode < BfTypeCode_Length) && (constRHS->mTypeCode < BfTypeCode_Length)) \
|
||||
{ \
|
||||
|
@ -654,6 +652,14 @@ BfIRValue BfIRConstHolder::CreateConst(BfConstant* fromConst, BfIRConstHolder* f
|
|||
}
|
||||
return CreateConstAgg(constAgg->mType, copiedVals);
|
||||
}
|
||||
else if (fromConst->mConstType == BfConstType_Undef)
|
||||
{
|
||||
auto constUndef = (BfConstantUndef*)fromConst;
|
||||
BF_ASSERT(constUndef->mType.mKind != BfIRTypeData::TypeKind_Stream);
|
||||
if (constUndef->mType.mKind == BfIRTypeData::TypeKind_Stream)
|
||||
return GetUndefConstValue(BfIRValue());
|
||||
return GetUndefConstValue(constUndef->mType);
|
||||
}
|
||||
else if ((IsInt(fromConst->mTypeCode)) || (fromConst->mTypeCode == BfTypeCode_Boolean) || (fromConst->mTypeCode == BfTypeCode_StringId))
|
||||
{
|
||||
return CreateConst(fromConst->mTypeCode, fromConst->mUInt64);
|
||||
|
@ -778,11 +784,11 @@ BfIRValue BfIRConstHolder::CreateTypeOf(BfType* type)
|
|||
return irValue;
|
||||
}
|
||||
|
||||
BfIRValue BfIRConstHolder::GetUndefConstValue(BfTypeCode typeCode)
|
||||
BfIRValue BfIRConstHolder::GetUndefConstValue(BfIRType irType)
|
||||
{
|
||||
auto constUndef = mTempAlloc.Alloc<BfConstantUndef>();
|
||||
constUndef->mConstType = BfConstType_Undef;
|
||||
constUndef->mTypeCode = typeCode;
|
||||
constUndef->mType = irType;
|
||||
|
||||
BfIRValue undefVal(BfIRValueFlags_Const, mTempAlloc.GetChunkedId(constUndef));
|
||||
#ifdef CHECK_CONSTHOLDER
|
||||
|
@ -3462,11 +3468,10 @@ BfIRFunction BfIRBuilder::GetFakeFunction()
|
|||
|
||||
BfIRType BfIRBuilder::GetPrimitiveType(BfTypeCode typeCode)
|
||||
{
|
||||
|
||||
FixTypeCode(typeCode);
|
||||
BfIRType retType = WriteCmd(BfIRCmd_PrimitiveType, typeCode);
|
||||
NEW_CMD_INSERTED_IRTYPE;
|
||||
return retType;
|
||||
BfIRType retType = WriteCmd(BfIRCmd_PrimitiveType, typeCode);
|
||||
NEW_CMD_INSERTED_IRTYPE;
|
||||
return retType;
|
||||
}
|
||||
|
||||
BfIRType BfIRBuilder::CreateStructType(const StringImpl& name)
|
||||
|
@ -3495,6 +3500,7 @@ BfIRType BfIRBuilder::MapType(BfType* type, BfIRPopulateType populateType)
|
|||
{
|
||||
PopulateType(type, populateType);
|
||||
}
|
||||
BF_ASSERT(type->mTypeId > 0);
|
||||
BfIRType retType;
|
||||
retType.mKind = BfIRType::TypeKind_TypeId;
|
||||
retType.mId = type->mTypeId;
|
||||
|
|
|
@ -815,7 +815,7 @@ struct BfConstantSizedArrayType
|
|||
struct BfConstantUndef
|
||||
{
|
||||
BfConstType mConstType;
|
||||
BfTypeCode mTypeCode;
|
||||
BfIRType mType;
|
||||
};
|
||||
|
||||
struct BfConstantBitCast
|
||||
|
@ -903,7 +903,7 @@ public:
|
|||
BfIRValue CreateConstArrayZero(BfIRType type, int count);
|
||||
BfIRValue CreateConstArrayZero(int count);
|
||||
BfIRValue CreateTypeOf(BfType* type);
|
||||
BfIRValue GetUndefConstValue(BfTypeCode typeCode);
|
||||
BfIRValue GetUndefConstValue(BfIRType type);
|
||||
};
|
||||
|
||||
enum BfIRPopulateType
|
||||
|
|
|
@ -83,8 +83,8 @@ BfLocalMethod::~BfLocalMethod()
|
|||
BF_ASSERT(mSource->mRefCount >= 0);
|
||||
}
|
||||
|
||||
delete mMethodDef;
|
||||
delete mMethodInstanceGroup;
|
||||
delete mMethodDef;
|
||||
}
|
||||
|
||||
void BfDeferredLocalAssignData::ExtendFrom(BfDeferredLocalAssignData* outerLocalAssignData, bool doChain)
|
||||
|
@ -1134,7 +1134,7 @@ void BfModule::EnsureIRBuilder(bool dbgVerifyCodeGen)
|
|||
// code as we walk the AST
|
||||
//mBfIRBuilder->mDbgVerifyCodeGen = true;
|
||||
if (
|
||||
(mModuleName == "-")
|
||||
(mModuleName == "System_StringView")
|
||||
//|| (mModuleName == "BeefTest2_ClearColorValue")
|
||||
//|| (mModuleName == "Tests_FuncRefs")
|
||||
)
|
||||
|
@ -1441,12 +1441,12 @@ BfTypedValue BfModule::GetDefaultTypedValue(BfType* type, bool allowRef, BfDefau
|
|||
|
||||
if (defaultValueKind == BfDefaultValueKind_Undef)
|
||||
{
|
||||
auto primType = type->ToPrimitiveType();
|
||||
if (primType != NULL)
|
||||
{
|
||||
return BfTypedValue(mBfIRBuilder->GetUndefConstValue(primType->mTypeDef->mTypeCode), type);
|
||||
}
|
||||
return BfTypedValue(mBfIRBuilder->CreateUndefValue(mBfIRBuilder->MapType(type)), type);
|
||||
// auto primType = type->ToPrimitiveType();
|
||||
// if (primType != NULL)
|
||||
// {
|
||||
// return BfTypedValue(mBfIRBuilder->GetUndefConstValue( primType), type);
|
||||
// }
|
||||
return BfTypedValue(mBfIRBuilder->GetUndefConstValue(mBfIRBuilder->MapType(type)), type);
|
||||
}
|
||||
|
||||
BfTypedValue typedValue;
|
||||
|
@ -5390,7 +5390,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
|
|||
}
|
||||
}
|
||||
|
||||
if ((!typeInstance->IsInterface()) && (typeInstance->mVirtualMethodTableSize > 0) && (needsVData))
|
||||
if ((!mIsConstModule) && (!typeInstance->IsInterface()) && (typeInstance->mVirtualMethodTableSize > 0) && (needsVData))
|
||||
{
|
||||
int startTabIdx = (int)vData.size();
|
||||
|
||||
|
@ -7925,7 +7925,7 @@ BfTypedValue BfModule::CreateValueFromExpression(BfExprEvaluator& exprEvaluator,
|
|||
BfTypedValue result;
|
||||
result.mKind = BfTypedValueKind_Value;
|
||||
result.mType = genericTypeConstraint;
|
||||
result.mValue = mBfIRBuilder->GetUndefConstValue(primType->mTypeDef->mTypeCode);
|
||||
result.mValue = mBfIRBuilder->GetUndefConstValue(mBfIRBuilder->MapType(primType));
|
||||
typedVal = result;
|
||||
handled = true;
|
||||
}
|
||||
|
@ -12064,6 +12064,11 @@ void BfModule::AddMethodReference(const BfMethodRef& methodRef, BfGetMethodInsta
|
|||
|
||||
BfModuleMethodInstance BfModule::ReferenceExternalMethodInstance(BfMethodInstance* methodInstance, BfGetMethodInstanceFlags flags)
|
||||
{
|
||||
if (mIsConstModule)
|
||||
{
|
||||
NOP;
|
||||
}
|
||||
|
||||
if ((flags & BfGetMethodInstanceFlag_ResultNotUsed) != 0)
|
||||
return BfModuleMethodInstance(methodInstance, BfIRValue());
|
||||
|
||||
|
@ -12257,6 +12262,11 @@ BfModule* BfModule::GetOrCreateMethodModule(BfMethodInstance* methodInstance)
|
|||
|
||||
BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfMethodDef* methodDef, const BfTypeVector& methodGenericArguments, BfGetMethodInstanceFlags flags, BfTypeInstance* foreignType)
|
||||
{
|
||||
if (mIsConstModule)
|
||||
{
|
||||
NOP;
|
||||
}
|
||||
|
||||
if (methodDef->mMethodType == BfMethodType_Init)
|
||||
return BfModuleMethodInstance();
|
||||
|
||||
|
@ -12338,7 +12348,7 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
|
|||
if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mMethodInfoEx != NULL) && (mCurMethodInstance->mMethodInfoEx->mMinDependDepth >= 32))
|
||||
flags = (BfGetMethodInstanceFlags)(flags | BfGetMethodInstanceFlag_DepthExceeded);
|
||||
|
||||
if ((!mIsReified) && (instModule->mIsReified))
|
||||
if ((!mIsConstModule) && (!mIsReified) && (instModule->mIsReified))
|
||||
{
|
||||
BF_ASSERT(!mCompiler->mIsResolveOnly);
|
||||
// A resolve-only module is specializing a method from a type in a reified module,
|
||||
|
@ -12351,7 +12361,7 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
|
|||
}
|
||||
else
|
||||
{
|
||||
if ((mIsReified) && (!instModule->mIsReified))
|
||||
if ((!mIsConstModule) && (mIsReified) && (!instModule->mIsReified))
|
||||
{
|
||||
if (!typeInst->IsUnspecializedTypeVariation())
|
||||
{
|
||||
|
@ -13080,6 +13090,10 @@ void BfModule::SetupMethodIdHash(BfMethodInstance* methodInstance)
|
|||
}
|
||||
|
||||
methodInstance->mIdHash = (int64)hashCtx.Finish64();
|
||||
if (methodInstance->mIdHash == 0x3400000029LL)
|
||||
{
|
||||
NOP;
|
||||
}
|
||||
}
|
||||
|
||||
BfIRValue BfModule::GetInterfaceSlotNum(BfTypeInstance* ifaceType)
|
||||
|
@ -13134,6 +13148,18 @@ BfTypedValue BfModule::GetCompilerFieldValue(const StringImpl& str)
|
|||
{
|
||||
return BfTypedValue(mBfIRBuilder->CreateConst(BfTypeCode_Boolean, mIsConstModule ? 1 : 0), GetPrimitiveType(BfTypeCode_Boolean));
|
||||
}
|
||||
if (str == "#IsBuilding")
|
||||
{
|
||||
return BfTypedValue(mBfIRBuilder->CreateConst(BfTypeCode_Boolean, (!mCompiler->mIsResolveOnly) ? 1 : 0), GetPrimitiveType(BfTypeCode_Boolean));
|
||||
}
|
||||
if (str == "#IsReified")
|
||||
{
|
||||
return BfTypedValue(mBfIRBuilder->CreateConst(BfTypeCode_Boolean, mIsReified ? 1 : 0), GetPrimitiveType(BfTypeCode_Boolean));
|
||||
}
|
||||
if (str == "#CompileRev")
|
||||
{
|
||||
return BfTypedValue(mBfIRBuilder->CreateConst(BfTypeCode_Int32, mCompiler->mRevision), GetPrimitiveType(BfTypeCode_Int32));
|
||||
}
|
||||
if (str == "#ModuleName")
|
||||
{
|
||||
return BfTypedValue(GetStringObjectValue(mModuleName), ResolveTypeDef(mCompiler->mStringTypeDef));
|
||||
|
@ -14504,7 +14530,7 @@ void BfModule::CreateDelegateInvokeMethod()
|
|||
if (mCurMethodInstance->mReturnType->IsValueType())
|
||||
mBfIRBuilder->PopulateType(mCurMethodInstance->mReturnType, BfIRPopulateType_Full);
|
||||
|
||||
if ((!mIsConstModule) && (mCurMethodInstance->GetStructRetIdx() != 0))
|
||||
if ((mIsConstModule) || (mCurMethodInstance->GetStructRetIdx() != 0))
|
||||
memberFuncArgs.push_back(BfIRValue()); // Push 'target'
|
||||
|
||||
int thisIdx = 0;
|
||||
|
@ -17078,11 +17104,13 @@ void BfModule::ProcessMethod_ProcessDeferredLocals(int startIdx)
|
|||
BP_ZONE_F("ProcessMethod lambdaInstance %s", lambdaInstance->mMethodInstance->mMethodDef->mName.c_str());
|
||||
lambdaInstance->mMethodInstance->mMethodInstanceGroup = &methodInstanceGroup;
|
||||
ProcessMethod(lambdaInstance->mMethodInstance);
|
||||
lambdaInstance->mMethodInstance->mMethodInstanceGroup = NULL;
|
||||
|
||||
if (lambdaInstance->mDtorMethodInstance != NULL)
|
||||
{
|
||||
lambdaInstance->mDtorMethodInstance->mMethodInstanceGroup = &methodInstanceGroup;
|
||||
ProcessMethod(lambdaInstance->mDtorMethodInstance);
|
||||
lambdaInstance->mDtorMethodInstance->mMethodInstanceGroup = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17546,22 +17574,25 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
|
|||
|
||||
BF_ASSERT(methodInstance->mMethodInstanceGroup->mOnDemandKind != BfMethodOnDemandKind_NotSet);
|
||||
|
||||
if ((methodInstance->mMethodInstanceGroup->mOnDemandKind != BfMethodOnDemandKind_AlwaysInclude) &&
|
||||
(methodInstance->mMethodInstanceGroup->mOnDemandKind != BfMethodOnDemandKind_Referenced))
|
||||
if (!mIsConstModule)
|
||||
{
|
||||
methodInstance->mMethodInstanceGroup->mOnDemandKind = BfMethodOnDemandKind_Referenced;
|
||||
|
||||
auto owningModule = methodInstance->GetOwner()->mModule;
|
||||
|
||||
if (owningModule->mIsScratchModule)
|
||||
if ((methodInstance->mMethodInstanceGroup->mOnDemandKind != BfMethodOnDemandKind_AlwaysInclude) &&
|
||||
(methodInstance->mMethodInstanceGroup->mOnDemandKind != BfMethodOnDemandKind_Referenced))
|
||||
{
|
||||
BF_ASSERT(owningModule->mOnDemandMethodCount == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
BF_ASSERT((owningModule->mOnDemandMethodCount > 0) || (!HasCompiledOutput()) || (owningModule->mExtensionCount > 0));
|
||||
if (owningModule->mOnDemandMethodCount > 0)
|
||||
owningModule->mOnDemandMethodCount--;
|
||||
methodInstance->mMethodInstanceGroup->mOnDemandKind = BfMethodOnDemandKind_Referenced;
|
||||
|
||||
auto owningModule = methodInstance->GetOwner()->mModule;
|
||||
|
||||
if (owningModule->mIsScratchModule)
|
||||
{
|
||||
BF_ASSERT(owningModule->mOnDemandMethodCount == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
BF_ASSERT((owningModule->mOnDemandMethodCount > 0) || (!HasCompiledOutput()) || (owningModule->mExtensionCount > 0));
|
||||
if (owningModule->mOnDemandMethodCount > 0)
|
||||
owningModule->mOnDemandMethodCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,8 @@ enum BfEvalExprFlags
|
|||
BfEvalExprFlags_AllowNonConst = 0x10000,
|
||||
BfEvalExprFlags_StringInterpolateFormat = 0x20000,
|
||||
BfEvalExprFlags_NoLookupError = 0x40000,
|
||||
BfEvalExprFlags_ConstExpr = 0x80000,
|
||||
BfEvalExprFlags_ConstEval = 0x80000,
|
||||
BfEvalExprFlags_InCascade = 0x100000,
|
||||
};
|
||||
|
||||
enum BfCastFlags
|
||||
|
@ -904,13 +905,15 @@ public:
|
|||
|
||||
~BfLambdaInstance()
|
||||
{
|
||||
delete mMethodInstance->mMethodDef;
|
||||
auto methodDef = mMethodInstance->mMethodDef;
|
||||
delete mMethodInstance;
|
||||
delete methodDef;
|
||||
|
||||
if (mDtorMethodInstance != NULL)
|
||||
{
|
||||
delete mDtorMethodInstance->mMethodDef;
|
||||
auto methodDef = mDtorMethodInstance->mMethodDef;
|
||||
delete mDtorMethodInstance;
|
||||
delete methodDef;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -10169,7 +10169,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
|||
|
||||
if (allowCast)
|
||||
{
|
||||
if (ignoreWrites)
|
||||
if ((ignoreWrites) && (!typedVal.mValue.IsConst()))
|
||||
return mBfIRBuilder->GetFakeVal();
|
||||
return mBfIRBuilder->CreateBitCast(typedVal.mValue, mBfIRBuilder->MapType(toType));
|
||||
}
|
||||
|
@ -10566,12 +10566,13 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
|||
|
||||
auto undefConst = (BfConstantUndef*)constant;
|
||||
|
||||
auto fakeVal = GetFakeTypedValue(GetPrimitiveType(undefConst->mTypeCode));
|
||||
// Why did we have this BfCastFlags_Explicit? It broke creating errors on things like "int16 val = TCount;"
|
||||
//auto val = CastToValue(srcNode, fakeVal, toType, (BfCastFlags)(castFlags | BfCastFlags_Explicit));
|
||||
BF_ASSERT(undefConst->mType.mKind == BfIRTypeData::TypeKind_TypeId);
|
||||
auto bfType = mContext->mTypes[undefConst->mType.mId];
|
||||
|
||||
auto fakeVal = GetFakeTypedValue(bfType);
|
||||
auto val = CastToValue(srcNode, fakeVal, toType, castFlags);
|
||||
if (val)
|
||||
return val;
|
||||
return mBfIRBuilder->GetUndefConstValue(mBfIRBuilder->MapType(toType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5441,7 +5441,7 @@ BfExpression* BfReducer::CreateAttributedExpression(BfTokenNode* tokenNode, bool
|
|||
|
||||
if (!onlyAllowIdentifier)
|
||||
{
|
||||
BfExpression* expr = CreateExpressionAfter(attrib);
|
||||
BfExpression* expr = CreateExpressionAfter(attrib, CreateExprFlags_EarlyExit);
|
||||
if (expr != NULL)
|
||||
{
|
||||
if (auto identifier = BfNodeDynCast<BfIdentifierNode>(expr))
|
||||
|
|
|
@ -535,6 +535,13 @@ BfMethodInfoEx::~BfMethodInfoEx()
|
|||
|
||||
BfMethodInstance::~BfMethodInstance()
|
||||
{
|
||||
if (mMethodInstanceGroup != NULL)
|
||||
BfLogSys(GetOwner()->mModule->mSystem, "BfMethodInstance::~BfMethodInstance %p Local:%d InCEMachine:%d\n", this, mMethodDef->mIsLocalMethod, mInCEMachine);
|
||||
else
|
||||
{
|
||||
BF_ASSERT(!mMethodDef->mIsLocalMethod);
|
||||
}
|
||||
|
||||
if (mInCEMachine)
|
||||
{
|
||||
auto module = GetOwner()->mModule;
|
||||
|
|
|
@ -6441,7 +6441,12 @@ void BfModule::Visit(BfForEachStatement* forEachStmt)
|
|||
auto retVal = exprEvaluator.CreateCall(&methodMatcher, itr);
|
||||
if (exprEvaluator.mReceivingValue != NULL)
|
||||
{
|
||||
AssertErrorState();
|
||||
if (mIsConstModule)
|
||||
{
|
||||
mBfIRBuilder->CreateStore(retVal.mValue, nextResult.mValue);
|
||||
}
|
||||
else
|
||||
AssertErrorState();
|
||||
}
|
||||
if ((retVal) && (!retVal.mType->IsVar()))
|
||||
{
|
||||
|
|
|
@ -733,6 +733,7 @@ public:
|
|||
bool mIsNoSplat;
|
||||
bool mIsNoReflect;
|
||||
bool mIsSkipCall;
|
||||
bool mIsConstEval;
|
||||
bool mIsOperator;
|
||||
bool mIsExtern;
|
||||
bool mIsNoDiscard;
|
||||
|
@ -761,6 +762,7 @@ public:
|
|||
mIsNoSplat = false;
|
||||
mIsNoReflect = false;
|
||||
mIsSkipCall = false;
|
||||
mIsConstEval = false;
|
||||
mIsOperator = false;
|
||||
mIsExtern = false;
|
||||
mIsNoDiscard = false;
|
||||
|
|
|
@ -214,6 +214,13 @@ CeFunction::~CeFunction()
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CeFunctionInfo::~CeFunctionInfo()
|
||||
{
|
||||
delete mCeFunction;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define CE_GET(T) *((T*)(mPtr += sizeof(T)) - 1)
|
||||
|
||||
void CeDumpContext::DumpOperandInfo(CeOperandInfoKind operandInfoKind)
|
||||
|
@ -2151,6 +2158,10 @@ void CeBuilder::Build()
|
|||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
mcAgg = GetOperand(castedInst->mAggVal);
|
||||
}
|
||||
|
||||
auto aggType = mcAgg.mType;
|
||||
int byteOffset = 0;
|
||||
|
@ -2590,8 +2601,10 @@ CeMachine::CeMachine(BfCompiler* compiler)
|
|||
mCeModule = NULL;
|
||||
mRevision = 0;
|
||||
mExecuteId = 0;
|
||||
mRevisionExecuteTime = 0;
|
||||
mCurTargetSrc = NULL;
|
||||
mCurModule = NULL;
|
||||
mCurMethodInstance = NULL;
|
||||
mCurExpectingType = NULL;
|
||||
mHeap = NULL;
|
||||
mStringCharsOffset = -1;
|
||||
|
@ -2613,7 +2626,7 @@ CeMachine::~CeMachine()
|
|||
|
||||
BfError* CeMachine::Fail(const StringImpl& error)
|
||||
{
|
||||
auto bfError = mCurModule->Fail("Unable to const-evaluate function", mCurTargetSrc);
|
||||
auto bfError = mCurModule->Fail(StrFormat("Unable to const-evaluate %s", mCurModule->MethodToString(mCurMethodInstance).c_str()), mCurTargetSrc);
|
||||
if (bfError == NULL)
|
||||
return NULL;
|
||||
mCompiler->mPassInstance->MoreInfo(error);
|
||||
|
@ -2622,7 +2635,7 @@ BfError* CeMachine::Fail(const StringImpl& error)
|
|||
|
||||
BfError* CeMachine::Fail(const CeFrame& curFrame, const StringImpl& str)
|
||||
{
|
||||
auto bfError = mCurModule->Fail("Unable to const-evaluate function", mCurTargetSrc);
|
||||
auto bfError = mCurModule->Fail(StrFormat("Unable to const-evaluate %s", mCurModule->MethodToString(mCurMethodInstance).c_str()), mCurTargetSrc);
|
||||
if (bfError == NULL)
|
||||
return NULL;
|
||||
|
||||
|
@ -2696,7 +2709,11 @@ void CeMachine::Init()
|
|||
mCeModule->mIsSpecialModule = true;
|
||||
//mCeModule->mIsScratchModule = true;
|
||||
mCeModule->mIsConstModule = true;
|
||||
mCeModule->mIsReified = true;
|
||||
//mCeModule->mIsReified = true;
|
||||
if (mCompiler->mIsResolveOnly)
|
||||
mCeModule->mIsReified = true;
|
||||
else
|
||||
mCeModule->mIsReified = false;
|
||||
mCeModule->Init();
|
||||
|
||||
mCeModule->mBfIRBuilder = new BfIRBuilder(mCeModule);
|
||||
|
@ -2731,6 +2748,28 @@ bool CeMachine::CeFree(addr_ce addr)
|
|||
#endif
|
||||
}
|
||||
|
||||
addr_ce CeMachine::CeAllocArray(BfArrayType* arrayType, int count, addr_ce& elemsAddr)
|
||||
{
|
||||
mCeModule->PopulateType(arrayType);
|
||||
|
||||
BfType* elemType = arrayType->GetUnderlyingType();
|
||||
auto countOffset = arrayType->mBaseType->mFieldInstances[0].mDataOffset;
|
||||
auto elemOffset = arrayType->mFieldInstances[0].mDataOffset;
|
||||
|
||||
int allocSize = elemOffset + elemType->GetStride() * count;
|
||||
|
||||
uint8* mem = CeMalloc(allocSize);
|
||||
|
||||
memset(mem, 0, allocSize);
|
||||
|
||||
*(int32*)(mem) = arrayType->mTypeId;
|
||||
*(int32*)(mem + countOffset) = count;
|
||||
|
||||
elemsAddr = (addr_ce)(mem + elemOffset - mMemory.mVals);
|
||||
|
||||
return (addr_ce)(mem - mMemory.mVals);
|
||||
}
|
||||
|
||||
addr_ce CeMachine::GetConstantData(BeConstant* constant)
|
||||
{
|
||||
auto writeConstant = constant;
|
||||
|
@ -2889,6 +2928,7 @@ BeModule* CeMachine::GetBeModule()
|
|||
|
||||
void CeMachine::CompileStarted()
|
||||
{
|
||||
mRevisionExecuteTime = 0;
|
||||
mRevision++;
|
||||
if (mCeModule != NULL)
|
||||
{
|
||||
|
@ -2912,37 +2952,48 @@ void CeMachine::DerefMethodInfo(CeFunctionInfo* ceFunctionInfo)
|
|||
|
||||
void CeMachine::RemoveMethod(BfMethodInstance* methodInstance)
|
||||
{
|
||||
BfLogSys(methodInstance->GetOwner()->mModule->mSystem, "CeMachine::RemoveMethod %p\n", methodInstance);
|
||||
|
||||
auto itr = mFunctions.Find(methodInstance);
|
||||
auto ceFunctionInfo = itr->mValue;
|
||||
BF_ASSERT(itr != mFunctions.end());
|
||||
if (itr != mFunctions.end())
|
||||
{
|
||||
auto ceFunction = ceFunctionInfo->mCeFunction;
|
||||
for (auto& callEntry : ceFunction->mCallTable)
|
||||
if (ceFunctionInfo->mMethodInstance == methodInstance)
|
||||
{
|
||||
if (callEntry.mFunctionInfo != NULL)
|
||||
DerefMethodInfo(callEntry.mFunctionInfo);
|
||||
}
|
||||
delete ceFunction;
|
||||
ceFunctionInfo->mCeFunction = NULL;
|
||||
ceFunctionInfo->mMethodInstance = NULL;
|
||||
auto ceFunction = ceFunctionInfo->mCeFunction;
|
||||
for (auto& callEntry : ceFunction->mCallTable)
|
||||
{
|
||||
if (callEntry.mFunctionInfo != NULL)
|
||||
DerefMethodInfo(callEntry.mFunctionInfo);
|
||||
}
|
||||
delete ceFunction;
|
||||
ceFunctionInfo->mCeFunction = NULL;
|
||||
ceFunctionInfo->mMethodInstance = NULL;
|
||||
|
||||
if (ceFunctionInfo->mRefCount > 1)
|
||||
{
|
||||
// Generate a methodref
|
||||
ceFunctionInfo->mMethodRef = methodInstance;
|
||||
}
|
||||
if (methodInstance->mMethodDef->mIsLocalMethod)
|
||||
{
|
||||
// We can't rebuild these anyway
|
||||
}
|
||||
else if (ceFunctionInfo->mRefCount > 1)
|
||||
{
|
||||
// Generate a methodref
|
||||
ceFunctionInfo->mMethodRef = methodInstance;
|
||||
}
|
||||
|
||||
DerefMethodInfo(ceFunctionInfo);
|
||||
DerefMethodInfo(ceFunctionInfo);
|
||||
}
|
||||
|
||||
mFunctions.Remove(itr);
|
||||
}
|
||||
|
||||
CheckFunctions();
|
||||
}
|
||||
|
||||
//#define CE_GETC(T) *((T*)(addr += sizeof(T)) - 1)
|
||||
#define CE_GETC(T) *(T*)(mMemory.mVals + addr)
|
||||
|
||||
bool CeMachine::WriteConstant(BfModule* module, addr_ce addr, BfConstant* constant, BfType* type)
|
||||
bool CeMachine::WriteConstant(BfModule* module, addr_ce addr, BfConstant* constant, BfType* type, bool isParams)
|
||||
{
|
||||
switch (constant->mTypeCode)
|
||||
{
|
||||
|
@ -2987,6 +3038,54 @@ bool CeMachine::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
|
|||
{
|
||||
return false;
|
||||
}
|
||||
else if (type->IsArray())
|
||||
{
|
||||
auto elemType = type->GetUnderlyingType();
|
||||
|
||||
addr_ce elemsAddr = 0;
|
||||
addr_ce arrayAddr = CeAllocArray((BfArrayType*)type, aggConstant->mValues.size(), elemsAddr);
|
||||
|
||||
for (int i = 0; i < (int)aggConstant->mValues.size(); i++)
|
||||
{
|
||||
auto fieldConstant = module->mBfIRBuilder->GetConstant(aggConstant->mValues[i]);
|
||||
if (fieldConstant == NULL)
|
||||
return false;
|
||||
WriteConstant(module, elemsAddr + i * elemType->GetStride(), fieldConstant, elemType);
|
||||
}
|
||||
|
||||
if (mCeModule->mSystem->mPtrSize == 4)
|
||||
CE_GETC(int32) = arrayAddr;
|
||||
else
|
||||
CE_GETC(int64) = arrayAddr;
|
||||
|
||||
return true;
|
||||
}
|
||||
else if ((type->IsInstanceOf(module->mCompiler->mSpanTypeDef)) && (isParams))
|
||||
{
|
||||
auto elemType = type->GetUnderlyingType();
|
||||
addr_ce elemsAddr = CeMalloc(elemType->GetStride() * aggConstant->mValues.size()) - mMemory.mVals;
|
||||
|
||||
for (int i = 0; i < (int)aggConstant->mValues.size(); i++)
|
||||
{
|
||||
auto fieldConstant = module->mBfIRBuilder->GetConstant(aggConstant->mValues[i]);
|
||||
if (fieldConstant == NULL)
|
||||
return false;
|
||||
WriteConstant(module, elemsAddr + i * elemType->GetStride(), fieldConstant, elemType);
|
||||
}
|
||||
|
||||
if (mCeModule->mSystem->mPtrSize == 4)
|
||||
{
|
||||
CE_GETC(int32) = elemsAddr;
|
||||
addr += 4;
|
||||
CE_GETC(int32) = (int32)aggConstant->mValues.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
CE_GETC(int32) = elemsAddr;
|
||||
addr += 8;
|
||||
CE_GETC(int64) = (int32)aggConstant->mValues.size();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BF_ASSERT(type->IsStruct());
|
||||
|
@ -3087,7 +3186,40 @@ CeErrorKind CeMachine::WriteConstant(CeConstStructData& data, BeConstant* constV
|
|||
}
|
||||
|
||||
if (globalVar->mInitializer == NULL)
|
||||
return CeErrorKind_GlobalVariable;
|
||||
{
|
||||
auto ptr = data.mData.GrowUninitialized(mCeModule->mSystem->mPtrSize);
|
||||
int64 addr64 = (addr_ce)0;
|
||||
memcpy(ptr, &addr64, mCeModule->mSystem->mPtrSize);
|
||||
return CeErrorKind_None;
|
||||
|
||||
//TODO: Add this global variable in there and fixup
|
||||
|
||||
// CeStaticFieldInfo* staticFieldInfoPtr = NULL;
|
||||
// if (mCeMachine->mStaticFieldMap.TryGetValue(globalVar->mName, &staticFieldInfoPtr))
|
||||
// {
|
||||
// CeStaticFieldInfo* staticFieldInfo = staticFieldInfoPtr;
|
||||
//
|
||||
// int* staticFieldTableIdxPtr = NULL;
|
||||
// if (mStaticFieldMap.TryAdd(globalVar, NULL, &staticFieldTableIdxPtr))
|
||||
// {
|
||||
// CeStaticFieldEntry staticFieldEntry;
|
||||
// staticFieldEntry.mTypeId = staticFieldInfo->mFieldInstance->mOwner->mTypeId;
|
||||
// staticFieldEntry.mName = globalVar->mName;
|
||||
// staticFieldEntry.mSize = globalVar->mType->mSize;
|
||||
// *staticFieldTableIdxPtr = (int)mCeFunction->mStaticFieldTable.size();
|
||||
// mCeFunction->mStaticFieldTable.Add(staticFieldEntry);
|
||||
// }
|
||||
//
|
||||
// auto result = FrameAlloc(mCeMachine->GetBeContext()->GetPointerTo(globalVar->mType));
|
||||
//
|
||||
// Emit(CeOp_GetStaticField);
|
||||
// EmitFrameOffset(result);
|
||||
// Emit((int32)*staticFieldTableIdxPtr);
|
||||
//
|
||||
// return result;
|
||||
// }
|
||||
// return CeErrorKind_GlobalVariable;
|
||||
}
|
||||
|
||||
|
||||
BF_ASSERT(!data.mQueueFixups);
|
||||
|
@ -3375,7 +3507,7 @@ BfIRValue CeMachine::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType
|
|||
|
||||
if (typeInst->IsInstanceOf(mCeModule->mCompiler->mSpanTypeDef))
|
||||
{
|
||||
if ((outType != NULL) && (mCurExpectingType->IsSizedArray()))
|
||||
if ((outType != NULL) && ((mCurExpectingType == NULL) || (mCurExpectingType->IsSizedArray())))
|
||||
{
|
||||
module->PopulateType(typeInst);
|
||||
|
||||
|
@ -3402,6 +3534,9 @@ BfIRValue CeMachine::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType
|
|||
*outType = module->CreateSizedArrayType(elemType, lenVal);
|
||||
return instResult;
|
||||
}
|
||||
|
||||
Fail(StrFormat("Span return type '%s' must be received by a sized array", module->TypeToString(typeInst).c_str()));
|
||||
return BfIRValue();
|
||||
}
|
||||
|
||||
if (typeInst->IsObjectOrInterface())
|
||||
|
@ -3599,6 +3734,8 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
|
|||
uint8* stackPtr = startStackPtr;
|
||||
uint8* framePtr = startFramePtr;
|
||||
|
||||
volatile bool* cancelPtr = &mCompiler->mCanceling;
|
||||
|
||||
auto _GetCurFrame = [&]()
|
||||
{
|
||||
CeFrame ceFrame;
|
||||
|
@ -3659,32 +3796,6 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
|
|||
handled = true;
|
||||
return true;
|
||||
}
|
||||
else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite)
|
||||
{
|
||||
int32 ptrVal = *(int32*)((uint8*)stackPtr + 0);
|
||||
auto size = *(int32*)(stackPtr + mCeModule->mSystem->mPtrSize);
|
||||
CE_CHECKADDR(ptrVal, size);
|
||||
char* strPtr = (char*)(ptrVal + memStart);
|
||||
String str;
|
||||
str.Insert(0, strPtr, size);
|
||||
OutputDebugStr(str);
|
||||
handled = true;
|
||||
return true;
|
||||
}
|
||||
else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite_Int)
|
||||
{
|
||||
int32 intVal = *(int32*)((uint8*)stackPtr + 0);
|
||||
OutputDebugStrF("Debug Val: %d\n", intVal);
|
||||
handled = true;
|
||||
return true;
|
||||
}
|
||||
else if (checkFunction->mFunctionKind == CeFunctionKind_GetReflectType)
|
||||
{
|
||||
int32 typeId = *(int32*)((uint8*)stackPtr + mCeModule->mSystem->mPtrSize);
|
||||
auto reflectType = GetReflectType(typeId);
|
||||
_FixVariables();
|
||||
*(addr_ce*)(stackPtr + 0) = reflectType;
|
||||
}
|
||||
else if (checkFunction->mFunctionKind == CeFunctionKind_FatalError)
|
||||
{
|
||||
int32 strInstAddr = *(int32*)((uint8*)stackPtr + 0);
|
||||
|
@ -3725,6 +3836,67 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
|
|||
|
||||
return false;
|
||||
}
|
||||
else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite)
|
||||
{
|
||||
int32 ptrVal = *(int32*)((uint8*)stackPtr + 0);
|
||||
auto size = *(int32*)(stackPtr + mCeModule->mSystem->mPtrSize);
|
||||
CE_CHECKADDR(ptrVal, size);
|
||||
char* strPtr = (char*)(ptrVal + memStart);
|
||||
String str;
|
||||
str.Insert(0, strPtr, size);
|
||||
OutputDebugStr(str);
|
||||
handled = true;
|
||||
return true;
|
||||
}
|
||||
else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite_Int)
|
||||
{
|
||||
int32 intVal = *(int32*)((uint8*)stackPtr + 0);
|
||||
OutputDebugStrF("Debug Val: %d\n", intVal);
|
||||
handled = true;
|
||||
return true;
|
||||
}
|
||||
else if (checkFunction->mFunctionKind == CeFunctionKind_GetReflectType)
|
||||
{
|
||||
addr_ce objAddr = *(addr_ce*)((uint8*)stackPtr + mCeModule->mSystem->mPtrSize);
|
||||
CE_CHECKADDR(addr_ce, 4);
|
||||
int32 typeId = *(int32*)(objAddr + memStart);
|
||||
|
||||
auto reflectType = GetReflectType(typeId);
|
||||
_FixVariables();
|
||||
*(addr_ce*)(stackPtr + 0) = reflectType;
|
||||
handled = true;
|
||||
return true;
|
||||
}
|
||||
else if (checkFunction->mFunctionKind == CeFunctionKind_GetReflectTypeById)
|
||||
{
|
||||
int32 typeId = *(int32*)((uint8*)stackPtr + mCeModule->mSystem->mPtrSize);
|
||||
auto reflectType = GetReflectType(typeId);
|
||||
_FixVariables();
|
||||
*(addr_ce*)(stackPtr + 0) = reflectType;
|
||||
handled = true;
|
||||
return true;
|
||||
}
|
||||
else if (checkFunction->mFunctionKind == CeFunctionKind_Sleep)
|
||||
{
|
||||
int32 sleepMS = *(int32*)((uint8*)stackPtr);
|
||||
while (sleepMS > 0)
|
||||
{
|
||||
if (*cancelPtr)
|
||||
break;
|
||||
|
||||
if (sleepMS > 200)
|
||||
{
|
||||
Sleep(200);
|
||||
sleepMS -= 200;
|
||||
continue;
|
||||
}
|
||||
Sleep(sleepMS);
|
||||
break;
|
||||
}
|
||||
|
||||
handled = true;
|
||||
return true;
|
||||
}
|
||||
else if (checkFunction->mFunctionKind == CeFunctionKind_Char32_ToLower)
|
||||
{
|
||||
int32& result = *(int32*)((uint8*)stackPtr + 0);
|
||||
|
@ -3849,8 +4021,6 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
|
|||
return true;
|
||||
}
|
||||
|
||||
volatile bool* cancelPtr = &mCompiler->mCanceling;
|
||||
|
||||
int callCount = 0;
|
||||
int instIdx = 0;
|
||||
|
||||
|
@ -3858,7 +4028,7 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
|
|||
{
|
||||
if (*cancelPtr)
|
||||
{
|
||||
_Fail("Cancelled");
|
||||
_Fail("Compilation cancelled");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -4989,6 +5159,8 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
|
|||
|
||||
void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder)
|
||||
{
|
||||
AutoTimer autoTimer(mRevisionExecuteTime);
|
||||
|
||||
if (mHeap == NULL)
|
||||
mHeap = new ContiguousHeap();
|
||||
|
||||
|
@ -5007,6 +5179,13 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder
|
|||
ceFunction->mFunctionKind = CeFunctionKind_GetReflectType;
|
||||
}
|
||||
}
|
||||
else if (owner->IsInstanceOf(mCeModule->mCompiler->mTypeTypeDef))
|
||||
{
|
||||
if (methodDef->mName == "ConstEval_GetTypeById")
|
||||
{
|
||||
ceFunction->mFunctionKind = CeFunctionKind_GetReflectTypeById;
|
||||
}
|
||||
}
|
||||
else if (owner->IsInstanceOf(mCeModule->mCompiler->mDiagnosticsDebugTypeDef))
|
||||
{
|
||||
if (methodDef->mName == "Write")
|
||||
|
@ -5017,6 +5196,11 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder
|
|||
ceFunction->mFunctionKind = CeFunctionKind_DebugWrite;
|
||||
}
|
||||
}
|
||||
else if (owner->IsInstanceOf(mCeModule->mCompiler->mThreadTypeDef))
|
||||
{
|
||||
if (methodDef->mName == "SleepInternal")
|
||||
ceFunction->mFunctionKind = CeFunctionKind_Sleep;
|
||||
}
|
||||
else if (owner->IsInstanceOf(mCeModule->mCompiler->mInternalTypeDef))
|
||||
{
|
||||
if (methodDef->mName == "ThrowIndexOutOfRange")
|
||||
|
@ -5063,7 +5247,7 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder
|
|||
ceBuilder.mCeFunction = ceFunction;
|
||||
ceBuilder.Build();
|
||||
|
||||
if (!ceFunction->mCode.IsEmpty())
|
||||
/*if (!ceFunction->mCode.IsEmpty())
|
||||
{
|
||||
CeDumpContext dumpCtx;
|
||||
dumpCtx.mCeFunction = ceFunction;
|
||||
|
@ -5073,6 +5257,14 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder
|
|||
dumpCtx.Dump();
|
||||
|
||||
OutputDebugStrF("Code for %s:\n%s\n", ceBuilder.mBeFunction->mName.c_str(), dumpCtx.mStr.c_str());
|
||||
}*/
|
||||
}
|
||||
|
||||
void CeMachine::CheckFunctions()
|
||||
{
|
||||
for (auto kv : mFunctions)
|
||||
{
|
||||
BF_ASSERT((((intptr)(void*)kv.mKey->mMethodDef) & 0xFF) != 0xDD);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5084,6 +5276,8 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f
|
|||
return NULL;
|
||||
}
|
||||
|
||||
CheckFunctions();
|
||||
|
||||
CeFunctionInfo** functionInfoPtr = NULL;
|
||||
CeFunctionInfo* ceFunctionInfo = NULL;
|
||||
CeFunction* ceFunction = NULL;
|
||||
|
@ -5094,6 +5288,11 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f
|
|||
return ceFunctionInfo->mCeFunction;
|
||||
}
|
||||
|
||||
BF_ASSERT(!methodInstance->mInCEMachine);
|
||||
methodInstance->mInCEMachine = true;
|
||||
|
||||
BfLogSys(mCeModule->mSystem, "CeMachine::GetFunction %p\n", methodInstance);
|
||||
|
||||
if (!func)
|
||||
{
|
||||
ceFunctionInfo = new CeFunctionInfo();
|
||||
|
@ -5130,8 +5329,7 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f
|
|||
added = true;
|
||||
auto module = methodInstance->GetOwner()->mModule;
|
||||
|
||||
BF_ASSERT(!methodInstance->mInCEMachine);
|
||||
methodInstance->mInCEMachine = true;
|
||||
BF_ASSERT(ceFunctionInfo->mCeFunction == NULL);
|
||||
|
||||
ceFunction = new CeFunction();
|
||||
ceFunction->mCeFunctionInfo = ceFunctionInfo;
|
||||
|
@ -5140,6 +5338,8 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f
|
|||
ceFunctionInfo->mMethodInstance = methodInstance;
|
||||
ceFunctionInfo->mCeFunction = ceFunction;
|
||||
}
|
||||
|
||||
|
||||
return ceFunction;
|
||||
}
|
||||
|
||||
|
@ -5189,13 +5389,23 @@ void CeMachine::ClearAppendAllocInfo()
|
|||
|
||||
BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodInstance* methodInstance, const BfSizedArray<BfIRValue>& args, CeEvalFlags flags, BfType* expectingType)
|
||||
{
|
||||
AutoTimer autoTimer(mRevisionExecuteTime);
|
||||
|
||||
// DISABLED
|
||||
return BfTypedValue();
|
||||
//return BfTypedValue();
|
||||
|
||||
SetAndRestoreValue<BfAstNode*> prevTargetSrc(mCurTargetSrc, targetSrc);
|
||||
SetAndRestoreValue<BfModule*> prevModule(mCurModule, module);
|
||||
SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mCurMethodInstance, methodInstance);
|
||||
SetAndRestoreValue<BfType*> prevExpectingType(mCurExpectingType, expectingType);
|
||||
|
||||
if (mAppendAllocInfo != NULL)
|
||||
{
|
||||
if ((mAppendAllocInfo->mAppendSizeValue) && (!mAppendAllocInfo->mAppendSizeValue.IsConst()))
|
||||
{
|
||||
Fail("Non-constant append alloc");
|
||||
return BfTypedValue();
|
||||
}
|
||||
}
|
||||
|
||||
int thisArgIdx = -1;
|
||||
|
@ -5208,20 +5418,37 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
|
|||
appendAllocIdx = 1;
|
||||
}
|
||||
|
||||
for (int argIdx = 0; argIdx < (int)args.size(); argIdx++)
|
||||
int paramCompositeSize = 0;
|
||||
int paramIdx = methodInstance->GetParamCount();
|
||||
for (int argIdx = (int)args.size() - 1; argIdx >= 0; argIdx--)
|
||||
{
|
||||
BfType* paramType = NULL;
|
||||
while (true)
|
||||
{
|
||||
paramIdx--;
|
||||
paramType = methodInstance->GetParamType(paramIdx);
|
||||
if (paramType->IsTypedPrimitive())
|
||||
paramType = paramType->GetUnderlyingType();
|
||||
if (!paramType->IsValuelessType())
|
||||
break;
|
||||
}
|
||||
if (paramType->IsComposite())
|
||||
{
|
||||
auto paramTypeInst = paramType->ToTypeInstance();
|
||||
paramCompositeSize += paramTypeInst->mInstSize;
|
||||
}
|
||||
|
||||
auto arg = args[argIdx];
|
||||
if (!arg.IsConst())
|
||||
{
|
||||
if ((argIdx != thisArgIdx) && (argIdx != appendAllocIdx))
|
||||
{
|
||||
Fail(StrFormat("Non-constant argument for param '%s'", methodInstance->GetParamName(paramIdx).c_str()));
|
||||
return BfTypedValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetAndRestoreValue<BfAstNode*> prevTargetSrc(mCurTargetSrc, targetSrc);
|
||||
SetAndRestoreValue<BfModule*> prevModule(mCurModule, module);
|
||||
SetAndRestoreValue<BfType*> prevExpectingType(mCurExpectingType, expectingType);
|
||||
|
||||
BF_ASSERT(mCallStack.IsEmpty());
|
||||
|
||||
auto methodDef = methodInstance->mMethodDef;
|
||||
|
@ -5287,26 +5514,7 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
|
|||
};
|
||||
|
||||
addr_ce compositeStartAddr = stackPtr - memStart;
|
||||
int paramIdx = methodInstance->GetParamCount();
|
||||
for (int argIdx = (int)args.size() - 1; argIdx >= 0; argIdx--)
|
||||
{
|
||||
BfType* paramType = NULL;
|
||||
while (true)
|
||||
{
|
||||
paramIdx--;
|
||||
paramType = methodInstance->GetParamType(paramIdx);
|
||||
if (paramType->IsTypedPrimitive())
|
||||
paramType = paramType->GetUnderlyingType();
|
||||
if (!paramType->IsValuelessType())
|
||||
break;
|
||||
}
|
||||
if (paramType->IsComposite())
|
||||
{
|
||||
auto paramTypeInst = paramType->ToTypeInstance();
|
||||
stackPtr -= paramTypeInst->mInstSize;
|
||||
}
|
||||
}
|
||||
|
||||
stackPtr -= paramCompositeSize;
|
||||
addr_ce useCompositeAddr = compositeStartAddr;
|
||||
paramIdx = methodInstance->GetParamCount();
|
||||
for (int argIdx = (int)args.size() - 1; argIdx >= 0; argIdx--)
|
||||
|
@ -5322,6 +5530,7 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
|
|||
break;
|
||||
}
|
||||
|
||||
bool isParams = methodInstance->GetParamKind(paramIdx) == BfParamKind_Params;
|
||||
auto arg = args[argIdx];
|
||||
if (!arg.IsConst())
|
||||
{
|
||||
|
@ -5351,8 +5560,11 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
|
|||
{
|
||||
auto paramTypeInst = paramType->ToTypeInstance();
|
||||
useCompositeAddr -= paramTypeInst->mInstSize;
|
||||
if (!WriteConstant(module, useCompositeAddr, constant, paramType))
|
||||
if (!WriteConstant(module, useCompositeAddr, constant, paramType, isParams))
|
||||
{
|
||||
Fail(StrFormat("Failed to process argument for param '%s'", methodInstance->GetParamName(paramIdx).c_str()));
|
||||
return BfTypedValue();
|
||||
}
|
||||
_FixVariables();
|
||||
|
||||
stackPtr -= mCeModule->mSystem->mPtrSize;
|
||||
|
@ -5362,8 +5574,11 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
|
|||
else
|
||||
{
|
||||
stackPtr -= paramType->mSize;
|
||||
if (!WriteConstant(module, stackPtr - memStart, constant, paramType))
|
||||
if (!WriteConstant(module, stackPtr - memStart, constant, paramType, isParams))
|
||||
{
|
||||
Fail(StrFormat("Failed to process argument for param '%s'", methodInstance->GetParamName(paramIdx).c_str()));
|
||||
return BfTypedValue();
|
||||
}
|
||||
_FixVariables();
|
||||
}
|
||||
}
|
||||
|
@ -5405,6 +5620,10 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
|
|||
BfIRValue constVal = CreateConstant(module, retPtr, returnType, &usedReturnType);
|
||||
if (constVal)
|
||||
returnValue = BfTypedValue(constVal, usedReturnType);
|
||||
else
|
||||
{
|
||||
Fail("Failed to encode return argument");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -202,6 +202,8 @@ public:
|
|||
mCeFunction = NULL;
|
||||
mRefCount = 0;
|
||||
}
|
||||
|
||||
~CeFunctionInfo();
|
||||
};
|
||||
|
||||
class CeCallEntry
|
||||
|
@ -247,6 +249,8 @@ enum CeFunctionKind
|
|||
CeFunctionKind_DebugWrite,
|
||||
CeFunctionKind_DebugWrite_Int,
|
||||
CeFunctionKind_GetReflectType,
|
||||
CeFunctionKind_GetReflectTypeById,
|
||||
CeFunctionKind_Sleep,
|
||||
CeFunctionKind_Char32_ToLower,
|
||||
CeFunctionKind_Char32_ToUpper,
|
||||
CeFunctionKind_Char32_IsLower,
|
||||
|
@ -595,6 +599,7 @@ public:
|
|||
BfCompiler* mCompiler;
|
||||
BfModule* mCeModule;
|
||||
int mRevision;
|
||||
int mRevisionExecuteTime;
|
||||
int mExecuteId;
|
||||
|
||||
// These are only valid for the current execution
|
||||
|
@ -610,6 +615,7 @@ public:
|
|||
CeAppendAllocInfo* mAppendAllocInfo;
|
||||
|
||||
BfAstNode* mCurTargetSrc;
|
||||
BfMethodInstance* mCurMethodInstance;
|
||||
BfModule* mCurModule;
|
||||
BfType* mCurExpectingType;
|
||||
|
||||
|
@ -623,6 +629,7 @@ public:
|
|||
void Init();
|
||||
uint8* CeMalloc(int size);
|
||||
bool CeFree(addr_ce addr);
|
||||
addr_ce CeAllocArray(BfArrayType* arrayType, int count, addr_ce& elemsAddr);
|
||||
addr_ce GetReflectType(int typeId);
|
||||
addr_ce GetString(int stringId);
|
||||
addr_ce GetConstantData(BeConstant* constant);
|
||||
|
@ -633,13 +640,15 @@ public:
|
|||
BeModule* GetBeModule();
|
||||
void DerefMethodInfo(CeFunctionInfo* ceFunctionInfo);
|
||||
void RemoveMethod(BfMethodInstance* methodInstance);
|
||||
bool WriteConstant(BfModule* module, addr_ce addr, BfConstant* constant, BfType* type);
|
||||
bool WriteConstant(BfModule* module, addr_ce addr, BfConstant* constant, BfType* type, bool isParams = false);
|
||||
CeErrorKind WriteConstant(CeConstStructData& data, BeConstant* constVal);
|
||||
BfIRValue CreateConstant(BfModule* module, uint8* ptr, BfType* type, BfType** outType = NULL);
|
||||
void CreateFunction(BfMethodInstance* methodInstance, CeFunction* ceFunction);
|
||||
bool Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* startFramePtr);
|
||||
|
||||
void PrepareFunction(CeFunction* methodInstance, CeBuilder* parentBuilder);
|
||||
|
||||
void CheckFunctions();
|
||||
CeFunction* GetFunction(BfMethodInstance* methodInstance, BfIRValue func, bool& added);
|
||||
CeFunction* GetPreparedFunction(BfMethodInstance* methodInstance);
|
||||
|
||||
|
|
159
IDEHelper/Tests/src/ConstEval.bf
Normal file
159
IDEHelper/Tests/src/ConstEval.bf
Normal file
|
@ -0,0 +1,159 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Tests
|
||||
{
|
||||
class ConstEval
|
||||
{
|
||||
struct StructA
|
||||
{
|
||||
public int32 mA;
|
||||
public int32 mB;
|
||||
|
||||
public static int32 sVal = 1000;
|
||||
|
||||
public this(int32 a, int32 b)
|
||||
{
|
||||
mA = a + sVal;
|
||||
mB = b;
|
||||
}
|
||||
}
|
||||
|
||||
const String cStrA = "Abc";
|
||||
const String cStrB = GetStringA(cStrA, 12, 23);
|
||||
|
||||
[ConstEval]
|
||||
static String GetStringA(String str, int a, int b)
|
||||
{
|
||||
// Const-eval functions can return scope-allocated data
|
||||
return scope $"{str}:{a}:{b}";
|
||||
}
|
||||
|
||||
static int32 Factorial(int32 n)
|
||||
{
|
||||
return n <= 1 ? 1 : (n * Factorial(n - 1));
|
||||
}
|
||||
|
||||
static int32 Fibonacci(int32 n)
|
||||
{
|
||||
return n <= 1 ? n : Fibonacci(n - 1) + Fibonacci(n - 2);
|
||||
}
|
||||
|
||||
public static String GetTypeDesc<T>()
|
||||
{
|
||||
String str = scope .();
|
||||
|
||||
T val = default;
|
||||
val.GetType().GetFullName(str);
|
||||
str.Append(" ");
|
||||
|
||||
for (var fieldInfo in typeof(T).GetFields())
|
||||
{
|
||||
if (!fieldInfo.IsInstanceField)
|
||||
continue;
|
||||
if (@fieldInfo.Index > 0)
|
||||
str.Append(", ");
|
||||
fieldInfo.FieldType.GetFullName(str);
|
||||
str.Append(" ");
|
||||
str.Append(fieldInfo.Name);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
public static Span<int32> GetSorted(String numList)
|
||||
{
|
||||
List<int32> list = scope .();
|
||||
for (var sv in numList.Split(','))
|
||||
{
|
||||
sv.Trim();
|
||||
if (int32.Parse(sv) case .Ok(let val))
|
||||
list.Add(val);
|
||||
}
|
||||
list.Sort();
|
||||
return list;
|
||||
}
|
||||
|
||||
public static int32 MethodA()
|
||||
{
|
||||
mixin Add10(var a)
|
||||
{
|
||||
a += 10
|
||||
}
|
||||
|
||||
int32 a = 1;
|
||||
|
||||
void Inc()
|
||||
{
|
||||
a++;
|
||||
}
|
||||
|
||||
for (int i < 2)
|
||||
{
|
||||
defer { a *= 2; }
|
||||
Inc();
|
||||
Add10!(a);
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
// This method can only be const evaluated
|
||||
[ConstEval]
|
||||
public static int32 ConstSum(params int32[] vals)
|
||||
{
|
||||
int32 sum = 0;
|
||||
for (let val in vals)
|
||||
sum += val;
|
||||
return sum;
|
||||
}
|
||||
|
||||
public static int32 MethodB()
|
||||
{
|
||||
// Returns different results depending on whether we are const-evaluating
|
||||
return Compiler.IsConstEval ? 1 : 0;
|
||||
}
|
||||
|
||||
public static int32 MethodC(StructA sa = .(1, 2), (int32, int32) tup = (20, 30), int32[2] arr = .(300, 400))
|
||||
{
|
||||
return sa.mA + sa.mB + tup.0 + tup.1 + arr[0] + arr[1];
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void TestBasics()
|
||||
{
|
||||
const int fac = Factorial(8);
|
||||
Test.Assert(fac == 40320);
|
||||
const int fib = Fibonacci(27);
|
||||
Test.Assert(fib == 196418);
|
||||
|
||||
// Generated string has reference equality to equivalent literal
|
||||
Test.Assert(cStrB === "Abc:12:23");
|
||||
|
||||
const String strC = GetTypeDesc<StructA>();
|
||||
Test.Assert(strC === "Tests.ConstEval.StructA int32 mA, int32 mB");
|
||||
|
||||
// Const Span<T> results can be used to initialize statically-sized arrays
|
||||
const int32[?] iArr = GetSorted("8, 1, 3, 7");
|
||||
Compiler.Assert(iArr == .(1, 3, 7, 8));
|
||||
Test.Assert(iArr == .(1, 3, 7, 8));
|
||||
|
||||
let val0 = [ConstEval]MethodA();
|
||||
Compiler.Assert(val0 == 70);
|
||||
let val1 = MethodA();
|
||||
// 'val1' is a read-only variable, but not const, so the following line would fail
|
||||
//Compiler.Assert(val1 == 24);
|
||||
Test.Assert(val1 == 70);
|
||||
|
||||
// This method is marked as ConstEval so it always evaluates as const
|
||||
let val2 = ConstSum(3, 20, 100);
|
||||
Compiler.Assert(val2 == 123);
|
||||
|
||||
Test.Assert(MethodB() == 0);
|
||||
Test.Assert([ConstEval]MethodB() == 1);
|
||||
|
||||
Test.Assert(MethodC() == 1753);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue