diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/KotlinNothingValueExceptionLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/KotlinNothingValueExceptionLowering.kt index f904a5a1797..d7a3af77ca2 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/KotlinNothingValueExceptionLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/KotlinNothingValueExceptionLowering.kt @@ -7,8 +7,10 @@ package org.jetbrains.kotlin.backend.common.lower import org.jetbrains.kotlin.backend.common.BodyLoweringPass import org.jetbrains.kotlin.backend.common.CommonBackendContext +import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.expressions.IrBody import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrExpression @@ -20,6 +22,9 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid class KotlinNothingValueExceptionLowering( val backendContext: CommonBackendContext, val skip: (IrDeclaration) -> Boolean = { false } ) : BodyLoweringPass { + override fun lower(irFile: IrFile) = + runOnFilePostfix(irFile, withLocalDeclarations = true) + override fun lower(irBody: IrBody, container: IrDeclaration) { if (!skip(container)) { irBody.transformChildrenVoid(Transformer(container.symbol)) @@ -27,6 +32,8 @@ class KotlinNothingValueExceptionLowering( } private inner class Transformer(val parent: IrSymbol) : IrElementTransformerVoid() { + override fun visitBody(body: IrBody): IrBody = body + override fun visitCall(expression: IrCall): IrExpression = if (expression.type.isNothing()) { // Replace call 'foo' of type 'kotlin.Nothing' with a block: diff --git a/compiler/testData/codegen/box/coroutines/tailCallToNothing.kt b/compiler/testData/codegen/box/coroutines/tailCallToNothing.kt index 599cb5dbec7..92992c861ff 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallToNothing.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallToNothing.kt @@ -5,12 +5,14 @@ import helpers.* import kotlin.coroutines.* import kotlin.coroutines.intrinsics.* +class Success : RuntimeException() + suspend fun suspendThenThrow(): Nothing { suspendCoroutineUninterceptedOrReturn { it.resume(Unit) COROUTINE_SUSPENDED } - throw RuntimeException() + throw Success() } suspend fun foo(x: Int = 1): Nothing = suspendThenThrow() @@ -26,9 +28,20 @@ class C : I by (object : I { var result = "" fun box(): String { + var counter = 0 suspend { - try { foo() } catch (e: RuntimeException) { result += "O" } - try { C().bar() } catch (e: RuntimeException) { result += "K" } + // 1. foo$default is a bridge to foo, should not throw after foo returns + try { foo() } catch (e: Success) { counter++ } + // 2. C.bar is a delegation to another method, so same + try { C().bar() } catch (e: Success) { counter++ } + // 3. object.foo$default is the same as 1 but in a local object + try { + object { + suspend fun foo(x: Int = 1): Nothing = suspendThenThrow() + }.foo() + } catch (e: Success) { counter++ } + // 4. this point should be reached exactly once + counter++ }.startCoroutine(EmptyContinuation) - return result + return if (counter == 4) "OK" else "counter incremented $counter times" }