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

Fixed deferred function call

This commit is contained in:
Brian Fiete 2025-03-08 11:02:07 -08:00
parent 805d312c98
commit be0733d37c
6 changed files with 81 additions and 25 deletions

View file

@ -3356,8 +3356,7 @@ BfExprEvaluator::BfExprEvaluator(BfModule* module)
mExpectingType = NULL; mExpectingType = NULL;
mFunctionBindResult = NULL; mFunctionBindResult = NULL;
mExplicitCast = false; mExplicitCast = false;
mDeferCallRef = NULL; mDeferCallData = NULL;
mDeferScopeAlloc = NULL;
mPrefixedAttributeState = NULL; mPrefixedAttributeState = NULL;
mResolveGenericParam = true; mResolveGenericParam = true;
mNoBind = false; mNoBind = false;
@ -6938,7 +6937,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance*
if (methodInstance->mVirtualTableIdx != -1) if (methodInstance->mVirtualTableIdx != -1)
{ {
if ((!bypassVirtual) && (mDeferCallRef == NULL)) if ((!bypassVirtual) && (mDeferCallData == NULL))
{ {
if ((methodDef->mIsOverride) && (mModule->mCurMethodInstance->mIsReified)) if ((methodDef->mIsOverride) && (mModule->mCurMethodInstance->mIsReified))
{ {
@ -7107,9 +7106,12 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance*
return _GetDefaultReturnValue(); return _GetDefaultReturnValue();
} }
if (mDeferCallRef != NULL) if (mDeferCallData != NULL)
{ {
mModule->AddDeferredCall(BfModuleMethodInstance(methodInstance, func), irArgs, mDeferScopeAlloc, mDeferCallRef, bypassVirtual); if (mDeferCallData->mFuncAlloca_Orig == func)
mModule->AddDeferredCall(BfModuleMethodInstance(methodInstance, mDeferCallData->mFuncAlloca), irArgs, mDeferCallData->mScopeAlloc, mDeferCallData->mRefNode, bypassVirtual, false, true);
else
mModule->AddDeferredCall(BfModuleMethodInstance(methodInstance, func), irArgs, mDeferCallData->mScopeAlloc, mDeferCallData->mRefNode, bypassVirtual);
return mModule->GetFakeTypedValue(returnType); return mModule->GetFakeTypedValue(returnType);
} }
@ -7861,6 +7863,13 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
auto funcType = mModule->mBfIRBuilder->MapMethod(moduleMethodInstance.mMethodInstance); auto funcType = mModule->mBfIRBuilder->MapMethod(moduleMethodInstance.mMethodInstance);
auto funcPtrType = mModule->mBfIRBuilder->GetPointerTo(funcType); auto funcPtrType = mModule->mBfIRBuilder->GetPointerTo(funcType);
moduleMethodInstance.mFunc = mModule->mBfIRBuilder->CreateIntToPtr(target.mValue, funcPtrType); moduleMethodInstance.mFunc = mModule->mBfIRBuilder->CreateIntToPtr(target.mValue, funcPtrType);
if (mDeferCallData != NULL)
{
mDeferCallData->mFuncAlloca_Orig = moduleMethodInstance.mFunc;
mDeferCallData->mFuncAlloca = mModule->CreateAlloca(funcPtrType, target.mType->mAlign, false, "FuncAlloca");
mModule->mBfIRBuilder->CreateStore(mDeferCallData->mFuncAlloca_Orig, mDeferCallData->mFuncAlloca);
}
} }
else if (!methodDef->mIsStatic) else if (!methodDef->mIsStatic)
{ {
@ -8070,7 +8079,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
autoComplete->mIsCapturingMethodMatchInfo = wasCapturingMatchInfo; autoComplete->mIsCapturingMethodMatchInfo = wasCapturingMatchInfo;
}); });
BfScopeData* boxScopeData = mDeferScopeAlloc; BfScopeData* boxScopeData = (mDeferCallData != NULL) ? mDeferCallData->mScopeAlloc : NULL;
if ((boxScopeData == NULL) && (mModule->mCurMethodState != NULL)) if ((boxScopeData == NULL) && (mModule->mCurMethodState != NULL))
boxScopeData = mModule->mCurMethodState->mCurScope; boxScopeData = mModule->mCurMethodState->mCurScope;
@ -9254,9 +9263,9 @@ BfTypedValue BfExprEvaluator::ResolveArgValue(BfResolvedArg& resolvedArg, BfType
if ((argValue) && (argValue.mType != wantType) && (wantType != NULL)) if ((argValue) && (argValue.mType != wantType) && (wantType != NULL))
{ {
if ((mDeferScopeAlloc != NULL) && (wantType == mModule->mContext->mBfObjectType)) if ((mDeferCallData != NULL) && (wantType == mModule->mContext->mBfObjectType))
{ {
BfAllocTarget allocTarget(mDeferScopeAlloc); BfAllocTarget allocTarget(mDeferCallData->mScopeAlloc);
argValue = mModule->BoxValue(expr, argValue, wantType, allocTarget, ((mBfEvalExprFlags & BfEvalExprFlags_Comptime) != 0) ? BfCastFlags_WantsConst : BfCastFlags_None); argValue = mModule->BoxValue(expr, argValue, wantType, allocTarget, ((mBfEvalExprFlags & BfEvalExprFlags_Comptime) != 0) ? BfCastFlags_WantsConst : BfCastFlags_None);
} }
else else
@ -17731,7 +17740,7 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo
if (mModule->mCurMethodState == NULL) if (mModule->mCurMethodState == NULL)
return; return;
if (mDeferCallRef != NULL) if (mDeferCallData != NULL)
{ {
mModule->Fail("Mixins cannot be directly deferred. Consider wrapping in a block.", targetSrc); mModule->Fail("Mixins cannot be directly deferred. Consider wrapping in a block.", targetSrc);
} }
@ -20013,7 +20022,7 @@ BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericTyp
if (!handled) if (!handled)
{ {
SetAndRestoreValue<BfFunctionBindResult*> prevFunctionBindResult(mFunctionBindResult, NULL); SetAndRestoreValue<BfFunctionBindResult*> prevFunctionBindResult(mFunctionBindResult, NULL);
SetAndRestoreValue<BfAstNode*> prevDeferCallRef(mDeferCallRef, NULL); SetAndRestoreValue<BfDeferCallData*> prevDeferCallRef(mDeferCallData, NULL);
BfMethodDef* matchedMethod = GetPropertyMethodDef(mPropDef, BfMethodType_PropertyGetter, mPropCheckedKind, mPropTarget); BfMethodDef* matchedMethod = GetPropertyMethodDef(mPropDef, BfMethodType_PropertyGetter, mPropCheckedKind, mPropTarget);
if (matchedMethod == NULL) if (matchedMethod == NULL)
@ -23198,7 +23207,7 @@ BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedVal
else else
{ {
SetAndRestoreValue<BfEvalExprFlags> prevFlags(mBfEvalExprFlags, (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_NoAutoComplete)); SetAndRestoreValue<BfEvalExprFlags> prevFlags(mBfEvalExprFlags, (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_NoAutoComplete));
SetAndRestoreValue<BfAstNode*> prevDeferCallRef(mDeferCallRef, NULL); SetAndRestoreValue<BfDeferCallData*> prevDeferCallRef(mDeferCallData, NULL);
result = CreateCall(&methodMatcher, callTarget); result = CreateCall(&methodMatcher, callTarget);
} }

View file

@ -401,6 +401,14 @@ enum BfBinOpFlags
BfBinOpFlag_DeferRight = 0x20 BfBinOpFlag_DeferRight = 0x20
}; };
struct BfDeferCallData
{
BfAstNode* mRefNode;
BfScopeData* mScopeAlloc;
BfIRValue mFuncAlloca; // When we need to load
BfIRValue mFuncAlloca_Orig;
};
class BfExprEvaluator : public BfStructuralVisitor class BfExprEvaluator : public BfStructuralVisitor
{ {
public: public:
@ -422,9 +430,8 @@ public:
BfAttributeState* mPrefixedAttributeState; BfAttributeState* mPrefixedAttributeState;
BfTypedValue* mReceivingValue; BfTypedValue* mReceivingValue;
BfFunctionBindResult* mFunctionBindResult; BfFunctionBindResult* mFunctionBindResult;
SizedArray<BfResolvedArg, 2> mIndexerValues; SizedArray<BfResolvedArg, 2> mIndexerValues;
BfAstNode* mDeferCallRef; BfDeferCallData* mDeferCallData;
BfScopeData* mDeferScopeAlloc;
bool mUsedAsStatement; bool mUsedAsStatement;
bool mPropDefBypassVirtual; bool mPropDefBypassVirtual;
bool mExplicitCast; bool mExplicitCast;

View file

@ -2080,23 +2080,23 @@ void BfModule::RestoreScopeState()
mCurMethodState->mTailScope = mCurMethodState->mCurScope; mCurMethodState->mTailScope = mCurMethodState->mCurScope;
} }
BfIRValue BfModule::CreateAlloca(BfType* type, bool addLifetime, const char* name, BfIRValue arraySize) BfIRValue BfModule::CreateAlloca(BfIRType irType, int align, bool addLifetime, const char* name, BfIRValue arraySize)
{ {
if (mBfIRBuilder->mIgnoreWrites) if (mBfIRBuilder->mIgnoreWrites)
return mBfIRBuilder->GetFakeVal(); return mBfIRBuilder->GetFakeVal();
BF_ASSERT((*(int8*)&addLifetime == 1) || (*(int8*)&addLifetime == 0)); BF_ASSERT((*(int8*)&addLifetime == 1) || (*(int8*)&addLifetime == 0));
mBfIRBuilder->PopulateType(type);
auto prevInsertBlock = mBfIRBuilder->GetInsertBlock(); auto prevInsertBlock = mBfIRBuilder->GetInsertBlock();
if (!mBfIRBuilder->mIgnoreWrites) if (!mBfIRBuilder->mIgnoreWrites)
BF_ASSERT(!prevInsertBlock.IsFake()); BF_ASSERT(!prevInsertBlock.IsFake());
mBfIRBuilder->SetInsertPoint(mCurMethodState->mIRHeadBlock); mBfIRBuilder->SetInsertPoint(mCurMethodState->mIRHeadBlock);
BfIRValue allocaInst; BfIRValue allocaInst;
if (arraySize) if (arraySize)
allocaInst = mBfIRBuilder->CreateAlloca(mBfIRBuilder->MapType(type), arraySize); allocaInst = mBfIRBuilder->CreateAlloca(irType, arraySize);
else else
allocaInst = mBfIRBuilder->CreateAlloca(mBfIRBuilder->MapType(type)); allocaInst = mBfIRBuilder->CreateAlloca(irType);
mBfIRBuilder->SetAllocaAlignment(allocaInst, type->mAlign); if (align > 0)
mBfIRBuilder->SetAllocaAlignment(allocaInst, align);
mBfIRBuilder->ClearDebugLocation(allocaInst); mBfIRBuilder->ClearDebugLocation(allocaInst);
if (name != NULL) if (name != NULL)
mBfIRBuilder->SetName(allocaInst, name); mBfIRBuilder->SetName(allocaInst, name);
@ -2110,6 +2110,16 @@ BfIRValue BfModule::CreateAlloca(BfType* type, bool addLifetime, const char* nam
return allocaInst; return allocaInst;
} }
BfIRValue BfModule::CreateAlloca(BfType* type, bool addLifetime, const char* name, BfIRValue arraySize)
{
if (mBfIRBuilder->mIgnoreWrites)
return mBfIRBuilder->GetFakeVal();
BF_ASSERT((*(int8*)&addLifetime == 1) || (*(int8*)&addLifetime == 0));
mBfIRBuilder->PopulateType(type);
return CreateAlloca(mBfIRBuilder->MapType(type), type->mAlign, addLifetime, name, arraySize);
}
BfIRValue BfModule::CreateAllocaInst(BfTypeInstance* typeInst, bool addLifetime, const char* name) BfIRValue BfModule::CreateAllocaInst(BfTypeInstance* typeInst, bool addLifetime, const char* name)
{ {
if (mBfIRBuilder->mIgnoreWrites) if (mBfIRBuilder->mIgnoreWrites)

View file

@ -323,6 +323,7 @@ public:
bool mCastThis; bool mCastThis;
bool mArgsNeedLoad; bool mArgsNeedLoad;
bool mIgnored; bool mIgnored;
bool mIsAllocaFunc;
SLIList<BfDeferredCallEntry*> mDynList; SLIList<BfDeferredCallEntry*> mDynList;
BfIRValue mDynCallTail; BfIRValue mDynCallTail;
@ -1481,6 +1482,7 @@ enum BfDeferredBlockFlags
BfDeferredBlockFlag_DoNullChecks = 2, BfDeferredBlockFlag_DoNullChecks = 2,
BfDeferredBlockFlag_SkipObjectAccessCheck = 4, BfDeferredBlockFlag_SkipObjectAccessCheck = 4,
BfDeferredBlockFlag_MoveNewBlocksToEnd = 8, BfDeferredBlockFlag_MoveNewBlocksToEnd = 8,
BfDeferredBlockFlag_IsAllocaFunc = 0x10
}; };
enum BfGetCustomAttributesFlags enum BfGetCustomAttributesFlags
@ -1696,6 +1698,7 @@ public:
BfTypedValue FlushNullConditional(BfTypedValue result, bool ignoreNullable = false); BfTypedValue FlushNullConditional(BfTypedValue result, bool ignoreNullable = false);
void NewScopeState(bool createLexicalBlock = true, bool flushValueScope = true); // returns prev scope data void NewScopeState(bool createLexicalBlock = true, bool flushValueScope = true); // returns prev scope data
BfIRValue CreateAlloca(BfIRType irType, int align, bool addLifetime = true, const char* name = NULL, BfIRValue arraySize = BfIRValue());
BfIRValue CreateAlloca(BfType* type, bool addLifetime = true, const char* name = NULL, BfIRValue arraySize = BfIRValue()); BfIRValue CreateAlloca(BfType* type, bool addLifetime = true, const char* name = NULL, BfIRValue arraySize = BfIRValue());
BfIRValue CreateAllocaInst(BfTypeInstance* typeInst, bool addLifetime = true, const char* name = NULL); BfIRValue CreateAllocaInst(BfTypeInstance* typeInst, bool addLifetime = true, const char* name = NULL);
BfDeferredCallEntry* AddStackAlloc(BfTypedValue val, BfIRValue arraySize, BfAstNode* refNode, BfScopeData* scope, bool condAlloca = false, bool mayEscape = false, BfIRBlock valBlock = BfIRBlock()); BfDeferredCallEntry* AddStackAlloc(BfTypedValue val, BfIRValue arraySize, BfAstNode* refNode, BfScopeData* scope, bool condAlloca = false, bool mayEscape = false, BfIRBlock valBlock = BfIRBlock());
@ -1721,7 +1724,7 @@ public:
void EmitDeferredCall(BfModuleMethodInstance moduleMethodInstance, SizedArrayImpl<BfIRValue>& llvmArgs, BfDeferredBlockFlags flags = BfDeferredBlockFlag_None); void EmitDeferredCall(BfModuleMethodInstance moduleMethodInstance, SizedArrayImpl<BfIRValue>& llvmArgs, BfDeferredBlockFlags flags = BfDeferredBlockFlag_None);
bool AddDeferredCallEntry(BfDeferredCallEntry* deferredCallEntry, BfScopeData* scope); bool AddDeferredCallEntry(BfDeferredCallEntry* deferredCallEntry, BfScopeData* scope);
BfDeferredCallEntry* AddDeferredBlock(BfBlock* block, BfScopeData* scope, Array<BfDeferredCapture>* captures = NULL); BfDeferredCallEntry* AddDeferredBlock(BfBlock* block, BfScopeData* scope, Array<BfDeferredCapture>* captures = NULL);
BfDeferredCallEntry* AddDeferredCall(const BfModuleMethodInstance& moduleMethodInstance, SizedArrayImpl<BfIRValue>& llvmArgs, BfScopeData* scope, BfAstNode* srcNode = NULL, bool bypassVirtual = false, bool doNullCheck = false); BfDeferredCallEntry* AddDeferredCall(const BfModuleMethodInstance& moduleMethodInstance, SizedArrayImpl<BfIRValue>& llvmArgs, BfScopeData* scope, BfAstNode* srcNode = NULL, bool bypassVirtual = false, bool doNullCheck = false, bool isAllocaFunc = false);
void EmitDeferredCall(BfScopeData* scopeData, BfDeferredCallEntry& deferredCallEntry, bool moveBlocks); void EmitDeferredCall(BfScopeData* scopeData, BfDeferredCallEntry& deferredCallEntry, bool moveBlocks);
void EmitDeferredCallProcessor(BfScopeData* scopeData, SLIList<BfDeferredCallEntry*>& callEntries, BfIRValue callTail); void EmitDeferredCallProcessor(BfScopeData* scopeData, SLIList<BfDeferredCallEntry*>& callEntries, BfIRValue callTail);
void EmitDeferredCallProcessorInstances(BfScopeData* scopeData); void EmitDeferredCallProcessorInstances(BfScopeData* scopeData);

View file

@ -543,11 +543,12 @@ BfDeferredCallEntry* BfModule::AddDeferredBlock(BfBlock* block, BfScopeData* sco
return deferredCallEntry; return deferredCallEntry;
} }
BfDeferredCallEntry* BfModule::AddDeferredCall(const BfModuleMethodInstance& moduleMethodInstance, SizedArrayImpl<BfIRValue>& llvmArgs, BfScopeData* scopeData, BfAstNode* srcNode, bool bypassVirtual, bool doNullCheck) BfDeferredCallEntry* BfModule::AddDeferredCall(const BfModuleMethodInstance& moduleMethodInstance, SizedArrayImpl<BfIRValue>& llvmArgs, BfScopeData* scopeData, BfAstNode* srcNode, bool bypassVirtual, bool doNullCheck, bool isAllocaFunc)
{ {
BfDeferredCallEntry* deferredCallEntry = new BfDeferredCallEntry(); BfDeferredCallEntry* deferredCallEntry = new BfDeferredCallEntry();
BF_ASSERT(moduleMethodInstance); BF_ASSERT(moduleMethodInstance);
deferredCallEntry->mModuleMethodInstance = moduleMethodInstance; deferredCallEntry->mModuleMethodInstance = moduleMethodInstance;
deferredCallEntry->mIsAllocaFunc = isAllocaFunc;
for (auto arg : llvmArgs) for (auto arg : llvmArgs)
{ {
@ -783,7 +784,12 @@ void BfModule::EmitDeferredCall(BfModuleMethodInstance moduleMethodInstance, Siz
} }
BfExprEvaluator expressionEvaluator(this); BfExprEvaluator expressionEvaluator(this);
expressionEvaluator.CreateCall(NULL, moduleMethodInstance.mMethodInstance, moduleMethodInstance.mFunc, ((flags & BfDeferredBlockFlag_BypassVirtual) != 0), llvmArgs);
auto func = moduleMethodInstance.mFunc;
if ((flags & BfDeferredBlockFlag_IsAllocaFunc) != 0)
func = mBfIRBuilder->CreateLoad(func);
expressionEvaluator.CreateCall(NULL, moduleMethodInstance.mMethodInstance, func, ((flags & BfDeferredBlockFlag_BypassVirtual) != 0), llvmArgs);
if ((flags & BfDeferredBlockFlag_DoNullChecks) != 0) if ((flags & BfDeferredBlockFlag_DoNullChecks) != 0)
{ {
@ -914,6 +920,8 @@ void BfModule::EmitDeferredCall(BfScopeData* scopeData, BfDeferredCallEntry& def
flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_DoNullChecks | BfDeferredBlockFlag_SkipObjectAccessCheck | BfDeferredBlockFlag_MoveNewBlocksToEnd); flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_DoNullChecks | BfDeferredBlockFlag_SkipObjectAccessCheck | BfDeferredBlockFlag_MoveNewBlocksToEnd);
if (moveBlocks) if (moveBlocks)
flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_MoveNewBlocksToEnd); flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_MoveNewBlocksToEnd);
if (deferredCallEntry.mIsAllocaFunc)
flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_IsAllocaFunc);
EmitDeferredCall(deferredCallEntry.mModuleMethodInstance, args, flags); EmitDeferredCall(deferredCallEntry.mModuleMethodInstance, args, flags);
} }
@ -926,6 +934,7 @@ void BfModule::EmitDeferredCallProcessor(BfScopeData* scopeData, SLIList<BfDefer
{ {
BfModuleMethodInstance mModuleMethodInstance; BfModuleMethodInstance mModuleMethodInstance;
bool mBypassVirtual; bool mBypassVirtual;
bool mIsAllocaFunc;
}; };
//typedef std::map<int64, _CallInfo> MapType; //typedef std::map<int64, _CallInfo> MapType;
@ -951,6 +960,7 @@ void BfModule::EmitDeferredCallProcessor(BfScopeData* scopeData, SLIList<BfDefer
{ {
callInfo->mModuleMethodInstance = moduleMethodInstance; callInfo->mModuleMethodInstance = moduleMethodInstance;
callInfo->mBypassVirtual = deferredCallEntry->mBypassVirtual; callInfo->mBypassVirtual = deferredCallEntry->mBypassVirtual;
callInfo->mIsAllocaFunc = deferredCallEntry->mIsAllocaFunc;
} }
else else
{ {
@ -1118,6 +1128,7 @@ void BfModule::EmitDeferredCallProcessor(BfScopeData* scopeData, SLIList<BfDefer
{ {
auto moduleMethodInstance = callInfoKV.mValue.mModuleMethodInstance; auto moduleMethodInstance = callInfoKV.mValue.mModuleMethodInstance;
bool bypassVirtual = callInfoKV.mValue.mBypassVirtual; bool bypassVirtual = callInfoKV.mValue.mBypassVirtual;
bool isAllocaFunc = callInfoKV.mValue.mIsAllocaFunc;
auto methodInstance = moduleMethodInstance.mMethodInstance; auto methodInstance = moduleMethodInstance.mMethodInstance;
auto methodDef = methodInstance->mMethodDef; auto methodDef = methodInstance->mMethodDef;
auto methodOwner = methodInstance->mMethodInstanceGroup->mOwner; auto methodOwner = methodInstance->mMethodInstanceGroup->mOwner;
@ -1204,6 +1215,8 @@ void BfModule::EmitDeferredCallProcessor(BfScopeData* scopeData, SLIList<BfDefer
flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_DoNullChecks | BfDeferredBlockFlag_SkipObjectAccessCheck); flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_DoNullChecks | BfDeferredBlockFlag_SkipObjectAccessCheck);
if (bypassVirtual) if (bypassVirtual)
flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_BypassVirtual); flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_BypassVirtual);
if (isAllocaFunc)
flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_IsAllocaFunc);
EmitDeferredCall(moduleMethodInstance, llvmArgs, flags); EmitDeferredCall(moduleMethodInstance, llvmArgs, flags);
ValueScopeEnd(valueScopeStart); ValueScopeEnd(valueScopeStart);
mBfIRBuilder->CreateBr(condBB); mBfIRBuilder->CreateBr(condBB);
@ -7336,9 +7349,12 @@ void BfModule::Visit(BfDeferStatement* deferStmt)
} }
else if (auto exprStmt = BfNodeDynCast<BfExpressionStatement>(deferStmt->mTargetNode)) else if (auto exprStmt = BfNodeDynCast<BfExpressionStatement>(deferStmt->mTargetNode))
{ {
BfDeferCallData deferCallData;
deferCallData.mRefNode = exprStmt->mExpression;
deferCallData.mScopeAlloc = scope;
BfExprEvaluator expressionEvaluator(this); BfExprEvaluator expressionEvaluator(this);
expressionEvaluator.mDeferCallRef = exprStmt->mExpression; expressionEvaluator.mDeferCallData = &deferCallData;
expressionEvaluator.mDeferScopeAlloc = scope;
expressionEvaluator.VisitChild(exprStmt->mExpression); expressionEvaluator.VisitChild(exprStmt->mExpression);
if (mCurMethodState->mPendingNullConditional != NULL) if (mCurMethodState->mPendingNullConditional != NULL)
FlushNullConditional(expressionEvaluator.mResult, true); FlushNullConditional(expressionEvaluator.mResult, true);

View file

@ -182,6 +182,13 @@ namespace Tests
{ {
sVal = 123; sVal = 123;
} }
public static void TestDefer()
{
function void() func = => Func;
if (func != null)
defer:: func.Invoke();
}
} }
public static int UseFunc0<T>(function int (T this, float f) func, T a, float b) public static int UseFunc0<T>(function int (T this, float f) func, T a, float b)
@ -254,6 +261,10 @@ namespace Tests
ClassC<Zoop>.Test(); ClassC<Zoop>.Test();
Test.Assert(Zoop.sVal == 123); Test.Assert(Zoop.sVal == 123);
Zoop.sVal = 0;
Zoop.TestDefer();
Test.Assert(Zoop.sVal == 123);
} }
} }
} }