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"
}