diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt index 4da35f03929..210ebae33fd 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt @@ -14,9 +14,6 @@ import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.coroutines.SUSPEND_IMPL_NAME_SUFFIX import org.jetbrains.kotlin.codegen.mangleNameIfNeeded import org.jetbrains.kotlin.codegen.state.GenerationState -import org.jetbrains.kotlin.codegen.ClassBuilderMode -import org.jetbrains.kotlin.codegen.coroutines.SUSPEND_IMPL_NAME_SUFFIX -import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX import org.jetbrains.kotlin.codegen.visitAnnotableParameterCount import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.Modality @@ -122,8 +119,11 @@ open class FunctionCodegen( isAnonymousObject || origin == JvmLoweredDeclarationOrigin.CONTINUATION_CLASS || origin == JvmLoweredDeclarationOrigin.SUSPEND_LAMBDA private fun psiElement(): KtElement = - if (irFunction.isSuspend) irFunction.symbol.descriptor.psiElement as KtElement - else context.suspendLambdaToOriginalFunctionMap[irFunction.parentAsClass.attributeOwnerId]!!.symbol.descriptor.psiElement as KtElement + (if (irFunction.isSuspend) + irFunction.symbol.descriptor.psiElement ?: irFunction.parentAsClass.descriptor.psiElement + else + context.suspendLambdaToOriginalFunctionMap[irFunction.parentAsClass.attributeOwnerId]!!.symbol.descriptor.psiElement) + as KtElement private fun IrFunction.hasContinuation(): Boolean = isSuspend && // We do not generate continuation and state-machine for synthetic accessors, bridges, and delegated members, diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/interfaceDelegation.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/interfaceDelegation.kt new file mode 100644 index 00000000000..5ad7c1cdeb3 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/interfaceDelegation.kt @@ -0,0 +1,56 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM +// FULL_JDK +// WITH_RUNTIME +// WITH_COROUTINES +// CHECK_TAIL_CALL_OPTIMIZATION +import helpers.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* + +suspend fun suspendThere(v: String): String = suspendCoroutineUninterceptedOrReturn { x -> + TailCallOptimizationChecker.saveStackTrace(x) + x.resume(v) + COROUTINE_SUSPENDED +} + +interface I { + suspend fun suspendHere(): String + + suspend fun suspendHereNoTailCall(): String +} + +class A : I { + override suspend fun suspendHere(): String = suspendThere("OK") + + override suspend fun suspendHereNoTailCall(): String { + suspendThere("FAIL 2") + return "OK" + } +} + +open class B(val x: I) : I by x // open override suspend fun suspendHere() = x.suspendHere() + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var result = "" + + builder { + result = B(A()).suspendHere() + } + TailCallOptimizationChecker.checkNoStateMachineIn("suspendHere") + TailCallOptimizationChecker.checkNoStateMachineIn("suspendHere\$suspendImpl") + + if (result != "OK") return "FAIL 1" + + builder { + result = B(A()).suspendHereNoTailCall() + } + TailCallOptimizationChecker.checkStateMachineIn("suspendHereNoTailCall") + TailCallOptimizationChecker.checkNoStateMachineIn("suspendHereNoTailCall\$suspendImpl") + + return result +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 7c5650be0fe..eb7c5788d7d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -8612,6 +8612,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation.kt", "kotlin.coroutines"); } + @TestMetadata("interfaceDelegation.kt") + public void testInterfaceDelegation() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/interfaceDelegation.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/simple.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 36a591536bf..fcd08a3ebdf 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -8612,6 +8612,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation.kt", "kotlin.coroutines"); } + @TestMetadata("interfaceDelegation.kt") + public void testInterfaceDelegation() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/interfaceDelegation.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/simple.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 45fbbd5616f..20e06673d6e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -7517,6 +7517,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation.kt", "kotlin.coroutines"); } + @TestMetadata("interfaceDelegation.kt") + public void testInterfaceDelegation() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/interfaceDelegation.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/simple.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 7042980af16..b29f7b78a4b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -7517,6 +7517,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation.kt", "kotlin.coroutines"); } + @TestMetadata("interfaceDelegation.kt") + public void testInterfaceDelegation() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/interfaceDelegation.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/simple.kt");