Support non-tail suspend calls in JVM back-end
#KT-15597 In Progress
This commit is contained in:
+82
@@ -0,0 +1,82 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
class Controller {
|
||||
var log = ""
|
||||
var resumeIndex = 0
|
||||
|
||||
suspend fun <T> suspendWithValue(value: T): T = suspendCoroutineOrReturn { continuation ->
|
||||
log += "suspend($value);"
|
||||
continuation.resume(value)
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(value: String): Unit = suspendCoroutineOrReturn { continuation ->
|
||||
log += "error($value);"
|
||||
continuation.resumeWithException(RuntimeException(value))
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
}
|
||||
|
||||
fun test(c: suspend Controller.() -> Unit): String {
|
||||
val controller = Controller()
|
||||
c.startCoroutine(controller, EmptyContinuation, object: ContinuationDispatcher {
|
||||
private fun dispatchResume(block: () -> Unit) {
|
||||
val id = controller.resumeIndex++
|
||||
controller.log += "before $id;"
|
||||
block()
|
||||
controller.log += "after $id;"
|
||||
}
|
||||
|
||||
override fun <P> dispatchResume(data: P, continuation: Continuation<P>): Boolean {
|
||||
dispatchResume {
|
||||
continuation.resume(data)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun dispatchResumeWithException(exception: Throwable, continuation: Continuation<*>): Boolean {
|
||||
dispatchResume {
|
||||
continuation.resumeWithException(exception)
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
return controller.log
|
||||
}
|
||||
|
||||
suspend fun Controller.foo() = suspendWithValue("") + suspendWithValue("O")
|
||||
|
||||
suspend fun Controller.test1() {
|
||||
val o = foo()
|
||||
val k = suspendWithValue("K")
|
||||
log += "$o$k;"
|
||||
}
|
||||
|
||||
suspend fun Controller.test2() {
|
||||
try {
|
||||
foo()
|
||||
|
||||
suspendWithException("OK")
|
||||
log += "ignore;"
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
log += "${e.message};"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = test {
|
||||
test1()
|
||||
}
|
||||
if (result != "before 0;suspend();before 1;suspend(O);before 2;before 3;suspend(K);before 4;OK;before 5;after 5;after 4;after 3;after 2;after 1;after 0;") return "fail1: $result"
|
||||
|
||||
result = test {
|
||||
test2()
|
||||
}
|
||||
if (result != "before 0;suspend();before 1;suspend(O);before 2;before 3;error(OK);before 4;OK;before 5;after 5;after 4;after 3;after 2;after 1;after 0;") return "fail2: $result"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
class Controller {
|
||||
var exception: Throwable? = null
|
||||
val postponedActions = ArrayList<() -> Unit>()
|
||||
|
||||
suspend fun suspendWithValue(v: String): String = suspendCoroutineOrReturn { x ->
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception): String = suspendCoroutineOrReturn { x ->
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
fun run(c: suspend Controller.() -> Unit) {
|
||||
c.startCoroutine(this, handleExceptionContinuation {
|
||||
exception = it
|
||||
})
|
||||
while (postponedActions.isNotEmpty()) {
|
||||
postponedActions[0]()
|
||||
postponedActions.removeAt(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(c: suspend Controller.() -> Unit) {
|
||||
val controller = Controller()
|
||||
controller.run(c)
|
||||
|
||||
if (controller.exception?.message != "OK") {
|
||||
throw RuntimeException("Unexpected result: ${controller.exception?.message}")
|
||||
}
|
||||
}
|
||||
|
||||
fun commonThrow(t: Throwable) {
|
||||
throw t
|
||||
}
|
||||
|
||||
suspend fun justContinue(): Unit = suspendCoroutineOrReturn { x ->
|
||||
x.resume(Unit)
|
||||
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
suspend fun Controller.test1() {
|
||||
justContinue()
|
||||
throw RuntimeException("OK")
|
||||
}
|
||||
|
||||
suspend fun Controller.test2() {
|
||||
justContinue()
|
||||
commonThrow(RuntimeException("OK"))
|
||||
}
|
||||
|
||||
suspend fun Controller.test3() {
|
||||
justContinue()
|
||||
suspendWithException(RuntimeException("OK"))
|
||||
}
|
||||
|
||||
suspend fun Controller.test4() {
|
||||
justContinue()
|
||||
try {
|
||||
suspendWithException(RuntimeException("fail 1"))
|
||||
} catch (e: RuntimeException) {
|
||||
suspendWithException(RuntimeException("OK"))
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun Controller.test5() {
|
||||
justContinue()
|
||||
try {
|
||||
suspendWithException(Exception("OK"))
|
||||
} catch (e: RuntimeException) {
|
||||
suspendWithException(RuntimeException("fail 3"))
|
||||
throw RuntimeException("fail 4")
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
test1()
|
||||
}
|
||||
|
||||
builder {
|
||||
test2()
|
||||
}
|
||||
|
||||
builder {
|
||||
test3()
|
||||
}
|
||||
|
||||
builder {
|
||||
test4()
|
||||
}
|
||||
|
||||
builder {
|
||||
test5()
|
||||
}
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x ->
|
||||
x.resume(v)
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
suspend inline fun suspendHere(crossinline block: () -> String): String {
|
||||
return suspendThere(block()) + suspendThere(block())
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
builder {
|
||||
var q = "O"
|
||||
result = suspendHere {
|
||||
val r = q
|
||||
q = "K"
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
class A(val v: String) {
|
||||
suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x ->
|
||||
x.resume(v)
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
suspend fun suspendHere(): String = suspendThere("O") + suspendThere(v)
|
||||
}
|
||||
|
||||
fun builder(c: suspend A.() -> Unit) {
|
||||
c.startCoroutine(A("K"), EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
builder {
|
||||
result = suspendHere()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x ->
|
||||
x.resume(v)
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
suspend fun suspendHere(suspend: Boolean): String {
|
||||
if (!suspend) return "O"
|
||||
|
||||
return suspendThere("") + suspendThere("K")
|
||||
}
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
builder {
|
||||
result = suspendHere(false) + suspendHere(true)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x ->
|
||||
x.resume(v)
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
suspend fun suspendHere(): String = suspendThere("O") + suspendThere("K")
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
builder {
|
||||
result = suspendHere()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x ->
|
||||
x.resume(v)
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
suspend fun suspendHere(): String {
|
||||
val k = "K"
|
||||
val x = suspendThere("O")
|
||||
val y = x + suspendThere(k)
|
||||
|
||||
return y
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
builder {
|
||||
result = suspendHere()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user