diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt index f6aff56026e..fcfe41aa36d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt @@ -475,7 +475,8 @@ class CoroutineCodegenForLambda private constructor( shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization, containingClassInternalName = v.thisName, isForNamedFunction = false, - languageVersionSettings = languageVersionSettings + languageVersionSettings = languageVersionSettings, + disableTailCallOptimizationForFunctionReturningUnit = false ) return if (forInline) AddEndLabelMethodVisitor( MethodNodeCopyingMethodVisitor( diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt index 5f739b05b87..8d3e993dfe6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt @@ -63,6 +63,10 @@ class CoroutineTransformerMethodVisitor( // These two are needed to report diagnostics about suspension points inside critical section private val element: KtElement, private val diagnostics: DiagnosticSink, + // Since tail-call optimization of functions with Unit return type relies on ability of call-site to recognize them, + // in order to ignore return value and push Unit, when we cannot ensure this ability, for example, when the function overrides function, + // returning Any, we need to disable tail-call optimization for these functions. + private val disableTailCallOptimizationForFunctionReturningUnit: Boolean, // It's only matters for named functions, may differ from '!isStatic(access)' in case of DefaultImpls private val needDispatchReceiver: Boolean = false, // May differ from containingClassInternalName in case of DefaultImpls @@ -111,7 +115,8 @@ class CoroutineTransformerMethodVisitor( val examiner = MethodNodeExaminer( languageVersionSettings, containingClassInternalName, - methodNode + methodNode, + disableTailCallOptimizationForFunctionReturningUnit ) if (examiner.allSuspensionPointsAreTailCalls(suspensionPoints)) { examiner.replacePopsBeforeSafeUnitInstancesWithCoroutineSuspendedChecks() @@ -899,7 +904,8 @@ class CoroutineTransformerMethodVisitor( private class MethodNodeExaminer( val languageVersionSettings: LanguageVersionSettings, val containingClassInternalName: String, - val methodNode: MethodNode + val methodNode: MethodNode, + disableTailCallOptimizationForFunctionReturningUnit: Boolean ) { private val sourceFrames: Array?> = MethodTransformer.analyze(containingClassInternalName, methodNode, IgnoringCopyOperationSourceInterpreter()) @@ -912,25 +918,27 @@ private class MethodNodeExaminer( private val meaningfulPredecessorsCache = hashMapOf>() init { - // retrieve all POP insns - val pops = methodNode.instructions.asSequence().filter { it.opcode == Opcodes.POP } - // for each of them check that all successors are PUSH Unit - val popsBeforeUnitInstances = pops.map { it to it.meaningfulSuccessors() } - .filter { (_, succs) -> succs.all { it.isUnitInstance() } } - .map { it.first }.toList() - for (pop in popsBeforeUnitInstances) { - val units = pop.meaningfulSuccessors() - val allUnitsAreSafe = units.all { unit -> - // check no other predecessor exists - unit.meaningfulPredecessors().all { it in popsBeforeUnitInstances } && - // check they have only returns among successors - unit.meaningfulSuccessors().all { it.opcode == Opcodes.ARETURN } + if (!disableTailCallOptimizationForFunctionReturningUnit) { + // retrieve all POP insns + val pops = methodNode.instructions.asSequence().filter { it.opcode == Opcodes.POP } + // for each of them check that all successors are PUSH Unit + val popsBeforeUnitInstances = pops.map { it to it.meaningfulSuccessors() } + .filter { (_, succs) -> succs.all { it.isUnitInstance() } } + .map { it.first }.toList() + for (pop in popsBeforeUnitInstances) { + val units = pop.meaningfulSuccessors() + val allUnitsAreSafe = units.all { unit -> + // check no other predecessor exists + unit.meaningfulPredecessors().all { it in popsBeforeUnitInstances } && + // check they have only returns among successors + unit.meaningfulSuccessors().all { it.opcode == Opcodes.ARETURN } + } + if (!allUnitsAreSafe) continue + // save them all to the properties + popsBeforeSafeUnitInstances += pop + safeUnitInstances += units + units.flatMapTo(areturnsAfterSafeUnitInstances) { it.meaningfulSuccessors() } } - if (!allUnitsAreSafe) continue - // save them all to the properties - popsBeforeSafeUnitInstances += pop - safeUnitInstances += units - units.flatMapTo(areturnsAfterSafeUnitInstances) { it.meaningfulSuccessors() } } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt index e557003142f..e8ff4783de7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.sure import org.jetbrains.org.objectweb.asm.MethodVisitor @@ -100,10 +101,27 @@ open class SuspendFunctionGenerationStrategy( shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization, needDispatchReceiver = originalSuspendDescriptor.dispatchReceiverParameter != null, internalNameForDispatchReceiver = containingClassInternalNameOrNull(), - languageVersionSettings = languageVersionSettings + languageVersionSettings = languageVersionSettings, + disableTailCallOptimizationForFunctionReturningUnit = originalSuspendDescriptor.returnType?.isUnit() == true && + originalSuspendDescriptor.overriddenDescriptors.isNotEmpty() && + !originalSuspendDescriptor.allOverriddenFunctionsReturnUnit() ) } + private fun FunctionDescriptor.allOverriddenFunctionsReturnUnit(): Boolean { + val visited = mutableSetOf() + + fun bfs(descriptor: FunctionDescriptor): Boolean { + if (!visited.add(descriptor)) return true + if (descriptor.original.returnType?.isUnit() != true) return false + for (parent in descriptor.overriddenDescriptors) { + if (!bfs(parent)) return false + } + return true + } + return bfs(this) + } + private fun containingClassInternalNameOrNull() = originalSuspendDescriptor.containingDeclaration.safeAs()?.let(state.typeMapper::mapClass)?.internalName diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt index bceae4fe982..103f4aa0a8c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt @@ -17,11 +17,20 @@ import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.load.java.JvmAnnotationNames +import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass +import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader +import org.jetbrains.kotlin.load.kotlin.header.ReadKotlinClassHeaderAnnotationVisitor +import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.deserialization.* +import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin +import org.jetbrains.kotlin.serialization.deserialization.getClassId +import org.jetbrains.kotlin.serialization.deserialization.getName import org.jetbrains.kotlin.utils.addToStdlib.cast -import org.jetbrains.org.objectweb.asm.MethodVisitor -import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.* import org.jetbrains.org.objectweb.asm.tree.* import org.jetbrains.org.objectweb.asm.tree.analysis.Frame import org.jetbrains.org.objectweb.asm.tree.analysis.SourceInterpreter @@ -108,7 +117,8 @@ class CoroutineTransformer( languageVersionSettings = state.languageVersionSettings, shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization, containingClassInternalName = classBuilder.thisName, - isForNamedFunction = false + isForNamedFunction = false, + disableTailCallOptimizationForFunctionReturningUnit = false ) ) @@ -137,6 +147,8 @@ class CoroutineTransformer( ArrayUtil.toStringArray(node.exceptions) ) ) { + // If the node already has state-machine, it is safer to generate state-machine. + val disableTailCallOptimization = methods.find { it.name == name && it.desc == node.desc }?.let { isStateMachine(it) } ?: false val stateMachineBuilder = surroundNoinlineCallsWithMarkers( node, CoroutineTransformerMethodVisitor( @@ -149,7 +161,8 @@ class CoroutineTransformer( containingClassInternalName = classBuilder.thisName, isForNamedFunction = true, needDispatchReceiver = true, - internalNameForDispatchReceiver = classBuilder.thisName + internalNameForDispatchReceiver = classBuilder.thisName, + disableTailCallOptimizationForFunctionReturningUnit = disableTailCallOptimization ) ) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt index 3881a944104..a17c1f04954 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.types.createType import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection +import org.jetbrains.kotlin.ir.types.isUnit import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid @@ -40,6 +41,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource import org.jetbrains.kotlin.types.Variance import org.jetbrains.org.objectweb.asm.MethodVisitor +import org.jetbrains.org.objectweb.asm.Opcodes internal fun generateStateMachineForNamedFunction( irFunction: IrFunction, @@ -58,7 +60,7 @@ internal fun generateStateMachineForNamedFunction( val languageVersionSettings = state.languageVersionSettings assert(languageVersionSettings.isReleaseCoroutines()) { "Experimental coroutines are unsupported in JVM_IR backend" } return CoroutineTransformerMethodVisitor( - methodVisitor, access, signature.asmMethod.name, signature.asmMethod.descriptor, null, null, + methodVisitor, access, signature.asmMethod.name, signature.asmMethod.descriptor, signature.genericsSignature, null, obtainClassBuilderForCoroutineState = { continuationClassBuilder!! }, element = element, diagnostics = state.diagnostics, @@ -69,7 +71,11 @@ internal fun generateStateMachineForNamedFunction( needDispatchReceiver = irFunction.dispatchReceiverParameter != null || irFunction.origin == JvmLoweredDeclarationOrigin.SUSPEND_IMPL_STATIC_FUNCTION, internalNameForDispatchReceiver = classCodegen.visitor.thisName, - putContinuationParameterToLvt = false + putContinuationParameterToLvt = false, + disableTailCallOptimizationForFunctionReturningUnit = irFunction.returnType.isUnit() && + (irFunction as? IrSimpleFunction)?.overriddenSymbols?.let { symbols -> + symbols.isNotEmpty() && symbols.any { !it.owner.returnType.isUnit() } + } == true ) } @@ -84,14 +90,15 @@ internal fun generateStateMachineForLambda( val languageVersionSettings = state.languageVersionSettings assert(languageVersionSettings.isReleaseCoroutines()) { "Experimental coroutines are unsupported in JVM_IR backend" } return CoroutineTransformerMethodVisitor( - methodVisitor, access, signature.asmMethod.name, signature.asmMethod.descriptor, null, null, + methodVisitor, access, signature.asmMethod.name, signature.asmMethod.descriptor, signature.genericsSignature, null, obtainClassBuilderForCoroutineState = { classCodegen.visitor }, element = element, diagnostics = state.diagnostics, languageVersionSettings = languageVersionSettings, shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization, containingClassInternalName = classCodegen.visitor.thisName, - isForNamedFunction = false + isForNamedFunction = false, + disableTailCallOptimizationForFunctionReturningUnit = false ) } diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override.kt new file mode 100644 index 00000000000..e70a8df6413 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override.kt @@ -0,0 +1,42 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM_IR +// FULL_JDK +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.* + +var c: Continuation<*>? = null + +suspend fun tx(lambda: () -> T): T = suspendCoroutine { c = it; lambda() } + +object Dummy + +interface Base { + suspend fun generic(): T +} + +class Derived: Base { + override suspend fun generic(): Unit { + tx { Dummy } + } +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res: Any? = null + + builder { + val base: Base<*> = Derived() + res = base.generic() + } + + (c as? Continuation)?.resume(Dummy) + + return if (res != Unit) "$res" else "OK" +} diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override2.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override2.kt new file mode 100644 index 00000000000..4a18e1c9b4d --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override2.kt @@ -0,0 +1,44 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM_IR +// FULL_JDK +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.* + +var c: Continuation<*>? = null + +suspend fun tx(lambda: () -> T): T = suspendCoroutine { c = it; lambda() } + +object Dummy + +interface Base { + suspend fun generic(): T +} + +abstract class Derived1: Base { +} + +class Derived2: Derived1() { + override suspend fun generic(): Unit { + tx { Dummy } + } +} +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res: Any? = null + + builder { + val base: Base<*> = Derived2() + res = base.generic() + } + + (c as? Continuation)?.resume(Dummy) + + return if (res != Unit) "$res" else "OK" +} diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override3.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override3.kt new file mode 100644 index 00000000000..948463c0100 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override3.kt @@ -0,0 +1,46 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM_IR +// FULL_JDK +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.* + +var c: Continuation<*>? = null + +suspend fun tx(lambda: () -> T): T = suspendCoroutine { c = it; lambda() } + +object Dummy + +interface Foo { + suspend fun generic(): Any +} + +interface Base { + suspend fun generic(): Unit +} + +class Derived: Base, Foo { + override suspend fun generic(): Unit { + tx { Dummy } + } +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res: Any? = null + + builder { + val foo: Foo = Derived() + res = foo.generic() + } + + (c as? Continuation)?.resume(Dummy) + + return if (res != Unit) "$res" else "OK" +} diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override4.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override4.kt new file mode 100644 index 00000000000..7a53634ef7d --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override4.kt @@ -0,0 +1,40 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM_IR +// FULL_JDK +// WITH_RUNTIME +// WITH_COROUTINES +// CHECK_TAIL_CALL_OPTIMIZATION + +import helpers.* +import kotlin.coroutines.* + +var c: Continuation<*>? = null + +suspend fun suspendHere() = TailCallOptimizationChecker.saveStackTrace() + +interface Base { + suspend fun generic(): T +} + +inline fun inlineMe(crossinline c: suspend () -> Unit) = object : Base { + override suspend fun generic(): Unit { + c() + suspendHere() + } +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + builder { + inlineMe { }.generic() + } + + // TODO: There should be no state-machine. Should fix in IR_BE + TailCallOptimizationChecker.checkStateMachineIn("generic") + + return "OK" +} diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5.kt new file mode 100644 index 00000000000..c9bd9c70e1f --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5.kt @@ -0,0 +1,35 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM_IR +// FULL_JDK +// WITH_RUNTIME +// WITH_COROUTINES +// CHECK_BYTECODE_LISTING + +import helpers.* +import kotlin.coroutines.* + +var c: Continuation<*>? = null + +interface Base { + suspend fun generic(): T +} + +inline fun inlineMe(crossinline c: suspend () -> Unit) = object : Base { + override suspend fun generic(): Unit { + c(); + {}() + } +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + builder { + inlineMe { }.generic() + } + + return "OK" +} diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5.txt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5.txt new file mode 100644 index 00000000000..f72b5f9bcf7 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5.txt @@ -0,0 +1,70 @@ +@kotlin.Metadata +public interface Base { + public abstract @org.jetbrains.annotations.Nullable method generic(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object +} + +@kotlin.Metadata +public final class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1 { + inner class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1 + inner class Override5Kt$inlineMe$1$generic$2 + public method (): void + public @org.jetbrains.annotations.Nullable method generic(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object +} + +@kotlin.coroutines.jvm.internal.DebugMetadata +@kotlin.Metadata +final class Override5Kt$box$1 { + field label: int + inner class Override5Kt$box$1 + method (p0: kotlin.coroutines.Continuation): void + public final @org.jetbrains.annotations.NotNull method create(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): kotlin.coroutines.Continuation + public final method invoke(p0: java.lang.Object): java.lang.Object + public final @org.jetbrains.annotations.Nullable method invokeSuspend(@org.jetbrains.annotations.NotNull p0: java.lang.Object): java.lang.Object +} + +@kotlin.Metadata +@kotlin.coroutines.jvm.internal.DebugMetadata +public final class Override5Kt$inlineMe$1$generic$1 { + field L$0: java.lang.Object + field label: int + synthetic field result: java.lang.Object + synthetic final field this$0: Override5Kt$inlineMe$1 + inner class Override5Kt$inlineMe$1 + inner class Override5Kt$inlineMe$1$generic$1 + public method (p0: Override5Kt$inlineMe$1, p1: kotlin.coroutines.Continuation): void + public final @org.jetbrains.annotations.Nullable method invokeSuspend(@org.jetbrains.annotations.NotNull p0: java.lang.Object): java.lang.Object +} + +@kotlin.Metadata +public final class Override5Kt$inlineMe$1$generic$2 { + public final static field INSTANCE: Override5Kt$inlineMe$1$generic$2 + inner class Override5Kt$inlineMe$1 + inner class Override5Kt$inlineMe$1$generic$2 + static method (): void + public method (): void + public synthetic method invoke(): java.lang.Object + public final method invoke(): void +} + +@kotlin.Metadata +public final class Override5Kt$inlineMe$1 { + synthetic final field $c: kotlin.jvm.functions.Function1 + inner class Override5Kt$inlineMe$1 + inner class Override5Kt$inlineMe$1$generic$1 + inner class Override5Kt$inlineMe$1$generic$2 + public method (p0: kotlin.jvm.functions.Function1): void + public @org.jetbrains.annotations.Nullable method generic$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object + public @org.jetbrains.annotations.Nullable method generic(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object +} + +@kotlin.Metadata +public final class Override5Kt { + private static @org.jetbrains.annotations.Nullable field c: kotlin.coroutines.Continuation + inner class Override5Kt$box$1 + inner class Override5Kt$inlineMe$1 + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String + public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void + public final static @org.jetbrains.annotations.Nullable method getC(): kotlin.coroutines.Continuation + public final static @org.jetbrains.annotations.NotNull method inlineMe(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): Base + public final static method setC(@org.jetbrains.annotations.Nullable p0: kotlin.coroutines.Continuation): void +} diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override6.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override6.kt new file mode 100644 index 00000000000..ecae95eb9a6 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override6.kt @@ -0,0 +1,38 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM_IR +// FULL_JDK +// WITH_RUNTIME +// WITH_COROUTINES +// CHECK_TAIL_CALL_OPTIMIZATION + +import helpers.* +import kotlin.coroutines.* + +var c: Continuation<*>? = null + +suspend fun suspendHere() = TailCallOptimizationChecker.saveStackTrace() + +interface Base { + suspend fun generic(): T +} + +inline fun inlineMe(crossinline c: suspend () -> Unit) = object : Base { + override suspend fun generic(): Unit { + c() + } +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + builder { + inlineMe { suspendHere() }.generic() + } + + TailCallOptimizationChecker.checkStateMachineIn("generic") + + return "OK" +} diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideCrossinline.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideCrossinline.kt new file mode 100644 index 00000000000..469541625b6 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideCrossinline.kt @@ -0,0 +1,53 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM_IR +// FULL_JDK +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.* + +var c: Continuation<*>? = null + +suspend fun tx(lambda: () -> T): T = suspendCoroutine { c = it; lambda() } + +object Dummy + +interface Base { + suspend fun callMe(a: IntArray): Unit + suspend fun callMe(s: String): Unit + suspend fun callMe(a: Array): Unit + suspend fun callMe(a: Int): T +} + +inline fun inlineMe(crossinline c: suspend () -> Unit): Base<*> { + return object: Base { + override suspend fun callMe(a: IntArray) {} + + override suspend fun callMe(a: Int): Unit { + c() + } + + override suspend fun callMe(s: String) {} + override suspend fun callMe(a: Array) {} + } +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res: Any? = null + + builder { + res = inlineMe { + tx { Dummy } + }.callMe(1) + } + + (c as? Continuation)?.resume(Dummy) + + return if (res != Unit) "$res" else "OK" +} diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideOverriden.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideOverriden.kt new file mode 100644 index 00000000000..5bf9d302cdc --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideOverriden.kt @@ -0,0 +1,45 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM_IR +// FULL_JDK +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.* + +var c: Continuation<*>? = null + +suspend fun tx(lambda: () -> T): T = suspendCoroutine { c = it; lambda() } + +object Dummy + +interface Base { + suspend fun generic(): T +} + +open class Derived1: Base { + override suspend fun generic() {} +} + +class Derived2: Derived1() { + override suspend fun generic(): Unit { + tx { Dummy } + } +} +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res: Any? = null + + builder { + val base: Base<*> = Derived2() + res = base.generic() + } + + (c as? Continuation)?.resume(Dummy) + + return if (res != Unit) "$res" else "OK" +} diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unitFunReturnsNonUnitCallSuspend.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/reflection.kt similarity index 100% rename from compiler/testData/codegen/box/coroutines/tailCallOptimizations/unitFunReturnsNonUnitCallSuspend.kt rename to compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/reflection.kt diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unitFunReturnsNonUnit.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/simple.kt similarity index 100% rename from compiler/testData/codegen/box/coroutines/tailCallOptimizations/unitFunReturnsNonUnit.kt rename to compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/simple.kt diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 3bdfa9f0713..1eb5937c45b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -8549,16 +8549,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt", "kotlin.coroutines"); } - @TestMetadata("unitFunReturnsNonUnit.kt") - public void testUnitFunReturnsNonUnit() throws Exception { - runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unitFunReturnsNonUnit.kt"); - } - - @TestMetadata("unitFunReturnsNonUnitCallSuspend.kt") - public void testUnitFunReturnsNonUnitCallSuspend() throws Exception { - runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unitFunReturnsNonUnitCallSuspend.kt"); - } - @TestMetadata("unreachable.kt") public void testUnreachable() throws Exception { runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unreachable.kt"); @@ -8568,6 +8558,69 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testWhenUnit() throws Exception { runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/whenUnit.kt"); } + + @TestMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Unit extends AbstractBlackBoxCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInUnit() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @TestMetadata("override.kt") + public void testOverride() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override.kt"); + } + + @TestMetadata("override2.kt") + public void testOverride2() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override2.kt"); + } + + @TestMetadata("override3.kt") + public void testOverride3() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override3.kt"); + } + + @TestMetadata("override4.kt") + public void testOverride4() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override4.kt"); + } + + @TestMetadata("override5.kt") + public void testOverride5() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5.kt"); + } + + @TestMetadata("override6.kt") + public void testOverride6() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override6.kt"); + } + + @TestMetadata("overrideCrossinline.kt") + public void testOverrideCrossinline() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideCrossinline.kt"); + } + + @TestMetadata("overrideOverriden.kt") + public void testOverrideOverriden() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideOverriden.kt"); + } + + @TestMetadata("reflection.kt") + public void testReflection() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/reflection.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/simple.kt"); + } + } } @TestMetadata("compiler/testData/codegen/box/coroutines/tailOperations") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 1acd241c1a3..8e30108a1ca 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -8549,16 +8549,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt", "kotlin.coroutines"); } - @TestMetadata("unitFunReturnsNonUnit.kt") - public void testUnitFunReturnsNonUnit() throws Exception { - runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unitFunReturnsNonUnit.kt"); - } - - @TestMetadata("unitFunReturnsNonUnitCallSuspend.kt") - public void testUnitFunReturnsNonUnitCallSuspend() throws Exception { - runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unitFunReturnsNonUnitCallSuspend.kt"); - } - @TestMetadata("unreachable.kt") public void testUnreachable() throws Exception { runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unreachable.kt"); @@ -8568,6 +8558,69 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes public void testWhenUnit() throws Exception { runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/whenUnit.kt"); } + + @TestMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Unit extends AbstractLightAnalysisModeTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInUnit() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @TestMetadata("override.kt") + public void testOverride() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override.kt"); + } + + @TestMetadata("override2.kt") + public void testOverride2() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override2.kt"); + } + + @TestMetadata("override3.kt") + public void testOverride3() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override3.kt"); + } + + @TestMetadata("override4.kt") + public void testOverride4() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override4.kt"); + } + + @TestMetadata("override5.kt") + public void testOverride5() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5.kt"); + } + + @TestMetadata("override6.kt") + public void testOverride6() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override6.kt"); + } + + @TestMetadata("overrideCrossinline.kt") + public void testOverrideCrossinline() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideCrossinline.kt"); + } + + @TestMetadata("overrideOverriden.kt") + public void testOverrideOverriden() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideOverriden.kt"); + } + + @TestMetadata("reflection.kt") + public void testReflection() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/reflection.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/simple.kt"); + } + } } @TestMetadata("compiler/testData/codegen/box/coroutines/tailOperations") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index e56e863a624..b7b622cbf9c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -7454,16 +7454,6 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt", "kotlin.coroutines"); } - @TestMetadata("unitFunReturnsNonUnit.kt") - public void testUnitFunReturnsNonUnit() throws Exception { - runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unitFunReturnsNonUnit.kt"); - } - - @TestMetadata("unitFunReturnsNonUnitCallSuspend.kt") - public void testUnitFunReturnsNonUnitCallSuspend() throws Exception { - runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unitFunReturnsNonUnitCallSuspend.kt"); - } - @TestMetadata("unreachable.kt") public void testUnreachable() throws Exception { runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unreachable.kt"); @@ -7473,6 +7463,69 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT public void testWhenUnit() throws Exception { runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/whenUnit.kt"); } + + @TestMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Unit extends AbstractFirBlackBoxCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTestWithCustomIgnoreDirective(this::doTest, TargetBackend.JVM_IR, testDataFilePath, "// IGNORE_BACKEND_FIR: "); + } + + public void testAllFilesPresentInUnit() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @TestMetadata("override.kt") + public void testOverride() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override.kt"); + } + + @TestMetadata("override2.kt") + public void testOverride2() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override2.kt"); + } + + @TestMetadata("override3.kt") + public void testOverride3() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override3.kt"); + } + + @TestMetadata("override4.kt") + public void testOverride4() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override4.kt"); + } + + @TestMetadata("override5.kt") + public void testOverride5() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5.kt"); + } + + @TestMetadata("override6.kt") + public void testOverride6() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override6.kt"); + } + + @TestMetadata("overrideCrossinline.kt") + public void testOverrideCrossinline() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideCrossinline.kt"); + } + + @TestMetadata("overrideOverriden.kt") + public void testOverrideOverriden() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideOverriden.kt"); + } + + @TestMetadata("reflection.kt") + public void testReflection() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/reflection.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/simple.kt"); + } + } } @TestMetadata("compiler/testData/codegen/box/coroutines/tailOperations") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index a57844230f7..01ccccacc85 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -7454,16 +7454,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt", "kotlin.coroutines"); } - @TestMetadata("unitFunReturnsNonUnit.kt") - public void testUnitFunReturnsNonUnit() throws Exception { - runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unitFunReturnsNonUnit.kt"); - } - - @TestMetadata("unitFunReturnsNonUnitCallSuspend.kt") - public void testUnitFunReturnsNonUnitCallSuspend() throws Exception { - runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unitFunReturnsNonUnitCallSuspend.kt"); - } - @TestMetadata("unreachable.kt") public void testUnreachable() throws Exception { runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unreachable.kt"); @@ -7473,6 +7463,69 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes public void testWhenUnit() throws Exception { runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/whenUnit.kt"); } + + @TestMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Unit extends AbstractIrBlackBoxCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); + } + + public void testAllFilesPresentInUnit() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @TestMetadata("override.kt") + public void testOverride() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override.kt"); + } + + @TestMetadata("override2.kt") + public void testOverride2() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override2.kt"); + } + + @TestMetadata("override3.kt") + public void testOverride3() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override3.kt"); + } + + @TestMetadata("override4.kt") + public void testOverride4() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override4.kt"); + } + + @TestMetadata("override5.kt") + public void testOverride5() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5.kt"); + } + + @TestMetadata("override6.kt") + public void testOverride6() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override6.kt"); + } + + @TestMetadata("overrideCrossinline.kt") + public void testOverrideCrossinline() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideCrossinline.kt"); + } + + @TestMetadata("overrideOverriden.kt") + public void testOverrideOverriden() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideOverriden.kt"); + } + + @TestMetadata("reflection.kt") + public void testReflection() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/reflection.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/simple.kt"); + } + } } @TestMetadata("compiler/testData/codegen/box/coroutines/tailOperations") diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index ffb5b980992..d2cbabfbf1b 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -6383,6 +6383,19 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { public void testTryCatch_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt", "kotlin.coroutines"); } + + @TestMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Unit extends AbstractIrJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath); + } + + public void testAllFilesPresentInUnit() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); + } + } } @TestMetadata("compiler/testData/codegen/box/coroutines/tailOperations") diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 1b619afbd01..66575d9f10a 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -7403,6 +7403,19 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { public void testTryCatch_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt", "kotlin.coroutines"); } + + @TestMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Unit extends AbstractJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath); + } + + public void testAllFilesPresentInUnit() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); + } + } } @TestMetadata("compiler/testData/codegen/box/coroutines/tailOperations")