JVM_IR: do not handle Nothing in suspend tail call bridges

Else they wouldn't be tail call, would they?
This commit is contained in:
pyos
2020-05-07 14:48:07 +02:00
committed by Ilmir Usmanov
parent 0acaedef92
commit 8809abdbac
10 changed files with 74 additions and 10 deletions
@@ -6706,6 +6706,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/suspensionInsideSafeCall.kt", "kotlin.coroutines");
}
@TestMetadata("tailCallToNothing.kt")
public void testTailCallToNothing() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/tailCallToNothing.kt");
}
@TestMetadata("tryCatchFinallyWithHandleResult.kt")
public void testTryCatchFinallyWithHandleResult_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tryCatchFinallyWithHandleResult.kt", "kotlin.coroutines");
@@ -19,11 +19,13 @@ import org.jetbrains.kotlin.ir.types.isNothing
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
class KotlinNothingValueExceptionLowering(val backendContext: CommonBackendContext) : BodyLoweringPass {
class KotlinNothingValueExceptionLowering(
val backendContext: CommonBackendContext, val skip: (IrDeclaration) -> Boolean = { false }
) : BodyLoweringPass {
override fun lower(irBody: IrBody, container: IrDeclaration) {
irBody.transformChildrenVoid(
Transformer((container as IrSymbolDeclaration<*>).symbol)
)
if (!skip(container)) {
irBody.transformChildrenVoid(Transformer((container as IrSymbolDeclaration<*>).symbol))
}
}
private inner class Transformer(val parent: IrSymbol) : IrElementTransformerVoid() {
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.lower.loops.forLoopsPhase
import org.jetbrains.kotlin.backend.common.lower.optimizations.foldConstantLoweringPhase
import org.jetbrains.kotlin.backend.common.phaser.*
import org.jetbrains.kotlin.backend.jvm.codegen.shouldContainSuspendMarkers
import org.jetbrains.kotlin.backend.jvm.lower.*
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
@@ -262,8 +263,8 @@ private val tailrecPhase = makeIrFilePhase(
description = "Handle tailrec calls"
)
private val kotlinNothingValueExceptionPhase = makeIrFilePhase(
::KotlinNothingValueExceptionLowering,
private val kotlinNothingValueExceptionPhase = makeIrFilePhase<CommonBackendContext>(
{ context -> KotlinNothingValueExceptionLowering(context) { it is IrFunction && !it.shouldContainSuspendMarkers() } },
name = "KotlinNothingValueException",
description = "Throw proper exception for calls returning value of type 'kotlin.Nothing'"
)
@@ -449,12 +449,9 @@ class ExpressionCodegen(
}
return when {
expression.type.isNothing() -> {
unitValue
}
expression is IrConstructorCall ->
MaterialValue(this, asmType, expression.type)
expression.type.isUnit() && irFunction.shouldContainSuspendMarkers() -> {
(expression.type.isNothing() || expression.type.isUnit()) && irFunction.shouldContainSuspendMarkers() -> {
// NewInference allows casting `() -> T` to `() -> Unit`. A CHECKCAST here will fail.
// Also, if the callee is a suspend function with a suspending tail call, the next `resumeWith`
// will continue from here, but the value passed to it might not have been `Unit`. An exception
@@ -0,0 +1,34 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
import helpers.*
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
suspend fun suspendThenThrow(): Nothing {
suspendCoroutineUninterceptedOrReturn<Unit> {
it.resume(Unit)
COROUTINE_SUSPENDED
}
throw RuntimeException()
}
suspend fun foo(x: Int = 1): Nothing = suspendThenThrow()
interface I {
suspend fun bar(): Nothing
}
class C : I by (object : I {
override suspend fun bar(): Nothing = suspendThenThrow()
})
var result = ""
fun box(): String {
suspend {
try { foo() } catch (e: RuntimeException) { result += "O" }
try { C().bar() } catch (e: RuntimeException) { result += "K" }
}.startCoroutine(EmptyContinuation)
return result
}
@@ -7136,6 +7136,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/suspensionInsideSafeCall.kt", "kotlin.coroutines");
}
@TestMetadata("tailCallToNothing.kt")
public void testTailCallToNothing() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/tailCallToNothing.kt");
}
@TestMetadata("tryCatchFinallyWithHandleResult.kt")
public void testTryCatchFinallyWithHandleResult_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tryCatchFinallyWithHandleResult.kt", "kotlin.coroutines.experimental");
@@ -7136,6 +7136,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/suspensionInsideSafeCall.kt", "kotlin.coroutines");
}
@TestMetadata("tailCallToNothing.kt")
public void testTailCallToNothing() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/tailCallToNothing.kt");
}
@TestMetadata("tryCatchFinallyWithHandleResult.kt")
public void testTryCatchFinallyWithHandleResult_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tryCatchFinallyWithHandleResult.kt", "kotlin.coroutines.experimental");
@@ -6706,6 +6706,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/suspensionInsideSafeCall.kt", "kotlin.coroutines");
}
@TestMetadata("tailCallToNothing.kt")
public void testTailCallToNothing() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/tailCallToNothing.kt");
}
@TestMetadata("tryCatchFinallyWithHandleResult.kt")
public void testTryCatchFinallyWithHandleResult_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tryCatchFinallyWithHandleResult.kt", "kotlin.coroutines");
@@ -5656,6 +5656,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/suspensionInsideSafeCall.kt", "kotlin.coroutines");
}
@TestMetadata("tailCallToNothing.kt")
public void testTailCallToNothing() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/tailCallToNothing.kt");
}
@TestMetadata("tryCatchFinallyWithHandleResult.kt")
public void testTryCatchFinallyWithHandleResult_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tryCatchFinallyWithHandleResult.kt", "kotlin.coroutines");
@@ -5656,6 +5656,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/suspensionInsideSafeCall.kt", "kotlin.coroutines");
}
@TestMetadata("tailCallToNothing.kt")
public void testTailCallToNothing() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/tailCallToNothing.kt");
}
@TestMetadata("tryCatchFinallyWithHandleResult.kt")
public void testTryCatchFinallyWithHandleResult_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tryCatchFinallyWithHandleResult.kt", "kotlin.coroutines");