Fix assignment codegen for suspend operators plus and plusAssign

KT-16079: Fixed
This commit is contained in:
Ilmir Usmanov
2017-11-01 16:40:18 +03:00
parent fbe274ff09
commit f4e180556c
8 changed files with 160 additions and 51 deletions
@@ -2171,15 +2171,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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();
@@ -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
}
@@ -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
}
@@ -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.*
@@ -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");
@@ -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");
@@ -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);
}
@@ -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");