[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:
Roman Artemev
2019-11-18 15:13:09 +03:00
committed by romanart
parent 18d0b477b6
commit c459b2ca6e
11 changed files with 288 additions and 41 deletions
@@ -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"
}