diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 17b00021..8f6f7d10 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -5568,8 +5568,8 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodMatcher* methodMatcher, BfTyped } PerformCallChecks(moduleMethodInstance.mMethodInstance, methodMatcher->mTargetSrc); - - return CreateCall(methodMatcher->mTargetSrc, target, BfTypedValue(), methodMatcher->mBestMethodDef, moduleMethodInstance, false, methodMatcher->mArguments); + + return CreateCall(methodMatcher->mTargetSrc, target, BfTypedValue(), methodMatcher->mBestMethodDef, moduleMethodInstance, false, methodMatcher->mArguments); } void BfExprEvaluator::MakeBaseConcrete(BfTypedValue& typedValue) @@ -5873,7 +5873,7 @@ void BfExprEvaluator::AddCallDependencies(BfMethodInstance* methodInstance) } //TODO: delete argumentsZ -BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValue& inTarget, const BfTypedValue& origTarget, BfMethodDef* methodDef, BfModuleMethodInstance moduleMethodInstance, bool bypassVirtual, SizedArrayImpl& argValues, bool skipThis) +BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValue& inTarget, const BfTypedValue& origTarget, BfMethodDef* methodDef, BfModuleMethodInstance moduleMethodInstance, bool bypassVirtual, SizedArrayImpl& argValues, BfTypedValue* argCascade, bool skipThis) { static int sCallIdx = 0; if (!mModule->mCompiler->mIsResolveOnly) @@ -6617,7 +6617,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu } if ((argExprIdx != -1) && (argExprIdx < (int)argValues.size()) && ((argValues[argExprIdx].mArgFlags & BfArgFlag_Cascade) != 0)) + { + mUsedAsStatement = true; argCascades.Add(argValue); + } if (expandedParamsArray) { @@ -6787,9 +6790,17 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu BfTypedValue callResult = CreateCall(targetSrc, methodInstance, func, bypassVirtual, irArgs); if (argCascades.mSize == 1) - return argCascades[0]; + { + if (argCascade == NULL) + return argCascades[0]; + *argCascade = argCascades[0]; + } if (argCascades.mSize > 1) - return mModule->CreateTuple(argCascades, {}); + { + if (argCascade == NULL) + return mModule->CreateTuple(argCascades, {}); + *argCascade = mModule->CreateTuple(argCascades, {}); + } return callResult; } @@ -8471,6 +8482,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp BfTypedValue result; + BfTypedValue argCascade; // { @@ -8486,26 +8498,13 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_ConstEval); } - result = CreateCall(targetSrc, callTarget, origTarget, methodDef, moduleMethodInstance, bypassVirtual, argValues.mResolvedArgs, skipThis); + result = CreateCall(targetSrc, callTarget, origTarget, methodDef, moduleMethodInstance, bypassVirtual, argValues.mResolvedArgs, &argCascade, skipThis); } if (result) { if (result.mType->IsRef()) - result = mModule->RemoveRef(result); - if (result.mType->IsSelf()) - { - if (methodMatcher.mSelfType != NULL) - { - BF_ASSERT(mModule->IsInGeneric()); - result = mModule->GetDefaultTypedValue(methodMatcher.mSelfType); - } - else - { - // Will be an error - result = mModule->GetDefaultTypedValue(methodMatcher.mBestMethodTypeInstance); - } - } + result = mModule->RemoveRef(result); } PerformCallChecks(moduleMethodInstance.mMethodInstance, targetSrc); @@ -8566,6 +8565,30 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp } } + if (argCascade) + { + if (argCascade.mType->IsRef()) + argCascade = mModule->RemoveRef(argCascade); + result = argCascade; + } + + if (result) + { + if (result.mType->IsSelf()) + { + if (methodMatcher.mSelfType != NULL) + { + BF_ASSERT(mModule->IsInGeneric()); + result = mModule->GetDefaultTypedValue(methodMatcher.mSelfType); + } + else + { + // Will be an error + result = mModule->GetDefaultTypedValue(methodMatcher.mBestMethodTypeInstance); + } + } + } + return result; } diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index f3f884f1..d7deb934 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -431,7 +431,7 @@ public: void AddCallDependencies(BfMethodInstance* methodInstance); void PerformCallChecks(BfMethodInstance* methodInstance, BfAstNode* targetSrc); BfTypedValue CreateCall(BfAstNode* targetSrc, BfMethodInstance* methodInstance, BfIRValue func, bool bypassVirtual, SizedArrayImpl& irArgs, BfTypedValue* sret = NULL, bool isTailCall = false); - BfTypedValue CreateCall(BfAstNode* targetSrc, const BfTypedValue& target, const BfTypedValue& origTarget, BfMethodDef* methodDef, BfModuleMethodInstance methodInstance, bool bypassVirtual, SizedArrayImpl& argValues, bool skipThis = false); + BfTypedValue CreateCall(BfAstNode* targetSrc, const BfTypedValue& target, const BfTypedValue& origTarget, BfMethodDef* methodDef, BfModuleMethodInstance methodInstance, bool bypassVirtual, SizedArrayImpl& argValues, BfTypedValue* argCascade = NULL, bool skipThis = false); BfTypedValue CreateCall(BfMethodMatcher* methodMatcher, BfTypedValue target); void MakeBaseConcrete(BfTypedValue& typedValue); void SplatArgs(BfTypedValue value, SizedArrayImpl& irArgs); diff --git a/IDEHelper/Tests/src/Cascades.bf b/IDEHelper/Tests/src/Cascades.bf index 91adc58d..30171b8c 100644 --- a/IDEHelper/Tests/src/Cascades.bf +++ b/IDEHelper/Tests/src/Cascades.bf @@ -4,27 +4,59 @@ namespace Tests { class Cascades { - public static void MethodA(int a, float b) + struct StructA { + public static int sDiscardCount; + public void ReturnValueDiscarded() + { + sDiscardCount++; + } + public void HandleResult() + { + + } + + public StructA Method0(int a) + { + return .(); + } } - public static void MethodB(int a, out float b) + static StructA MethodA(int a, float b) + { + return .(); + } + + static StructA MethodB(int a, out float b) { b = 100; + return .(); } [Test] public static void TestBasics() { + MethodA(1, 1.2f); + Test.Assert(StructA.sDiscardCount == 1); + + StructA sa = .(); + sa.Method0(1)..Method0(2).HandleResult(); + Test.Assert(StructA.sDiscardCount == 2); + int a = MethodA(.. 12, 2.3f); + Test.Assert(StructA.sDiscardCount == 3); Test.Assert(a == 12); + var (b, c) = MethodA(.. 12, .. 2.3f); + Test.Assert(StructA.sDiscardCount == 4); Test.Assert(b == 12); Test.Assert(c == 2.3f); var d = MethodA(.. 12, .. 2.3f); + Test.Assert(StructA.sDiscardCount == 5); Test.Assert(d == (12, 2.3f)); var f = ref MethodB(12, .. var e); + Test.Assert(StructA.sDiscardCount == 6); e += 23; Test.Assert(e == (int)123); Test.Assert(f == (int)123);