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:
@@ -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(
|
||||||
|
|||||||
+28
-20
@@ -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
-1
@@ -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
-4
@@ -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
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+11
-4
@@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+42
@@ -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"
|
||||||
|
}
|
||||||
+44
@@ -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"
|
||||||
|
}
|
||||||
+46
@@ -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"
|
||||||
|
}
|
||||||
+40
@@ -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"
|
||||||
|
}
|
||||||
+35
@@ -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"
|
||||||
|
}
|
||||||
+70
@@ -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
|
||||||
|
}
|
||||||
+38
@@ -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"
|
||||||
|
}
|
||||||
+53
@@ -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"
|
||||||
|
}
|
||||||
+45
@@ -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"
|
||||||
|
}
|
||||||
+63
-10
@@ -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")
|
||||||
|
|||||||
+63
-10
@@ -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")
|
||||||
|
|||||||
+63
-10
@@ -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")
|
||||||
|
|||||||
+63
-10
@@ -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")
|
||||||
|
|||||||
Generated
+13
@@ -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")
|
||||||
|
|||||||
+13
@@ -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")
|
||||||
|
|||||||
Reference in New Issue
Block a user