diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index d6a1b313b66..ba621a69cb7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2171,15 +2171,10 @@ public class ExpressionCodegen extends KtVisitor impleme resolvedCall, state.getProject(), state.getBindingContext() ); if (callWithRealDescriptor != null) { - StackValue coroutineInstanceValueForSuspensionPoint = getCoroutineInstanceValueForSuspensionPoint(resolvedCall); - StackValue coroutineInstanceValue = - coroutineInstanceValueForSuspensionPoint != null - ? coroutineInstanceValueForSuspensionPoint - : getContinuationParameterFromEnclosingSuspendFunction(resolvedCall); - tempVariables.put(callWithRealDescriptor.getFakeContinuationExpression(), coroutineInstanceValue); - + prepareCoroutineArgumentForSuspendCall(resolvedCall, callWithRealDescriptor.getFakeContinuationExpression()); return invokeFunction(callWithRealDescriptor.getResolvedCall(), receiver); } + FunctionDescriptor fd = accessibleFunctionDescriptor(resolvedCall); ClassDescriptor superCallTarget = getSuperCallTarget(call); @@ -2199,6 +2194,18 @@ public class ExpressionCodegen extends KtVisitor impleme return callable.invokeMethodWithArguments(resolvedCall, receiver, this); } + private void prepareCoroutineArgumentForSuspendCall( + @NotNull ResolvedCall resolvedCall, + @NotNull KtExpression continuationExpression + ) { + StackValue coroutineInstanceValueForSuspensionPoint = getCoroutineInstanceValueForSuspensionPoint(resolvedCall); + StackValue coroutineInstanceValue = + coroutineInstanceValueForSuspensionPoint != null + ? coroutineInstanceValueForSuspensionPoint + : getContinuationParameterFromEnclosingSuspendFunction(resolvedCall); + tempVariables.put(continuationExpression, coroutineInstanceValue); + } + private StackValue getContinuationParameterFromEnclosingSuspendFunction(@NotNull ResolvedCall resolvedCall) { FunctionDescriptor enclosingSuspendFunction = bindingContext.get(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall()); @@ -3405,6 +3412,16 @@ public class ExpressionCodegen extends KtVisitor impleme private StackValue generateAugmentedAssignment(KtBinaryExpression expression) { return StackValue.operation(Type.VOID_TYPE, adapter -> { ResolvedCall resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext); + + ResolvedCallWithRealDescriptor callWithRealDescriptor = + CoroutineCodegenUtilKt.replaceSuspensionFunctionWithRealDescriptor( + resolvedCall, state.getProject(), state.getBindingContext() + ); + if (callWithRealDescriptor != null) { + prepareCoroutineArgumentForSuspendCall(resolvedCall, callWithRealDescriptor.getFakeContinuationExpression()); + resolvedCall = callWithRealDescriptor.getResolvedCall(); + } + FunctionDescriptor descriptor = accessibleFunctionDescriptor(resolvedCall); Callable callable = resolveToCallable(descriptor, false, resolvedCall); KtExpression lhs = expression.getLeft(); diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlus.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlus.kt new file mode 100644 index 00000000000..14e162a5c67 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlus.kt @@ -0,0 +1,31 @@ +// WITH_RUNTIME +// WITH_COROUTINES +import helpers.* + +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +suspend fun suspendThere(v: A): A = suspendCoroutineOrReturn { x -> + x.resume(v) + COROUTINE_SUSPENDED +} + +class A(var value: String) { + operator suspend fun plus(other: A) = suspendThere(A(value + other.value)) +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +suspend fun usePlusAssign(): A { + var a = A("O") + a += A("K") + return a +} + +fun box(): String { + var a = A("") + builder { a = usePlusAssign() } + return a.value +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusAssign.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusAssign.kt new file mode 100644 index 00000000000..009ee3fce88 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusAssign.kt @@ -0,0 +1,33 @@ +// WITH_RUNTIME +// WITH_COROUTINES +import helpers.* + +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +suspend fun suspendThere(v: A): A = suspendCoroutineOrReturn { x -> + x.resume(v) + COROUTINE_SUSPENDED +} + +class A(var value: String) { + operator suspend fun plusAssign(other: A) { + value = suspendThere(A(value + other.value)).value + } +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +suspend fun usePlusAssign(): A { + var a = A("O") + a += A("K") + return a +} + +fun box(): String { + var a = A("") + builder { a = usePlusAssign() } + return a.value +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/augmentedAssignment.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusCallFromLambda.kt similarity index 88% rename from compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/augmentedAssignment.kt rename to compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusCallFromLambda.kt index b57aa353705..f8795af2d6e 100644 --- a/compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/augmentedAssignment.kt +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusCallFromLambda.kt @@ -1,9 +1,7 @@ -// IGNORE_BACKEND: JVM // WITH_RUNTIME // WITH_COROUTINES import helpers.* -// TODO: looks like this is a bug in JVM backend import kotlin.coroutines.experimental.* import kotlin.coroutines.experimental.intrinsics.* diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index d8c53845cda..d5418d24b5e 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -5938,6 +5938,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("suspendOperatorPlus.kt") + public void testSuspendOperatorPlus() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlus.kt"); + doTest(fileName); + } + + @TestMetadata("suspendOperatorPlusAssign.kt") + public void testSuspendOperatorPlusAssign() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusAssign.kt"); + doTest(fileName); + } + + @TestMetadata("suspendOperatorPlusCallFromLambda.kt") + public void testSuspendOperatorPlusCallFromLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusCallFromLambda.kt"); + doTest(fileName); + } + @TestMetadata("tailrec.kt") public void testTailrec() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec.kt"); @@ -6145,18 +6163,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } - @TestMetadata("augmentedAssignment.kt") - public void testAugmentedAssignment() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/augmentedAssignment.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); - } - @TestMetadata("dispatchResume.kt") public void testDispatchResume() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/dispatchResume.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index a512540dc79..aa3b34436b5 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -5938,6 +5938,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("suspendOperatorPlus.kt") + public void testSuspendOperatorPlus() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlus.kt"); + doTest(fileName); + } + + @TestMetadata("suspendOperatorPlusAssign.kt") + public void testSuspendOperatorPlusAssign() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusAssign.kt"); + doTest(fileName); + } + + @TestMetadata("suspendOperatorPlusCallFromLambda.kt") + public void testSuspendOperatorPlusCallFromLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusCallFromLambda.kt"); + doTest(fileName); + } + @TestMetadata("tailrec.kt") public void testTailrec() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec.kt"); @@ -6145,18 +6163,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } - @TestMetadata("augmentedAssignment.kt") - public void testAugmentedAssignment() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/augmentedAssignment.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); - } - @TestMetadata("dispatchResume.kt") public void testDispatchResume() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/dispatchResume.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index ac76b04203f..05591383a9e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -5938,6 +5938,24 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("suspendOperatorPlus.kt") + public void testSuspendOperatorPlus() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlus.kt"); + doTest(fileName); + } + + @TestMetadata("suspendOperatorPlusAssign.kt") + public void testSuspendOperatorPlusAssign() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusAssign.kt"); + doTest(fileName); + } + + @TestMetadata("suspendOperatorPlusCallFromLambda.kt") + public void testSuspendOperatorPlusCallFromLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusCallFromLambda.kt"); + doTest(fileName); + } + @TestMetadata("tailrec.kt") public void testTailrec() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec.kt"); @@ -6141,18 +6159,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class SuspendFunctionAsCoroutine extends AbstractLightAnalysisModeTest { - @TestMetadata("augmentedAssignment.kt") - public void ignoreAugmentedAssignment() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/augmentedAssignment.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); - } - public void testAllFilesPresentInSuspendFunctionAsCoroutine() throws Exception { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 2197869d1c3..d488d4c1765 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -6514,6 +6514,24 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("suspendOperatorPlus.kt") + public void testSuspendOperatorPlus() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlus.kt"); + doTest(fileName); + } + + @TestMetadata("suspendOperatorPlusAssign.kt") + public void testSuspendOperatorPlusAssign() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusAssign.kt"); + doTest(fileName); + } + + @TestMetadata("suspendOperatorPlusCallFromLambda.kt") + public void testSuspendOperatorPlusCallFromLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusCallFromLambda.kt"); + doTest(fileName); + } + @TestMetadata("tailrec.kt") public void testTailrec() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec.kt"); @@ -6703,12 +6721,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); } - @TestMetadata("augmentedAssignment.kt") - public void testAugmentedAssignment() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/augmentedAssignment.kt"); - doTest(fileName); - } - @TestMetadata("dispatchResume.kt") public void testDispatchResume() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/dispatchResume.kt");