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:
Denis Zharkov
2017-01-12 15:34:31 +03:00
parent de9c41c412
commit 2286027bed
14 changed files with 324 additions and 32 deletions
@@ -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"
}
@@ -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"
}
@@ -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
}
@@ -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
}
@@ -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
}