Fix verify error with 'return when/if/try' in suspend function
The problem appears for tail-optimized suspend functions, we erroneously assumed that when/if/try expressions in tail-call position have simple types like `I` while actually, they can return SUSPENDED object, i.e. must have `java/lang/Object` as return type. But this only concerns branching operations in tail-call position, so we have to make an additional analysis for remembering whether a given expression is in a tail-call position. Also, it's important here that we now assume the return type of the current function as `java/lang/Object` that is necessary to avoid wrong checkcasts. #KT-15364 Fixed
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
suspend fun foo(x: Any): Int {
|
||||
return if (x == "56") suspendHere() else 13
|
||||
}
|
||||
|
||||
suspend fun suspendHere(): Int = suspendCoroutineOrReturn { x ->
|
||||
x.resume(56)
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = -1
|
||||
|
||||
builder {
|
||||
result = foo("56")
|
||||
}
|
||||
|
||||
if (result != 56) return "fail 1: $result"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
suspend fun foo(x: Any): Int {
|
||||
return try {
|
||||
suspendHere()
|
||||
} catch (e: Throwable) {
|
||||
13
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun suspendHere(): Int = suspendCoroutineOrReturn { x ->
|
||||
x.resume(56)
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = -1
|
||||
|
||||
builder {
|
||||
result = foo("56")
|
||||
}
|
||||
|
||||
if (result != 56) return "fail 1: $result"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
suspend fun foo(x: Any): Int {
|
||||
return when {
|
||||
x == "56" -> suspendHere()
|
||||
else -> 13
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun suspendHere(): Int = suspendCoroutineOrReturn { x ->
|
||||
x.resume(56)
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = -1
|
||||
|
||||
builder {
|
||||
result = foo("56")
|
||||
}
|
||||
|
||||
if (result != 56) return "fail 1: $result"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
@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 final class EmptyContinuation {
|
||||
public final static field INSTANCE: EmptyContinuation
|
||||
private method <init>(): void
|
||||
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 class SuspendWithIfKt {
|
||||
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
|
||||
public final static @org.jetbrains.annotations.Nullable method foo(@org.jetbrains.annotations.NotNull p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method suspendHere(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
@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 final class EmptyContinuation {
|
||||
public final static field INSTANCE: EmptyContinuation
|
||||
private method <init>(): void
|
||||
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 class SuspendWithTryCatchKt {
|
||||
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
|
||||
public final static @org.jetbrains.annotations.Nullable method foo(@org.jetbrains.annotations.NotNull p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method suspendHere(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
@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 final class EmptyContinuation {
|
||||
public final static field INSTANCE: EmptyContinuation
|
||||
private method <init>(): void
|
||||
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 class SuspendWithWhenKt {
|
||||
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
|
||||
public final static @org.jetbrains.annotations.Nullable method foo(@org.jetbrains.annotations.NotNull p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method suspendHere(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
Reference in New Issue
Block a user