1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00

Fixed lambda capture of shadows variables

This commit is contained in:
Brian Fiete 2020-09-01 15:57:08 -07:00
parent 0700697fe9
commit 177b5b7254
6 changed files with 88 additions and 133 deletions

View file

@ -3323,15 +3323,6 @@ BfTypedValue BfExprEvaluator::LookupIdentifier(BfAstNode* refNode, const StringI
int varSkipCount = 0; int varSkipCount = 0;
StringT<128> wantName; StringT<128> wantName;
wantName.Reference(findName); wantName.Reference(findName);
if (findName.StartsWith('@'))
{
wantName = findName;
while (wantName.StartsWith("@"))
{
varSkipCount++;
wantName.Remove(0);
}
}
closureTypeInst->mTypeDef->PopulateMemberSets(); closureTypeInst->mTypeDef->PopulateMemberSets();
BfMemberSetEntry* memberSetEntry = NULL; BfMemberSetEntry* memberSetEntry = NULL;
@ -9457,7 +9448,7 @@ bool BfExprEvaluator::CanBindDelegate(BfDelegateBindExpression* delegateBindExpr
return IsExactMethodMatch(methodInstance, bindResult.mMethodInstance, true); return IsExactMethodMatch(methodInstance, bindResult.mMethodInstance, true);
} }
BfTypedValue BfExprEvaluator::DoImplicitArgCapture(BfAstNode* refNode, BfIdentifierNode* identifierNode) BfTypedValue BfExprEvaluator::DoImplicitArgCapture(BfAstNode* refNode, BfIdentifierNode* identifierNode, int shadowIdx)
{ {
String findName = identifierNode->ToString(); String findName = identifierNode->ToString();
@ -9468,6 +9459,8 @@ BfTypedValue BfExprEvaluator::DoImplicitArgCapture(BfAstNode* refNode, BfIdentif
auto checkMethodState = mModule->mCurMethodState; auto checkMethodState = mModule->mCurMethodState;
bool isMixinOuterVariablePass = false; bool isMixinOuterVariablePass = false;
int shadowSkip = shadowIdx;
while (checkMethodState != NULL) while (checkMethodState != NULL)
{ {
BP_ZONE("LookupIdentifier:DoImplicitArgCapture"); BP_ZONE("LookupIdentifier:DoImplicitArgCapture");
@ -9487,29 +9480,23 @@ BfTypedValue BfExprEvaluator::DoImplicitArgCapture(BfAstNode* refNode, BfIdentif
while (varDecl != NULL) while (varDecl != NULL)
{ {
// if ((closureTypeInst != NULL) && (wantName == "this"))
// break;
if (varDecl->mNameNode == identifierNode) if (varDecl->mNameNode == identifierNode)
{ {
BfTypedValue localResult = LoadLocal(varDecl); if (shadowSkip > 0)
// auto autoComplete = GetAutoComplete(); {
// if (identifierNode != NULL) shadowSkip--;
// { }
// if (autoComplete != NULL) else
// autoComplete->CheckLocalRef(identifierNode, varDecl); {
// if (((mModule->mCurMethodState->mClosureState == NULL) || (mModule->mCurMethodState->mClosureState->mCapturing)) && BfTypedValue localResult = LoadLocal(varDecl);
// (mModule->mCompiler->mResolvePassData != NULL) && (mModule->mCurMethodInstance != NULL))
// mModule->mCompiler->mResolvePassData->HandleLocalReference(identifierNode, varDecl->mNameNode, mModule->mCurTypeInstance->mTypeDef, rootMethodState->mMethodInstance->mMethodDef, varDecl->mLocalVarId);
// }
//
if (!isMixinOuterVariablePass) if (!isMixinOuterVariablePass)
{ {
mResultLocalVar = varDecl; mResultLocalVar = varDecl;
mResultFieldInstance = NULL; mResultFieldInstance = NULL;
mResultLocalVarRefNode = identifierNode; mResultLocalVarRefNode = identifierNode;
} }
return localResult; return localResult;
}
} }
varDecl = varDecl->mShadowedLocal; varDecl = varDecl->mShadowedLocal;
@ -9688,7 +9675,7 @@ BfTypedValue BfExprEvaluator::DoImplicitArgCapture(BfAstNode* refNode, BfMethodI
if (identifierNode != NULL) if (identifierNode != NULL)
{ {
lookupVal = DoImplicitArgCapture(refNode, identifierNode); lookupVal = DoImplicitArgCapture(refNode, identifierNode, 0);
} }
else else
{ {
@ -10940,11 +10927,45 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam
if (captureType == BfCaptureType_Reference) if (captureType == BfCaptureType_Reference)
capturedEntry.mExplicitlyByReference = true; capturedEntry.mExplicitlyByReference = true;
capturedEntry.mType = capturedType; capturedEntry.mType = capturedType;
capturedEntry.mNameNode = outerLocal->mNameNode;
if (outerLocal->mName == "this") if (outerLocal->mName == "this")
capturedEntry.mName = "__this"; capturedEntry.mName = "__this";
else else
{
capturedEntry.mName = outerLocal->mName; capturedEntry.mName = outerLocal->mName;
capturedEntry.mNameNode = outerLocal->mNameNode;
BfLocalVarEntry* entry = NULL;
if (varMethodState->mLocalVarSet.TryGetWith<StringImpl&>(capturedEntry.mName, &entry))
{
auto startCheckVar = entry->mLocalVar;
int shadowIdx = 0;
auto checkVar = startCheckVar;
while (checkVar != NULL)
{
if (checkVar == outerLocal)
{
// We only use mShadowIdx when we have duplicate name nodes (ie: in the case of for looks with iterator vs value)
auto shadowCheckVar = startCheckVar;
while (shadowCheckVar != checkVar)
{
if (shadowCheckVar->mNameNode == checkVar->mNameNode)
capturedEntry.mShadowIdx++;
shadowCheckVar = shadowCheckVar->mShadowedLocal;
}
for (int i = 0; i < shadowIdx; i++)
capturedEntry.mName.Insert(0, '@');
break;
}
shadowIdx++;
checkVar = checkVar->mShadowedLocal;
}
}
}
capturedEntries.Add(capturedEntry); capturedEntries.Add(capturedEntry);
} }
} }
@ -11107,10 +11128,12 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam
SizedArray<BfIRType, 8> origParamTypes; SizedArray<BfIRType, 8> origParamTypes;
BfIRType origReturnType; BfIRType origReturnType;
bool forceStatic = false;
if (invokeMethodInstance != NULL) if (invokeMethodInstance != NULL)
{ {
forceStatic = methodDef->mIsStatic;
auto invokeFunctionType = mModule->mBfIRBuilder->MapMethod(invokeMethodInstance); auto invokeFunctionType = mModule->mBfIRBuilder->MapMethod(invokeMethodInstance);
invokeMethodInstance->GetIRFunctionInfo(mModule, origReturnType, origParamTypes, methodDef->mIsStatic); invokeMethodInstance->GetIRFunctionInfo(mModule, origReturnType, origParamTypes, forceStatic);
} }
else else
{ {
@ -11119,15 +11142,15 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam
SizedArray<BfIRType, 3> newTypes; SizedArray<BfIRType, 3> newTypes;
if ((invokeMethodInstance != NULL) && (invokeMethodInstance->GetStructRetIdx() == 0)) if ((invokeMethodInstance != NULL) && (invokeMethodInstance->GetStructRetIdx(forceStatic) == 0))
newTypes.push_back(origParamTypes[0]); newTypes.push_back(origParamTypes[0]);
if (!methodDef->mIsStatic) if (!methodDef->mIsStatic)
newTypes.push_back(mModule->mBfIRBuilder->MapType(useTypeInstance)); newTypes.push_back(mModule->mBfIRBuilder->MapType(useTypeInstance));
if ((invokeMethodInstance != NULL) && (invokeMethodInstance->GetStructRetIdx() == 1)) if ((invokeMethodInstance != NULL) && (invokeMethodInstance->GetStructRetIdx(forceStatic) == 1))
newTypes.push_back(origParamTypes[1]); newTypes.push_back(origParamTypes[1]);
int paramStartIdx = 0; int paramStartIdx = 0;
if ((invokeMethodInstance != NULL) && (invokeMethodInstance->GetStructRetIdx() != -1)) if ((invokeMethodInstance != NULL) && (invokeMethodInstance->GetStructRetIdx(forceStatic) != -1))
paramStartIdx++; paramStartIdx++;
if (!methodDef->mIsStatic) if (!methodDef->mIsStatic)
paramStartIdx++; paramStartIdx++;
@ -11325,9 +11348,6 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam
lambdaCapture.mName = "this"; lambdaCapture.mName = "this";
else else
lambdaCapture.mName = capturedEntry.mName; lambdaCapture.mName = capturedEntry.mName;
// if (capturedEntry.mLocalVarDef != NULL)
// lambdaCapture.mLocalIdx = capturedEntry.mLocalVarDef->mLocalVarId;
// lambdaCapture.mCopyField = capturedEntry.mCopyField;
lambdaInstance->mCaptures.Add(lambdaCapture); lambdaInstance->mCaptures.Add(lambdaCapture);
closureInstanceInfo->mCaptureEntries.Add(capturedEntry); closureInstanceInfo->mCaptureEntries.Add(capturedEntry);
@ -11424,107 +11444,18 @@ void BfExprEvaluator::Visit(BfLambdaBindExpression* lambdaBindExpr)
} }
} }
// for (auto& capturedEntry : capturedEntries) int captureIdx = 0;
// {
// BfIRValue capturedValue;
// if (capturedEntry.mLocalVarDef != NULL)
// {
// BfTypedValue localResult = LoadLocal(capturedEntry.mLocalVarDef, true);
//
// if (!capturedEntry.mType->IsRef())
// {
// if (localResult.IsSplat())
// {
// auto aggResult = mModule->AggregateSplat(localResult);
// capturedValue = aggResult.mValue;
// }
// else
// {
// localResult = mModule->LoadValue(localResult);
// capturedValue = localResult.mValue;
// if ((capturedEntry.mLocalVarDef->mResolvedType->IsRef()) && (!capturedEntry.mType->IsRef()))
// capturedValue = mModule->mBfIRBuilder->CreateLoad(capturedValue);
// }
// }
// else
// {
// if (capturedEntry.mLocalVarDef->mResolvedType->IsRef())
// localResult = mModule->LoadValue(localResult);
// capturedValue = localResult.mValue;
// }
// }
// else
// {
// // Read captured field from outer lambda ('this')
// auto localVar = mModule->mCurMethodState->mLocals[0];
// capturedValue = mModule->mBfIRBuilder->CreateInBoundsGEP(localVar->mValue, 0, capturedEntry.mCopyField->mDataIdx);
// if ((capturedEntry.mCopyField->mResolvedType->IsRef()) || (!capturedEntry.mType->IsRef()))
// {
// capturedValue = mModule->mBfIRBuilder->CreateLoad(capturedValue);
// if ((capturedEntry.mCopyField->mResolvedType->IsRef()) && (!capturedEntry.mType->IsRef()))
// capturedValue = mModule->mBfIRBuilder->CreateLoad(capturedValue);
// }
// }
// if (capturedValue)
// {
// auto fieldPtr = mModule->mBfIRBuilder->CreateInBoundsGEP(mResult.mValue, 0, closureTypeInst->mFieldInstances[fieldIdx].mDataIdx);
// mModule->mBfIRBuilder->CreateStore(capturedValue, fieldPtr);
// }
// fieldIdx++;
// }
int captureIdx = 0;
//for (auto& capturedEntry : lambdaInstance->mCaptures)
for (int captureIdx = 0; captureIdx < (int)lambdaInstance->mCaptures.size(); captureIdx++) for (int captureIdx = 0; captureIdx < (int)lambdaInstance->mCaptures.size(); captureIdx++)
{ {
auto& capturedEntry = lambdaInstance->mCaptures[captureIdx]; auto& capturedEntry = lambdaInstance->mCaptures[captureIdx];
BfIdentifierNode* identifierNode = lambdaInstance->mMethodInstance->mMethodInfoEx->mClosureInstanceInfo->mCaptureEntries[captureIdx].mNameNode; auto& closureCaptureEntry = lambdaInstance->mMethodInstance->mMethodInfoEx->mClosureInstanceInfo->mCaptureEntries[captureIdx];
//if (captureIdx < lambdaInstance->mMethodInstance->mClosureInstanceInfo->mCaptureNodes.size) BfIdentifierNode* identifierNode = closureCaptureEntry.mNameNode;
BfIRValue capturedValue; BfIRValue capturedValue;
// if (capturedEntry.mLocalVarDef != NULL)
// {
// BfTypedValue localResult = LoadLocal(capturedEntry.mLocalVarDef, true);
//
// if (!capturedEntry.mType->IsRef())
// {
// if (localResult.IsSplat())
// {
// auto aggResult = mModule->AggregateSplat(localResult);
// capturedValue = aggResult.mValue;
// }
// else
// {
// localResult = mModule->LoadValue(localResult);
// capturedValue = localResult.mValue;
// if ((capturedEntry.mLocalVarDef->mResolvedType->IsRef()) && (!capturedEntry.mType->IsRef()))
// capturedValue = mModule->mBfIRBuilder->CreateLoad(capturedValue);
// }
// }
// else
// {
// if (capturedEntry.mLocalVarDef->mResolvedType->IsRef())
// localResult = mModule->LoadValue(localResult);
// capturedValue = localResult.mValue;
// }
// }
// else
// {
// // Read captured field from outer lambda ('this')
// auto localVar = mModule->mCurMethodState->mLocals[0];
// capturedValue = mModule->mBfIRBuilder->CreateInBoundsGEP(localVar->mValue, 0, capturedEntry.mCopyField->mDataIdx);
// if ((capturedEntry.mCopyField->mResolvedType->IsRef()) || (!capturedEntry.mType->IsRef()))
// {
// capturedValue = mModule->mBfIRBuilder->CreateLoad(capturedValue);
// if ((capturedEntry.mCopyField->mResolvedType->IsRef()) && (!capturedEntry.mType->IsRef()))
// capturedValue = mModule->mBfIRBuilder->CreateLoad(capturedValue);
// }
// }
auto fieldInstance = &closureTypeInst->mFieldInstances[fieldIdx]; auto fieldInstance = &closureTypeInst->mFieldInstances[fieldIdx];
BfTypedValue capturedTypedVal; BfTypedValue capturedTypedVal;
if (identifierNode != NULL) if (identifierNode != NULL)
capturedTypedVal = DoImplicitArgCapture(NULL, identifierNode); capturedTypedVal = DoImplicitArgCapture(NULL, identifierNode, closureCaptureEntry.mShadowIdx);
else else
capturedTypedVal = LookupIdentifier(NULL, capturedEntry.mName); capturedTypedVal = LookupIdentifier(NULL, capturedEntry.mName);
if (!fieldInstance->mResolvedType->IsRef()) if (!fieldInstance->mResolvedType->IsRef())

View file

@ -398,7 +398,7 @@ public:
void CheckLocalMethods(BfAstNode* targetSrc, BfTypeInstance* typeInstance, const StringImpl& methodName, BfMethodMatcher& methodMatcher, BfMethodType methodType); void CheckLocalMethods(BfAstNode* targetSrc, BfTypeInstance* typeInstance, const StringImpl& methodName, BfMethodMatcher& methodMatcher, BfMethodType methodType);
void InjectMixin(BfAstNode* targetSrc, BfTypedValue target, bool allowImplicitThis, const StringImpl& name, const BfSizedArray<BfExpression*>& arguments, BfSizedArray<ASTREF(BfTypeReference*)>* methodGenericArgs); void InjectMixin(BfAstNode* targetSrc, BfTypedValue target, bool allowImplicitThis, const StringImpl& name, const BfSizedArray<BfExpression*>& arguments, BfSizedArray<ASTREF(BfTypeReference*)>* methodGenericArgs);
void SetMethodElementType(BfAstNode* target); void SetMethodElementType(BfAstNode* target);
BfTypedValue DoImplicitArgCapture(BfAstNode* refNode, BfIdentifierNode* identifierNode); BfTypedValue DoImplicitArgCapture(BfAstNode* refNode, BfIdentifierNode* identifierNode, int shadowIdx);
BfTypedValue DoImplicitArgCapture(BfAstNode* refNode, BfMethodInstance* methodInstance, int paramIdx, bool& failed, BfImplicitParamKind paramKind = BfImplicitParamKind_General, const BfTypedValue& methodRefTarget = BfTypedValue()); BfTypedValue DoImplicitArgCapture(BfAstNode* refNode, BfMethodInstance* methodInstance, int paramIdx, bool& failed, BfImplicitParamKind paramKind = BfImplicitParamKind_General, const BfTypedValue& methodRefTarget = BfTypedValue());
bool CanBindDelegate(BfDelegateBindExpression* delegateBindExpr, BfMethodInstance** boundMethod = NULL); bool CanBindDelegate(BfDelegateBindExpression* delegateBindExpr, BfMethodInstance** boundMethod = NULL);
bool IsExactMethodMatch(BfMethodInstance* methodA, BfMethodInstance* methodB, bool ignoreImplicitParams = false); bool IsExactMethodMatch(BfMethodInstance* methodA, BfMethodInstance* methodB, bool ignoreImplicitParams = false);

View file

@ -662,7 +662,7 @@ bool BfMethodInstance::HasParamsArray()
return GetParamKind((int)mParams.size() - 1) == BfParamKind_Params; return GetParamKind((int)mParams.size() - 1) == BfParamKind_Params;
} }
int BfMethodInstance::GetStructRetIdx() int BfMethodInstance::GetStructRetIdx(bool forceStatic)
{ {
if ((mReturnType->IsComposite()) && (!mReturnType->IsValuelessType()) && (!GetLoweredReturnType()) && (!mIsIntrinsic)) if ((mReturnType->IsComposite()) && (!mReturnType->IsValuelessType()) && (!GetLoweredReturnType()) && (!mIsIntrinsic))
{ {
@ -674,7 +674,7 @@ int BfMethodInstance::GetStructRetIdx()
if (owner->mModule->mCompiler->mOptions.mPlatformType != BfPlatformType_Windows) if (owner->mModule->mCompiler->mOptions.mPlatformType != BfPlatformType_Windows)
return 0; return 0;
if (!HasThis()) if ((!HasThis()) || (forceStatic))
return 0; return 0;
if (!owner->IsValueType()) if (!owner->IsValueType())
return 1; return 1;
@ -1014,7 +1014,7 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType,
auto voidType = module->GetPrimitiveType(BfTypeCode_None); auto voidType = module->GetPrimitiveType(BfTypeCode_None);
returnType = module->mBfIRBuilder->MapType(voidType); returnType = module->mBfIRBuilder->MapType(voidType);
} }
else if (GetStructRetIdx() != -1) else if (GetStructRetIdx(forceStatic) != -1)
{ {
auto voidType = module->GetPrimitiveType(BfTypeCode_None); auto voidType = module->GetPrimitiveType(BfTypeCode_None);
returnType = module->mBfIRBuilder->MapType(voidType); returnType = module->mBfIRBuilder->MapType(voidType);
@ -1161,7 +1161,7 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType,
_AddType(checkType2); _AddType(checkType2);
} }
if ((GetStructRetIdx() == 1) && (!forceStatic)) if (GetStructRetIdx(forceStatic) == 1)
{ {
BF_SWAP(paramTypes[0], paramTypes[1]); BF_SWAP(paramTypes[0], paramTypes[1]);
} }

View file

@ -712,12 +712,14 @@ struct BfClosureCapturedEntry
String mName; String mName;
BfIdentifierNode* mNameNode; BfIdentifierNode* mNameNode;
bool mExplicitlyByReference; bool mExplicitlyByReference;
int mShadowIdx; // Only relative to matching nameNodes
BfClosureCapturedEntry() BfClosureCapturedEntry()
{ {
mNameNode = NULL; mNameNode = NULL;
mType = NULL; mType = NULL;
mExplicitlyByReference = false; mExplicitlyByReference = false;
mShadowIdx = 0;
} }
bool operator<(const BfClosureCapturedEntry& other) const bool operator<(const BfClosureCapturedEntry& other) const
@ -870,7 +872,7 @@ public:
bool HasThis(); bool HasThis();
bool HasExplicitThis(); bool HasExplicitThis();
bool HasParamsArray(); bool HasParamsArray();
int GetStructRetIdx(); int GetStructRetIdx(bool forceStatic = false);
bool HasSelf(); bool HasSelf();
bool GetLoweredReturnType(BfTypeCode* loweredTypeCode = NULL, BfTypeCode* loweredTypeCode2 = NULL); bool GetLoweredReturnType(BfTypeCode* loweredTypeCode = NULL, BfTypeCode* loweredTypeCode2 = NULL);
bool WantsStructsAttribByVal(); bool WantsStructsAttribByVal();

View file

@ -552,6 +552,9 @@ void BfSourceClassifier::Visit(BfPropertyDeclaration* propertyDeclaration)
BfElementVisitor::Visit(propertyDeclaration); BfElementVisitor::Visit(propertyDeclaration);
if (auto expr = BfNodeDynCast<BfPropertyBodyExpression>(propertyDeclaration->mDefinitionBlock))
return;
for (auto methodDeclaration : propertyDeclaration->mMethods) for (auto methodDeclaration : propertyDeclaration->mMethods)
{ {
if ((methodDeclaration != NULL) && (methodDeclaration->mNameNode != NULL)) if ((methodDeclaration != NULL) && (methodDeclaration->mNameNode != NULL))

View file

@ -1,9 +1,16 @@
using System; using System;
using System.Collections;
namespace Tests namespace Tests
{ {
class Lambdas class Lambdas
{ {
static void TestIt(List<float>.Enumerator e, int idx, float val)
{
Test.Assert(e.Index == idx);
Test.Assert(e.Current == val);
}
[Test] [Test]
static void TestBasics() static void TestBasics()
{ {
@ -20,6 +27,18 @@ namespace Tests
act(); act();
Test.Assert(a == 101); Test.Assert(a == 101);
List<float> iList = scope List<float>() { 10, 20, 30 };
int idx = 0;
for (var val in iList)
{
delegate void() dlg = scope () =>
{
TestIt(@val, idx, val);
};
dlg();
++idx;
}
} }
static int Add3<T>(T func) where T : delegate int() static int Add3<T>(T func) where T : delegate int()