Fix accessor generation for suspend functions

1. JVM view of suspend accessors must be also an instance of AccessorForFunctionDescriptor,
thus `createSubstitutedCopy` should be correctly overidden.

2. accessibleFunctionDescriptor should unwap the initial suspend descriptor,
for the same reasons as for type aliases constructors and etc:
these descriptors are used as keys of the map of accessors, so
to avoid duplication for suspend view and initial suspend descriptor,
we always use the latter one as a key.

 #KT-15907 Fixed
 #KT-15935 Fixed
This commit is contained in:
Denis Zharkov
2017-01-24 12:09:20 +03:00
parent 0693bd6b62
commit 9ca9a988a6
10 changed files with 217 additions and 0 deletions
@@ -20,6 +20,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
@@ -28,6 +30,7 @@ import java.util.LinkedHashMap;
public class AccessorForFunctionDescriptor extends AbstractAccessorForFunctionDescriptor implements AccessorForCallableDescriptor<FunctionDescriptor> {
private final FunctionDescriptor calleeDescriptor;
private final ClassDescriptor superCallTarget;
private final String nameSuffix;
public AccessorForFunctionDescriptor(
@NotNull FunctionDescriptor descriptor,
@@ -39,6 +42,7 @@ public class AccessorForFunctionDescriptor extends AbstractAccessorForFunctionDe
Name.identifier("access$" + nameSuffix));
this.calleeDescriptor = descriptor;
this.superCallTarget = superCallTarget;
this.nameSuffix = nameSuffix;
initialize(DescriptorUtils.getReceiverParameterType(descriptor.getExtensionReceiverParameter()),
descriptor instanceof ConstructorDescriptor || CodegenUtilKt.isJvmStaticInObjectOrClass(descriptor)
@@ -60,6 +64,19 @@ public class AccessorForFunctionDescriptor extends AbstractAccessorForFunctionDe
}
}
@NotNull
@Override
protected FunctionDescriptorImpl createSubstitutedCopy(
@NotNull DeclarationDescriptor newOwner,
@Nullable FunctionDescriptor original,
@NotNull Kind kind,
@Nullable Name newName,
@NotNull Annotations annotations,
@NotNull SourceElement source
) {
return new AccessorForFunctionDescriptor(calleeDescriptor, newOwner, superCallTarget, nameSuffix);
}
@NotNull
@Override
public FunctionDescriptor getCalleeDescriptor() {
@@ -2732,6 +2732,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
if (originalIfSamAdapter != null) {
descriptor = originalIfSamAdapter;
}
descriptor = CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(descriptor);
// $default method is not private, so you need no accessor to call it
return CallUtilKt.usesDefaultArguments(resolvedCall)
? descriptor
@@ -0,0 +1,43 @@
// WITH_RUNTIME
// WITH_COROUTINES
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
class X {
var res = ""
suspend fun execute() {
a()
b()
}
private suspend fun a() {
res += suspendThere("O")
res += suspendThere("K")
}
private suspend fun b() {
res += suspendThere("5")
res += suspendThere("6")
}
}
suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x ->
x.resume(v)
SUSPENDED_MARKER
}
fun builder(c: suspend X.() -> Unit) {
c.startCoroutine(X(), EmptyContinuation)
}
fun box(): String {
var result = ""
builder {
execute()
result = res
}
if (result != "OK56") return "fail 1: $result"
return "OK"
}
@@ -0,0 +1,30 @@
// WITH_RUNTIME
// WITH_COROUTINES
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
var x = true
private suspend fun foo(): String {
if (x) {
return suspendCoroutineOrReturn<String> {
it.resume("OK")
SUSPENDED_MARKER
}
}
return "fail"
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
fun box(): String {
var res = ""
builder {
res = foo()
}
return res
}
@@ -0,0 +1,42 @@
@kotlin.Metadata
public final class CoroutineUtilKt {
public final static @org.jetbrains.annotations.NotNull method handleExceptionContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
public final static @org.jetbrains.annotations.NotNull method handleResultContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
}
@kotlin.Metadata
public class EmptyContinuation {
public final static field Companion: EmptyContinuation.Companion
private final @org.jetbrains.annotations.NotNull field context: kotlin.coroutines.CoroutineContext
inner class EmptyContinuation/Companion
public @synthetic.kotlin.jvm.GeneratedByJvmOverloads method <init>(): void
public method <init>(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.CoroutineContext): void
public synthetic method <init>(p0: kotlin.coroutines.CoroutineContext, p1: int, p2: kotlin.jvm.internal.DefaultConstructorMarker): void
public @org.jetbrains.annotations.NotNull method getContext(): kotlin.coroutines.CoroutineContext
public method resume(@org.jetbrains.annotations.Nullable p0: java.lang.Object): void
public method resumeWithException(@org.jetbrains.annotations.NotNull p0: java.lang.Throwable): void
}
@kotlin.Metadata
public final static class EmptyContinuation/Companion {
inner class EmptyContinuation/Companion
private method <init>(): void
}
@kotlin.Metadata
public final class PrivateFunctionsKt {
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function2): void
public final static @org.jetbrains.annotations.Nullable method suspendThere(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
}
@kotlin.Metadata
public final class X {
private @org.jetbrains.annotations.NotNull field res: java.lang.String
public method <init>(): void
private final method a(p0: kotlin.coroutines.Continuation): java.lang.Object
private final method b(p0: kotlin.coroutines.Continuation): java.lang.Object
public final @org.jetbrains.annotations.Nullable method execute(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
public final @org.jetbrains.annotations.NotNull method getRes(): java.lang.String
public final method setRes(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
}
@@ -0,0 +1,34 @@
@kotlin.Metadata
public final class CoroutineUtilKt {
public final static @org.jetbrains.annotations.NotNull method handleExceptionContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
public final static @org.jetbrains.annotations.NotNull method handleResultContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
}
@kotlin.Metadata
public class EmptyContinuation {
public final static field Companion: EmptyContinuation.Companion
private final @org.jetbrains.annotations.NotNull field context: kotlin.coroutines.CoroutineContext
inner class EmptyContinuation/Companion
public @synthetic.kotlin.jvm.GeneratedByJvmOverloads method <init>(): void
public method <init>(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.CoroutineContext): void
public synthetic method <init>(p0: kotlin.coroutines.CoroutineContext, p1: int, p2: kotlin.jvm.internal.DefaultConstructorMarker): void
public @org.jetbrains.annotations.NotNull method getContext(): kotlin.coroutines.CoroutineContext
public method resume(@org.jetbrains.annotations.Nullable p0: java.lang.Object): void
public method resumeWithException(@org.jetbrains.annotations.NotNull p0: java.lang.Throwable): void
}
@kotlin.Metadata
public final static class EmptyContinuation/Companion {
inner class EmptyContinuation/Companion
private method <init>(): void
}
@kotlin.Metadata
public final class PrivateInFileKt {
private static field x: boolean
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void
private final static method foo(p0: kotlin.coroutines.Continuation): java.lang.Object
public final static method getX(): boolean
public final static method setX(p0: boolean): void
}
@@ -5179,6 +5179,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("privateFunctions.kt")
public void testPrivateFunctions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/privateFunctions.kt");
doTest(fileName);
}
@TestMetadata("privateInFile.kt")
public void testPrivateInFile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/privateInFile.kt");
doTest(fileName);
}
@TestMetadata("returnNoSuspend.kt")
public void testReturnNoSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/returnNoSuspend.kt");
@@ -5179,6 +5179,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("privateFunctions.kt")
public void testPrivateFunctions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/privateFunctions.kt");
doTest(fileName);
}
@TestMetadata("privateInFile.kt")
public void testPrivateInFile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/privateInFile.kt");
doTest(fileName);
}
@TestMetadata("returnNoSuspend.kt")
public void testReturnNoSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/returnNoSuspend.kt");
@@ -5179,6 +5179,18 @@ public class LightAnalysisModeCodegenTestGenerated extends AbstractLightAnalysis
doTest(fileName);
}
@TestMetadata("privateFunctions.kt")
public void testPrivateFunctions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/privateFunctions.kt");
doTest(fileName);
}
@TestMetadata("privateInFile.kt")
public void testPrivateInFile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/privateInFile.kt");
doTest(fileName);
}
@TestMetadata("returnNoSuspend.kt")
public void testReturnNoSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/returnNoSuspend.kt");
@@ -5852,6 +5852,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName);
}
@TestMetadata("privateFunctions.kt")
public void testPrivateFunctions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/privateFunctions.kt");
doTest(fileName);
}
@TestMetadata("privateInFile.kt")
public void testPrivateInFile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/privateInFile.kt");
doTest(fileName);
}
@TestMetadata("returnNoSuspend.kt")
public void testReturnNoSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/returnNoSuspend.kt");