JVM_IR: keep suspend fun return type in IrCalls

Otherwise:

  * should the dispatch receiver of a call be another call to a `suspend
    fun` wrapped in something that is optimized away later, the owner of
    the method will be incorrect;

  * references to functions returning non-Unit but casted to `() ->
    Unit` (allowed by new inference) might in fact not return Unit after
    tail call optimization.
This commit is contained in:
pyos
2020-02-21 12:49:07 +01:00
committed by Ilmir Usmanov
parent d982203d56
commit a3d85e108f
11 changed files with 177 additions and 29 deletions
@@ -0,0 +1,45 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// WITH_COROUTINES
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
var result: String = ""
var proceed: (() -> Unit)? = null
fun box(): String {
async {
O().foo(1)
O().foo(2)
}
while (proceed != null) {
result += "--;"
proceed!!()
}
if (result != "begin(1);--;end(1);begin(2);--;end(2);done;") return result;
return "OK"
}
open class O {
open suspend fun foo(x: Int) {
result += "begin($x);"
sleep()
result += "end($x);"
}
}
suspend fun sleep(): Unit = suspendCoroutine { c ->
proceed = { c.resume(Unit) }
}
fun async(f: suspend () -> Unit) {
f.startCoroutine(object : Continuation<Unit> {
override fun resumeWith(x: Result<Unit>) {
result += "done;"
proceed = null
}
override val context = EmptyCoroutineContext
})
}
@@ -0,0 +1,31 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// WITH_COROUTINES
// FILE: I.kt
open class A<T> {
suspend fun id(x: T): T = x
}
class B {
fun ok() = "OK"
}
// FILE: JavaClass.java
public class JavaClass extends A<B> {}
// FILE: main.kt
import helpers.*
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
fun box(): String {
var result = "fail"
suspend {
result = JavaClass().id(B()).ok()
}.startCoroutine(EmptyContinuation)
return result
}
@@ -0,0 +1,24 @@
// !LANGUAGE: +NewInference
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// WITH_COROUTINES
import helpers.*
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
object Dummy
suspend fun suspect(): Dummy = suspendCoroutineUninterceptedOrReturn {
x -> x.resume(Dummy)
COROUTINE_SUSPENDED
}
fun box(): String {
var res: Any? = null
suspend {
res = (::suspect as suspend () -> Unit)()
}.startCoroutine(EmptyContinuation)
return if (res != Unit) "$res" else "OK"
}