[JS IR] Fix state machine control flow
- exception loop unwinding: make sure exception state is reset after try block is finished - break/continue of suspended loops
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// COMMON_COROUTINES_TEST
|
||||
import helpers.*
|
||||
import COROUTINES_PACKAGE.*
|
||||
import COROUTINES_PACKAGE.intrinsics.*
|
||||
|
||||
|
||||
class Controller {
|
||||
var result = ""
|
||||
|
||||
suspend fun <T> suspendAndLog(value: T): T = suspendCoroutineUninterceptedOrReturn { c ->
|
||||
result += "suspend($value);"
|
||||
c.resume(value)
|
||||
COROUTINE_SUSPENDED
|
||||
}
|
||||
|
||||
var count = 0
|
||||
|
||||
fun <T> log(value: T) {
|
||||
result += "$value"
|
||||
}
|
||||
|
||||
fun check(): Boolean = count > 1
|
||||
|
||||
suspend fun foo() { count++ }
|
||||
}
|
||||
|
||||
fun builder(c: suspend Controller.() -> Unit): String {
|
||||
val controller = Controller()
|
||||
c.startCoroutine(controller, handleResultContinuation {
|
||||
controller.result += "return;"
|
||||
})
|
||||
return controller.result
|
||||
}
|
||||
|
||||
suspend fun Controller.test() {
|
||||
var exception: Throwable? = null
|
||||
suspendLoop@do {
|
||||
log("slh;")
|
||||
foo()
|
||||
regularLoop@do {
|
||||
log("rlh;")
|
||||
if (!check()) {
|
||||
log("rlb;")
|
||||
break@regularLoop
|
||||
}
|
||||
|
||||
log("rlc;")
|
||||
|
||||
if (check()) {
|
||||
log("slb;")
|
||||
break@suspendLoop
|
||||
}
|
||||
|
||||
log("fail1;")
|
||||
} while (false)
|
||||
|
||||
log("slt;")
|
||||
} while (true)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val res = builder {
|
||||
test()
|
||||
}
|
||||
|
||||
if (res != "slh;rlh;rlb;slt;slh;rlh;rlc;slb;return;") return "FAIL: $res"
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// COMMON_COROUTINES_TEST
|
||||
import helpers.*
|
||||
import COROUTINES_PACKAGE.*
|
||||
import COROUTINES_PACKAGE.intrinsics.*
|
||||
|
||||
class Controller {
|
||||
var result = ""
|
||||
|
||||
var count = 0
|
||||
fun expect(i: Int) {
|
||||
if (++count != i) throw Exception("EXPECTED $i")
|
||||
}
|
||||
|
||||
fun <T> log(value: T) {
|
||||
result += "$value"
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(c: suspend Controller.() -> Unit): String {
|
||||
val controller = Controller()
|
||||
c.startCoroutine(controller, handleResultContinuation {
|
||||
controller.result += "return;"
|
||||
})
|
||||
return controller.result
|
||||
}
|
||||
|
||||
suspend fun Controller.makeException(i: Int): Throwable? {
|
||||
expect(i)
|
||||
return Error("CHECK")
|
||||
}
|
||||
suspend fun Controller.rethrowException(i: Int, t: Throwable?) {
|
||||
expect(i)
|
||||
t?.let { throw it }
|
||||
}
|
||||
|
||||
suspend fun Controller.test() {
|
||||
var exception: Throwable? = null
|
||||
expect(1)
|
||||
try {
|
||||
exception = makeException(2)
|
||||
log("try(t);")
|
||||
} finally {
|
||||
// Separate method because of KT-32220
|
||||
rethrowException(3, exception)
|
||||
log("FAIL2")
|
||||
exception?.let { throw it }
|
||||
}
|
||||
log("FAIL3")
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val res = builder {
|
||||
try {
|
||||
log("try;")
|
||||
test()
|
||||
} catch (e: Error) {
|
||||
log("catch;")
|
||||
}
|
||||
}
|
||||
|
||||
if (res != "try;try(t);catch;return;") return "FAIL: $res"
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user