Disable tail-call optimization for suspend functions with Unit return type

if it overrides functions with another return type.
Otherwise, we cannot determine on call site that the function returns Unit
and cannot { POP, PUSH Unit } in order to avoid the situation when callee's
continuation resumes with non-unit result. The observed behavior is that
suspend function, which should return Unit, suddenly returns other value.
 #KT-35262: Fixed
This commit is contained in:
Ilmir Usmanov
2019-12-04 16:51:59 +03:00
parent 09acdb655d
commit b6de3c2fcc
22 changed files with 768 additions and 70 deletions
@@ -475,7 +475,8 @@ class CoroutineCodegenForLambda private constructor(
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization, shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
containingClassInternalName = v.thisName, containingClassInternalName = v.thisName,
isForNamedFunction = false, isForNamedFunction = false,
languageVersionSettings = languageVersionSettings languageVersionSettings = languageVersionSettings,
disableTailCallOptimizationForFunctionReturningUnit = false
) )
return if (forInline) AddEndLabelMethodVisitor( return if (forInline) AddEndLabelMethodVisitor(
MethodNodeCopyingMethodVisitor( MethodNodeCopyingMethodVisitor(
@@ -63,6 +63,10 @@ class CoroutineTransformerMethodVisitor(
// These two are needed to report diagnostics about suspension points inside critical section // These two are needed to report diagnostics about suspension points inside critical section
private val element: KtElement, private val element: KtElement,
private val diagnostics: DiagnosticSink, 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 // It's only matters for named functions, may differ from '!isStatic(access)' in case of DefaultImpls
private val needDispatchReceiver: Boolean = false, private val needDispatchReceiver: Boolean = false,
// May differ from containingClassInternalName in case of DefaultImpls // May differ from containingClassInternalName in case of DefaultImpls
@@ -111,7 +115,8 @@ class CoroutineTransformerMethodVisitor(
val examiner = MethodNodeExaminer( val examiner = MethodNodeExaminer(
languageVersionSettings, languageVersionSettings,
containingClassInternalName, containingClassInternalName,
methodNode methodNode,
disableTailCallOptimizationForFunctionReturningUnit
) )
if (examiner.allSuspensionPointsAreTailCalls(suspensionPoints)) { if (examiner.allSuspensionPointsAreTailCalls(suspensionPoints)) {
examiner.replacePopsBeforeSafeUnitInstancesWithCoroutineSuspendedChecks() examiner.replacePopsBeforeSafeUnitInstancesWithCoroutineSuspendedChecks()
@@ -899,7 +904,8 @@ class CoroutineTransformerMethodVisitor(
private class MethodNodeExaminer( private class MethodNodeExaminer(
val languageVersionSettings: LanguageVersionSettings, val languageVersionSettings: LanguageVersionSettings,
val containingClassInternalName: String, val containingClassInternalName: String,
val methodNode: MethodNode val methodNode: MethodNode,
disableTailCallOptimizationForFunctionReturningUnit: Boolean
) { ) {
private val sourceFrames: Array<Frame<SourceValue>?> = private val sourceFrames: Array<Frame<SourceValue>?> =
MethodTransformer.analyze(containingClassInternalName, methodNode, IgnoringCopyOperationSourceInterpreter()) MethodTransformer.analyze(containingClassInternalName, methodNode, IgnoringCopyOperationSourceInterpreter())
@@ -912,25 +918,27 @@ private class MethodNodeExaminer(
private val meaningfulPredecessorsCache = hashMapOf<AbstractInsnNode, List<AbstractInsnNode>>() private val meaningfulPredecessorsCache = hashMapOf<AbstractInsnNode, List<AbstractInsnNode>>()
init { init {
// retrieve all POP insns if (!disableTailCallOptimizationForFunctionReturningUnit) {
val pops = methodNode.instructions.asSequence().filter { it.opcode == Opcodes.POP } // retrieve all POP insns
// for each of them check that all successors are PUSH Unit val pops = methodNode.instructions.asSequence().filter { it.opcode == Opcodes.POP }
val popsBeforeUnitInstances = pops.map { it to it.meaningfulSuccessors() } // for each of them check that all successors are PUSH Unit
.filter { (_, succs) -> succs.all { it.isUnitInstance() } } val popsBeforeUnitInstances = pops.map { it to it.meaningfulSuccessors() }
.map { it.first }.toList() .filter { (_, succs) -> succs.all { it.isUnitInstance() } }
for (pop in popsBeforeUnitInstances) { .map { it.first }.toList()
val units = pop.meaningfulSuccessors() for (pop in popsBeforeUnitInstances) {
val allUnitsAreSafe = units.all { unit -> val units = pop.meaningfulSuccessors()
// check no other predecessor exists val allUnitsAreSafe = units.all { unit ->
unit.meaningfulPredecessors().all { it in popsBeforeUnitInstances } && // check no other predecessor exists
// check they have only returns among successors unit.meaningfulPredecessors().all { it in popsBeforeUnitInstances } &&
unit.meaningfulSuccessors().all { it.opcode == Opcodes.ARETURN } // 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() }
} }
} }
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature 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.addToStdlib.safeAs
import org.jetbrains.kotlin.utils.sure import org.jetbrains.kotlin.utils.sure
import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.MethodVisitor
@@ -100,10 +101,27 @@ open class SuspendFunctionGenerationStrategy(
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization, shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
needDispatchReceiver = originalSuspendDescriptor.dispatchReceiverParameter != null, needDispatchReceiver = originalSuspendDescriptor.dispatchReceiverParameter != null,
internalNameForDispatchReceiver = containingClassInternalNameOrNull(), internalNameForDispatchReceiver = containingClassInternalNameOrNull(),
languageVersionSettings = languageVersionSettings languageVersionSettings = languageVersionSettings,
disableTailCallOptimizationForFunctionReturningUnit = originalSuspendDescriptor.returnType?.isUnit() == true &&
originalSuspendDescriptor.overriddenDescriptors.isNotEmpty() &&
!originalSuspendDescriptor.allOverriddenFunctionsReturnUnit()
) )
} }
private fun FunctionDescriptor.allOverriddenFunctionsReturnUnit(): Boolean {
val visited = mutableSetOf<FunctionDescriptor>()
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() = private fun containingClassInternalNameOrNull() =
originalSuspendDescriptor.containingDeclaration.safeAs<ClassDescriptor>()?.let(state.typeMapper::mapClass)?.internalName originalSuspendDescriptor.containingDeclaration.safeAs<ClassDescriptor>()?.let(state.typeMapper::mapClass)?.internalName
@@ -17,11 +17,20 @@ import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor 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.psi.KtElement
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin 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.kotlin.utils.addToStdlib.cast
import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.* import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceInterpreter import org.jetbrains.org.objectweb.asm.tree.analysis.SourceInterpreter
@@ -108,7 +117,8 @@ class CoroutineTransformer(
languageVersionSettings = state.languageVersionSettings, languageVersionSettings = state.languageVersionSettings,
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization, shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
containingClassInternalName = classBuilder.thisName, containingClassInternalName = classBuilder.thisName,
isForNamedFunction = false isForNamedFunction = false,
disableTailCallOptimizationForFunctionReturningUnit = false
) )
) )
@@ -137,6 +147,8 @@ class CoroutineTransformer(
ArrayUtil.toStringArray(node.exceptions) 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( val stateMachineBuilder = surroundNoinlineCallsWithMarkers(
node, node,
CoroutineTransformerMethodVisitor( CoroutineTransformerMethodVisitor(
@@ -149,7 +161,8 @@ class CoroutineTransformer(
containingClassInternalName = classBuilder.thisName, containingClassInternalName = classBuilder.thisName,
isForNamedFunction = true, isForNamedFunction = true,
needDispatchReceiver = true, needDispatchReceiver = true,
internalNameForDispatchReceiver = classBuilder.thisName internalNameForDispatchReceiver = classBuilder.thisName,
disableTailCallOptimizationForFunctionReturningUnit = disableTailCallOptimization
) )
) )
@@ -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.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.createType import org.jetbrains.kotlin.ir.types.createType
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection 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.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid 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.serialization.deserialization.descriptors.DescriptorWithContainerSource
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
internal fun generateStateMachineForNamedFunction( internal fun generateStateMachineForNamedFunction(
irFunction: IrFunction, irFunction: IrFunction,
@@ -58,7 +60,7 @@ internal fun generateStateMachineForNamedFunction(
val languageVersionSettings = state.languageVersionSettings val languageVersionSettings = state.languageVersionSettings
assert(languageVersionSettings.isReleaseCoroutines()) { "Experimental coroutines are unsupported in JVM_IR backend" } assert(languageVersionSettings.isReleaseCoroutines()) { "Experimental coroutines are unsupported in JVM_IR backend" }
return CoroutineTransformerMethodVisitor( 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!! }, obtainClassBuilderForCoroutineState = { continuationClassBuilder!! },
element = element, element = element,
diagnostics = state.diagnostics, diagnostics = state.diagnostics,
@@ -69,7 +71,11 @@ internal fun generateStateMachineForNamedFunction(
needDispatchReceiver = irFunction.dispatchReceiverParameter != null needDispatchReceiver = irFunction.dispatchReceiverParameter != null
|| irFunction.origin == JvmLoweredDeclarationOrigin.SUSPEND_IMPL_STATIC_FUNCTION, || irFunction.origin == JvmLoweredDeclarationOrigin.SUSPEND_IMPL_STATIC_FUNCTION,
internalNameForDispatchReceiver = classCodegen.visitor.thisName, 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 val languageVersionSettings = state.languageVersionSettings
assert(languageVersionSettings.isReleaseCoroutines()) { "Experimental coroutines are unsupported in JVM_IR backend" } assert(languageVersionSettings.isReleaseCoroutines()) { "Experimental coroutines are unsupported in JVM_IR backend" }
return CoroutineTransformerMethodVisitor( 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 }, obtainClassBuilderForCoroutineState = { classCodegen.visitor },
element = element, element = element,
diagnostics = state.diagnostics, diagnostics = state.diagnostics,
languageVersionSettings = languageVersionSettings, languageVersionSettings = languageVersionSettings,
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization, shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
containingClassInternalName = classCodegen.visitor.thisName, containingClassInternalName = classCodegen.visitor.thisName,
isForNamedFunction = false isForNamedFunction = false,
disableTailCallOptimizationForFunctionReturningUnit = false
) )
} }
@@ -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 <T> tx(lambda: () -> T): T = suspendCoroutine { c = it; lambda() }
object Dummy
interface Base<T> {
suspend fun generic(): T
}
class Derived: Base<Unit> {
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<Dummy>)?.resume(Dummy)
return if (res != Unit) "$res" else "OK"
}
@@ -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 <T> tx(lambda: () -> T): T = suspendCoroutine { c = it; lambda() }
object Dummy
interface Base<T> {
suspend fun generic(): T
}
abstract class Derived1: Base<Unit> {
}
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<Dummy>)?.resume(Dummy)
return if (res != Unit) "$res" else "OK"
}
@@ -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 <T> 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<Dummy>)?.resume(Dummy)
return if (res != Unit) "$res" else "OK"
}
@@ -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<T> {
suspend fun generic(): T
}
inline fun inlineMe(crossinline c: suspend () -> Unit) = object : Base<Unit> {
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"
}
@@ -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<T> {
suspend fun generic(): T
}
inline fun inlineMe(crossinline c: suspend () -> Unit) = object : Base<Unit> {
override suspend fun generic(): Unit {
c();
{}()
}
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
fun box(): String {
builder {
inlineMe { }.generic()
}
return "OK"
}
@@ -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 <init>(): 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 <init>(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 <init>(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 <clinit>(): void
public method <init>(): 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 <init>(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
}
@@ -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<T> {
suspend fun generic(): T
}
inline fun inlineMe(crossinline c: suspend () -> Unit) = object : Base<Unit> {
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"
}
@@ -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 <T> tx(lambda: () -> T): T = suspendCoroutine { c = it; lambda() }
object Dummy
interface Base<T> {
suspend fun callMe(a: IntArray): Unit
suspend fun callMe(s: String): Unit
suspend fun callMe(a: Array<String>): Unit
suspend fun callMe(a: Int): T
}
inline fun inlineMe(crossinline c: suspend () -> Unit): Base<*> {
return object: Base<Unit> {
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<String>) {}
}
}
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<Dummy>)?.resume(Dummy)
return if (res != Unit) "$res" else "OK"
}
@@ -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 <T> tx(lambda: () -> T): T = suspendCoroutine { c = it; lambda() }
object Dummy
interface Base<T> {
suspend fun generic(): T
}
open class Derived1: Base<Unit> {
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<Dummy>)?.resume(Dummy)
return if (res != Unit) "$res" else "OK"
}
@@ -8549,16 +8549,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt", "kotlin.coroutines"); 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") @TestMetadata("unreachable.kt")
public void testUnreachable() throws Exception { public void testUnreachable() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unreachable.kt"); runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unreachable.kt");
@@ -8568,6 +8558,69 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
public void testWhenUnit() throws Exception { public void testWhenUnit() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/whenUnit.kt"); 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") @TestMetadata("compiler/testData/codegen/box/coroutines/tailOperations")
@@ -8549,16 +8549,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt", "kotlin.coroutines"); 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") @TestMetadata("unreachable.kt")
public void testUnreachable() throws Exception { public void testUnreachable() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unreachable.kt"); runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unreachable.kt");
@@ -8568,6 +8558,69 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
public void testWhenUnit() throws Exception { public void testWhenUnit() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/whenUnit.kt"); 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") @TestMetadata("compiler/testData/codegen/box/coroutines/tailOperations")
@@ -7454,16 +7454,6 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt", "kotlin.coroutines"); 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") @TestMetadata("unreachable.kt")
public void testUnreachable() throws Exception { public void testUnreachable() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unreachable.kt"); runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unreachable.kt");
@@ -7473,6 +7463,69 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
public void testWhenUnit() throws Exception { public void testWhenUnit() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/whenUnit.kt"); 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") @TestMetadata("compiler/testData/codegen/box/coroutines/tailOperations")
@@ -7454,16 +7454,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt", "kotlin.coroutines"); 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") @TestMetadata("unreachable.kt")
public void testUnreachable() throws Exception { public void testUnreachable() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unreachable.kt"); runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unreachable.kt");
@@ -7473,6 +7463,69 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
public void testWhenUnit() throws Exception { public void testWhenUnit() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/whenUnit.kt"); 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") @TestMetadata("compiler/testData/codegen/box/coroutines/tailOperations")
@@ -6383,6 +6383,19 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
public void testTryCatch_1_3() throws Exception { public void testTryCatch_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt", "kotlin.coroutines"); 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") @TestMetadata("compiler/testData/codegen/box/coroutines/tailOperations")
@@ -7403,6 +7403,19 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
public void testTryCatch_1_3() throws Exception { public void testTryCatch_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt", "kotlin.coroutines"); 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") @TestMetadata("compiler/testData/codegen/box/coroutines/tailOperations")