[K/JS] Reset exceptionState inside coroutines with a finally block ^KT-58685 Fixed

This commit is contained in:
Artem Kobzar
2023-09-12 15:18:16 +00:00
committed by Space Team
parent 752ea6fd98
commit 7bc521ab92
8 changed files with 86 additions and 6 deletions
@@ -27,6 +27,8 @@ import org.jetbrains.kotlin.ir.util.setDeclarationsParent
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
object FINALLY_EXPRESSION : IrStatementOriginImpl("FINALLY_EXPRESSION")
class FinallyBlocksLowering(val context: CommonBackendContext, private val throwableType: IrType): FileLoweringPass, IrElementTransformerVoidWithContext() {
private interface HighLevelJump {
@@ -271,13 +273,17 @@ class FinallyBlocksLowering(val context: CommonBackendContext, private val throw
+irReturnableBlock(symbol, type) {
+value
}
+copy(finallyExpression)
+irComposite(resultType = context.irBuiltIns.unitType, origin = FINALLY_EXPRESSION) {
+copy(finallyExpression)
}
}
else -> irBlock(value, null, type) {
val tmp = createTmpVariable(irReturnableBlock(symbol, type) {
+irReturn(symbol, value)
})
+copy(finallyExpression)
+irComposite(resultType = context.irBuiltIns.unitType, origin = FINALLY_EXPRESSION) {
+copy(finallyExpression)
}
+irGet(tmp)
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.ir.backend.js.lower.coroutines
import org.jetbrains.kotlin.backend.common.ir.isPure
import org.jetbrains.kotlin.backend.common.lower.FINALLY_EXPRESSION
import org.jetbrains.kotlin.backend.common.peek
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
@@ -396,6 +397,13 @@ class StateMachineBuilder(
private fun wrap(expression: IrExpression, variable: IrVariableSymbol) =
JsIrBuilder.buildSetVariable(variable, expression, unit)
override fun visitComposite(expression: IrComposite) {
if (expression.origin == FINALLY_EXPRESSION) {
catchBlockStack.peek()?.let(::setupExceptionState)
}
super.visitComposite(expression)
}
override fun visitWhen(expression: IrWhen) {
if (expression !in suspendableNodes) return addStatement(expression)
@@ -709,7 +717,6 @@ class StateMachineBuilder(
catchBlockStack.pop()
updateState(tryState.catchState)
setupExceptionState(enclosingCatch)
var rethrowNeeded = true
-3
View File
@@ -1,6 +1,3 @@
// IGNORE_BACKEND_K2: WASM
// ^ KT-59800 K2 + Wasm: test failure after changing `finally` block generation
fun test1() : Boolean {
try {
return true
@@ -961,6 +961,12 @@ public class FirJsBoxTestGenerated extends AbstractFirJsBoxTest {
public void testSuspendMethodWithSuperCall() throws Exception {
runTest("js/js.translator/testData/box/coroutines/suspendMethodWithSuperCall.kt");
}
@Test
@TestMetadata("tryFinally.kt")
public void testTryFinally() throws Exception {
runTest("js/js.translator/testData/box/coroutines/tryFinally.kt");
}
}
@Nested
@@ -961,6 +961,12 @@ public class FirJsES6BoxTestGenerated extends AbstractFirJsES6BoxTest {
public void testSuspendMethodWithSuperCall() throws Exception {
runTest("js/js.translator/testData/box/coroutines/suspendMethodWithSuperCall.kt");
}
@Test
@TestMetadata("tryFinally.kt")
public void testTryFinally() throws Exception {
runTest("js/js.translator/testData/box/coroutines/tryFinally.kt");
}
}
@Nested
@@ -961,6 +961,12 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test {
public void testSuspendMethodWithSuperCall() throws Exception {
runTest("js/js.translator/testData/box/coroutines/suspendMethodWithSuperCall.kt");
}
@Test
@TestMetadata("tryFinally.kt")
public void testTryFinally() throws Exception {
runTest("js/js.translator/testData/box/coroutines/tryFinally.kt");
}
}
@Nested
@@ -961,6 +961,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
public void testSuspendMethodWithSuperCall() throws Exception {
runTest("js/js.translator/testData/box/coroutines/suspendMethodWithSuperCall.kt");
}
@Test
@TestMetadata("tryFinally.kt")
public void testTryFinally() throws Exception {
runTest("js/js.translator/testData/box/coroutines/tryFinally.kt");
}
}
@Nested
+46
View File
@@ -0,0 +1,46 @@
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
var isLocked = false
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object : Continuation<Unit> {
override val context = EmptyCoroutineContext
override fun resumeWith(result: Result<Unit>) {}
})
}
private suspend fun lock() {
isLocked = true
}
private fun unlock() {
if (isLocked) {
isLocked = false
} else {
throw IllegalStateException("Not locked")
}
}
private suspend inline fun <T> withLock(block: () -> T): T {
lock()
try {
return block()
} finally {
unlock()
}
}
fun box(): String {
var error: Exception? = null
builder {
try {
withLock {}
throw Exception("seems fine")
} catch (e: Exception) {
error = e
}
}
return if (error !is IllegalStateException) "OK" else "fail"
}