diff --git a/IDEHelper/Compiler/BfDeferEvalChecker.cpp b/IDEHelper/Compiler/BfDeferEvalChecker.cpp index 84a942cb..b7975fe5 100644 --- a/IDEHelper/Compiler/BfDeferEvalChecker.cpp +++ b/IDEHelper/Compiler/BfDeferEvalChecker.cpp @@ -5,6 +5,8 @@ USING_NS_BF; BfDeferEvalChecker::BfDeferEvalChecker() { mNeedsDeferEval = false; + mDeferLiterals = true; + mDeferLambdaBind = true; } void BfDeferEvalChecker::Visit(BfAstNode* attribExpr) @@ -31,7 +33,8 @@ void BfDeferEvalChecker::Visit(BfLiteralExpression* literalExpr) case BfTypeCode_UIntPtr: case BfTypeCode_IntUnknown: case BfTypeCode_UIntUnknown: - mNeedsDeferEval = true; + if (mDeferLiterals) + mNeedsDeferEval = true; break; default: mNeedsDeferEval = false; @@ -82,6 +85,12 @@ void BfDeferEvalChecker::Visit(BfInvocationExpression* invocationExpr) VisitChild(invocationExpr->mTarget); } +void BfDeferEvalChecker::Visit(BfLambdaBindExpression* lambdaBindExpr) +{ + if (mDeferLambdaBind) + mNeedsDeferEval = true; +} + void BfDeferEvalChecker::Visit(BfConditionalExpression* condExpr) { VisitChild(condExpr->mConditionExpression); diff --git a/IDEHelper/Compiler/BfDeferEvalChecker.h b/IDEHelper/Compiler/BfDeferEvalChecker.h index 0a28d89f..2db12ea9 100644 --- a/IDEHelper/Compiler/BfDeferEvalChecker.h +++ b/IDEHelper/Compiler/BfDeferEvalChecker.h @@ -9,6 +9,8 @@ class BfDeferEvalChecker : public BfStructuralVisitor { public: bool mNeedsDeferEval; + bool mDeferLambdaBind; + bool mDeferLiterals; public: BfDeferEvalChecker(); @@ -21,6 +23,7 @@ public: virtual void Visit(BfTupleExpression* tupleExpr) override; virtual void Visit(BfMemberReferenceExpression* memberRefExpr) override; virtual void Visit(BfInvocationExpression* invocationExpr) override; + virtual void Visit(BfLambdaBindExpression* lambdaBindExpr) override; virtual void Visit(BfConditionalExpression* condExpr) override; virtual void Visit(BfUnaryOperatorExpression* unaryOpExpr) override; virtual void Visit(BfObjectCreateExpression* objCreateExpr) override; diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index c696a8f7..d620625a 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -5008,6 +5008,7 @@ void BfExprEvaluator::ResolveArgValues(BfResolvedArgs& resolvedArgs, BfResolveAr if (argExpr != NULL) { BfDeferEvalChecker deferEvalChecker; + deferEvalChecker.mDeferLambdaBind = false; argExpr->Accept(&deferEvalChecker); deferParamEval = deferEvalChecker.mNeedsDeferEval; } @@ -17762,18 +17763,29 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool CheckResultForReading(ptr); BfTypedValue leftValue = ptr; - auto expectedType = ptr.mType; - if ((binaryOp == BfBinaryOp_LeftShift) || (binaryOp == BfBinaryOp_RightShift)) - expectedType = mModule->GetPrimitiveType(BfTypeCode_IntPtr); + bool deferBinop = false; + BfDeferEvalChecker deferEvalChecker; + deferEvalChecker.mDeferLiterals = false; + assignExpr->mRight->Accept(&deferEvalChecker); + if (deferEvalChecker.mNeedsDeferEval) + deferBinop = true; - if ((!rightValue) && (assignExpr->mRight != NULL)) + if (!deferBinop) { - rightValue = mModule->CreateValueFromExpression(assignExpr->mRight, expectedType, (BfEvalExprFlags)(BfEvalExprFlags_AllowSplat | BfEvalExprFlags_NoCast)); + auto expectedType = ptr.mType; + if ((binaryOp == BfBinaryOp_LeftShift) || (binaryOp == BfBinaryOp_RightShift)) + expectedType = mModule->GetPrimitiveType(BfTypeCode_IntPtr); + + if ((!rightValue) && (assignExpr->mRight != NULL)) + { + rightValue = mModule->CreateValueFromExpression(assignExpr->mRight, expectedType, (BfEvalExprFlags)(BfEvalExprFlags_AllowSplat | BfEvalExprFlags_NoCast)); + } } bool handled = false; + BfResolvedArgs argValues; - if (rightValue) + if ((rightValue) || (deferBinop)) { auto checkTypeInst = leftValue.mType->ToTypeInstance(); while (checkTypeInst != NULL) @@ -17788,8 +17800,26 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool continue; auto paramType = methodInst->GetParamType(0); - if (!mModule->CanCast(rightValue, paramType)) - continue; + if (deferBinop) + { + if (argValues.mArguments == NULL) + { + SizedArray argExprs; + argExprs.push_back(assignExpr->mRight); + BfSizedArray sizedArgExprs(argExprs); + argValues.Init(&sizedArgExprs); + ResolveArgValues(argValues, BfResolveArgsFlag_DeferParamEval); + } + + rightValue = ResolveArgValue(argValues.mResolvedArgs[0], paramType); + if (!rightValue) + continue; + } + else + { + if (!mModule->CanCast(rightValue, paramType)) + continue; + } mModule->SetElementType(assignExpr->mOpToken, BfSourceElementType_Method); if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(assignExpr->mOpToken))) @@ -17817,8 +17847,12 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool if (!handled) { + auto flags = BfBinOpFlag_ForceLeftType; + if (deferBinop) + flags = (BfBinOpFlags)(flags | BfBinOpFlag_DeferRight); + leftValue = mModule->LoadValue(leftValue); - PerformBinaryOperation(assignExpr->mLeft, assignExpr->mRight, binaryOp, assignExpr->mOpToken, BfBinOpFlag_ForceLeftType, leftValue, rightValue); + PerformBinaryOperation(assignExpr->mLeft, assignExpr->mRight, binaryOp, assignExpr->mOpToken, flags, leftValue, rightValue); } } @@ -20417,6 +20451,12 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod { bool noClassify = (flags & BfBinOpFlag_NoClassify) != 0; bool forceLeftType = (flags & BfBinOpFlag_ForceLeftType) != 0; + bool deferRight = (flags & BfBinOpFlag_DeferRight) != 0; + + if (deferRight) + { + rightValue = mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Var)); + } if ((rightValue.mValue.IsConst()) && (!leftValue.mValue.IsConst())) { @@ -20646,7 +20686,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod BfIRValue convLeftValue; BfIRValue convRightValue; - if ((resultType->IsVar()) || (otherType->IsVar())) + if (((resultType->IsVar()) || (otherType->IsVar())) && (!deferRight)) { bool isComparison = (binaryOp >= BfBinaryOp_Equality) && (binaryOp <= BfBinaryOp_LessThanOrEqual); if (isComparison) @@ -20794,7 +20834,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod } if (!skipOpOverload) - { + { BfBinaryOp findBinaryOp = binaryOp; bool isComparison = (binaryOp >= BfBinaryOp_Equality) && (binaryOp <= BfBinaryOp_LessThanOrEqual); @@ -20802,16 +20842,28 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod for (int pass = 0; pass < 2; pass++) { BfBinaryOp oppositeBinaryOp = BfGetOppositeBinaryOp(findBinaryOp); - bool foundOp = false; + bool foundOp = false; - SizedArray args; BfResolvedArg leftArg; leftArg.mExpression = leftExpression; - leftArg.mTypedValue = leftValue; + leftArg.mTypedValue = leftValue; BfResolvedArg rightArg; rightArg.mExpression = rightExpression; rightArg.mTypedValue = rightValue; + if (deferRight) + { + BfResolvedArgs argValues; + SizedArray argExprs; + argExprs.push_back(BfNodeDynCast(rightExpression)); + BfSizedArray sizedArgExprs(argExprs); + argValues.Init(&sizedArgExprs); + ResolveArgValues(argValues, BfResolveArgsFlag_DeferParamEval); + rightArg = argValues.mResolvedArgs[0]; + } + + SizedArray args; + if (pass == 0) { args.push_back(leftArg); @@ -20820,8 +20872,9 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod else { args.push_back(rightArg); - args.push_back(leftArg); + args.push_back(leftArg); } + BfMethodMatcher methodMatcher(opToken, mModule, "", args, NULL); methodMatcher.mBfEvalExprFlags = BfEvalExprFlags_NoAutoComplete; BfBaseClassWalker baseClassWalker(leftValue.mType, rightValue.mType, mModule); @@ -21135,7 +21188,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod if (flippedBinaryOp != BfBinaryOp_None) findBinaryOp = flippedBinaryOp; } - + auto prevResultType = resultType; if ((leftValue.mType->IsPrimitiveType()) && (!rightValue.mType->IsTypedPrimitive())) resultType = leftValue.mType; @@ -21144,6 +21197,16 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod } } + if (deferRight) + { + auto expectedType = resultType; + if ((binaryOp == BfBinaryOp_LeftShift) || (binaryOp == BfBinaryOp_RightShift)) + expectedType = mModule->GetPrimitiveType(BfTypeCode_IntPtr); + rightValue = mModule->CreateValueFromExpression(BfNodeDynCast(rightExpression), expectedType, (BfEvalExprFlags)(BfEvalExprFlags_AllowSplat | BfEvalExprFlags_NoCast)); + PerformBinaryOperation(leftExpression, rightExpression, binaryOp, opToken, (BfBinOpFlags)(flags & ~BfBinOpFlag_DeferRight), leftValue, rightValue); + return; + } + if (mModule->IsUnboundGeneric(resultType)) { mResult = mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Var)); diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index 56d288c3..b51d5b44 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -347,7 +347,8 @@ enum BfBinOpFlags BfBinOpFlag_NoClassify = 1, BfBinOpFlag_ForceLeftType = 2, BfBinOpFlag_IgnoreOperatorWithWrongResult = 4, - BfBinOpFlag_IsConstraintCheck = 8 + BfBinOpFlag_IsConstraintCheck = 8, + BfBinOpFlag_DeferRight = 0x10 }; class BfExprEvaluator : public BfStructuralVisitor diff --git a/IDEHelper/Tests/src/Delegates.bf b/IDEHelper/Tests/src/Delegates.bf index a8cd9efc..bbd1bc4f 100644 --- a/IDEHelper/Tests/src/Delegates.bf +++ b/IDEHelper/Tests/src/Delegates.bf @@ -2,6 +2,17 @@ using System; +namespace System +{ + extension Event + { + public implicit void operator+=(T dlg) mut + { + Add(dlg); + } + } +} + namespace Tests { class Delegates @@ -146,6 +157,9 @@ namespace Tests ClassB.DelegateB dlg2 = scope (val) => val + 123; Test.Assert(dlg2(3) == 126); + + Event e = .(); + e += scope (sender, e) => {}; } public static void Modify(ref int a, ref Splattable b)