JVM_IR: improve suspend tail call detection.
* TailCallOptimizationLowering should go into local classes in order to transform their suspend methods; * the check for invokes of noinline lambda arguments in codegen was incorrect, as it also returned true for calls of lambdas stored in local variables; * IrInlineCodegen should mark non-inlinable arguments used as inline suspend parameters; * detection of suspend/inline call sites was incorrect (or maybe it's the `compilationContextDescriptor` that was incorrect?..)
This commit is contained in:
@@ -117,7 +117,6 @@ class JvmBackendContext(
|
||||
val continuationClassBuilders = mutableMapOf<IrSimpleFunction, ClassBuilder>()
|
||||
val suspendFunctionOriginalToView = mutableMapOf<IrFunction, IrFunction>()
|
||||
val suspendFunctionOriginalToStub = mutableMapOf<IrFunction, IrFunction>()
|
||||
val suspendTailCallsWithUnitReplacement = mutableSetOf<IrAttributeContainer>()
|
||||
val fakeContinuation: IrExpression = createFakeContinuation(this)
|
||||
|
||||
val staticDefaultStubs = mutableMapOf<IrFunctionSymbol, IrFunction>()
|
||||
|
||||
+16
-29
@@ -476,28 +476,22 @@ class ExpressionCodegen(
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunctionAccessExpression.isSuspensionPoint(): Boolean {
|
||||
val owner = symbol.owner
|
||||
return when {
|
||||
// Only suspend functions are suspension points
|
||||
!owner.isSuspend -> false
|
||||
// But not inside continuation classes and bridges
|
||||
irFunction.shouldNotContainSuspendMarkers() -> false
|
||||
// Noinline function are always suspension points
|
||||
!owner.isInline -> true
|
||||
// The suspend intrinsics are, albeit inline, also suspension points
|
||||
owner.fqNameForIrSerialization == FqName("kotlin.coroutines.intrinsics.IntrinsicsKt.suspendCoroutineUninterceptedOrReturn") -> true
|
||||
// Inside $$forInline functions crossinline calls are (usually) not suspension points, otherwise, flow will be pessimized
|
||||
(dispatchReceiver as? IrGetField)?.symbol?.owner?.origin ==
|
||||
LocalDeclarationsLowering.DECLARATION_ORIGIN_FIELD_FOR_CROSSINLINE_CAPTURED_VALUE ->
|
||||
irFunction.origin != FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE
|
||||
// The same goes for inline lambdas
|
||||
(dispatchReceiver as? IrGetValue)?.let {
|
||||
it.origin == IrStatementOrigin.VARIABLE_AS_FUNCTION && (it.symbol.owner as? IrValueParameter)?.isNoinline != true
|
||||
} == true -> irFunction.origin != FOR_INLINE_STATE_MACHINE_TEMPLATE
|
||||
// Otherwise, this is normal inline call, ergo not a suspension point
|
||||
else -> false
|
||||
}
|
||||
private fun IrFunctionAccessExpression.isInvokeOfInlineLambda(): Boolean = when (val receiver = dispatchReceiver) {
|
||||
is IrGetField -> receiver.symbol.owner.origin == LocalDeclarationsLowering.DECLARATION_ORIGIN_FIELD_FOR_CROSSINLINE_CAPTURED_VALUE
|
||||
is IrGetValue -> receiver.origin == IrStatementOrigin.VARIABLE_AS_FUNCTION &&
|
||||
(receiver.symbol.owner as? IrValueParameter)?.isNoinline == false
|
||||
else -> false
|
||||
}
|
||||
|
||||
private fun IrFunctionAccessExpression.isSuspensionPoint(): Boolean = when {
|
||||
!symbol.owner.isSuspend || irFunction.shouldNotContainSuspendMarkers() -> false
|
||||
// Copy-pasted bytecode blocks are not suspension points.
|
||||
symbol.owner.isInline ->
|
||||
symbol.owner.fqNameForIrSerialization == FqName("kotlin.coroutines.intrinsics.IntrinsicsKt.suspendCoroutineUninterceptedOrReturn")
|
||||
// This includes inline lambdas, but only in functions intended for the inliner; in others, they stay as `f.invoke()`.
|
||||
isInvokeOfInlineLambda() ->
|
||||
irFunction.origin != FOR_INLINE_STATE_MACHINE_TEMPLATE && irFunction.origin != FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE
|
||||
else -> true
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable, data: BlockInfo): PromisedValue {
|
||||
@@ -661,13 +655,6 @@ class ExpressionCodegen(
|
||||
val returnType = if (owner == irFunction) signature.returnType else methodSignatureMapper.mapReturnType(owner)
|
||||
val afterReturnLabel = Label()
|
||||
expression.value.accept(this, data).coerce(returnType, owner.returnType).materialize()
|
||||
// We replaced COERTION_TO_UNIT with IrReturn during TailCallOptimizationLowering.
|
||||
// Generate POP GETSTATIC kotlin/Unit.INSTANCE now.
|
||||
// Otherwise, tail-call optimization will not work. See tailSuspendUnitFun.kt test.
|
||||
if (expression in context.suspendTailCallsWithUnitReplacement) {
|
||||
mv.pop()
|
||||
mv.getstatic("kotlin/Unit", "INSTANCE", "Lkotlin/Unit;")
|
||||
}
|
||||
generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data)
|
||||
expression.markLineNumber(startOffset = true)
|
||||
if (isNonLocalReturn) {
|
||||
|
||||
+13
-18
@@ -22,11 +22,7 @@ import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.toKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.ir.util.getArgumentsWithIr
|
||||
import org.jetbrains.kotlin.ir.util.isSuspend
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
@@ -87,11 +83,9 @@ class IrInlineCodegen(
|
||||
super.genValueAndPut(irValueParameter, argumentExpression, parameterType, codegen, blockInfo)
|
||||
}
|
||||
|
||||
if (irValueParameter.isInlineParameter(
|
||||
/*after transformation inlinable lambda parameter with default value would have nullable type: check default value type first*/
|
||||
irValueParameter.defaultValue?.expression?.type ?: irValueParameter.type
|
||||
) && isInlineIrExpression(argumentExpression)
|
||||
) {
|
||||
// after transformation inlinable lambda parameter with default value would have nullable type: check default value type first
|
||||
val isInlineParameter = irValueParameter.isInlineParameter(irValueParameter.defaultValue?.expression?.type ?: irValueParameter.type)
|
||||
if (isInlineParameter && isInlineIrExpression(argumentExpression)) {
|
||||
val irReference: IrFunctionReference =
|
||||
(argumentExpression as IrBlock).statements.filterIsInstance<IrFunctionReference>().single()
|
||||
val boundReceiver = argumentExpression.statements.filterIsInstance<IrVariable>().singleOrNull()
|
||||
@@ -107,9 +101,14 @@ class IrInlineCodegen(
|
||||
val kind = when (irValueParameter.origin) {
|
||||
IrDeclarationOrigin.MASK_FOR_DEFAULT_FUNCTION -> ValueKind.DEFAULT_MASK
|
||||
IrDeclarationOrigin.METHOD_HANDLER_IN_DEFAULT_FUNCTION -> ValueKind.METHOD_HANDLE_IN_DEFAULT
|
||||
else -> if (argumentExpression is IrContainerExpression && argumentExpression.origin == IrStatementOrigin.DEFAULT_VALUE)
|
||||
ValueKind.DEFAULT_PARAMETER
|
||||
else ValueKind.CAPTURED
|
||||
else -> when {
|
||||
argumentExpression is IrContainerExpression && argumentExpression.origin == IrStatementOrigin.DEFAULT_VALUE ->
|
||||
ValueKind.DEFAULT_PARAMETER
|
||||
// TODO ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND?
|
||||
isInlineParameter && irValueParameter.type.isSuspendFunctionTypeOrSubtype() ->
|
||||
ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER
|
||||
else -> ValueKind.GENERAL
|
||||
}
|
||||
}
|
||||
|
||||
val onStack = when {
|
||||
@@ -130,11 +129,7 @@ class IrInlineCodegen(
|
||||
|
||||
|
||||
//TODO support default argument erasure
|
||||
if (!processDefaultMaskOrMethodHandler(
|
||||
onStack,
|
||||
kind
|
||||
)
|
||||
) {
|
||||
if (!processDefaultMaskOrMethodHandler(onStack, kind)) {
|
||||
val expectedType = JvmKotlinType(parameterType, irValueParameter.type.toKotlinType())
|
||||
putArgumentOrCapturedToLocalVal(expectedType, onStack, -1, irValueParameter.index, kind)
|
||||
}
|
||||
|
||||
+2
-2
@@ -89,8 +89,8 @@ class IrSourceCompilerForInline(
|
||||
root.classCodegen.type.internalName,
|
||||
root.signature.asmMethod.name,
|
||||
root.signature.asmMethod.descriptor,
|
||||
compilationContextFunctionDescriptor.isInlineOrInsideInline(),
|
||||
compilationContextFunctionDescriptor.isSuspend,
|
||||
root.irFunction.descriptor.isInlineOrInsideInline(),
|
||||
root.irFunction.isSuspend,
|
||||
findElement()?.let { CodegenUtil.getLineNumberForElement(it, false) } ?: 0
|
||||
)
|
||||
}
|
||||
|
||||
+51
-66
@@ -11,21 +11,18 @@ import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.anyOfOverriddenFunctionsReturnsNonUnit
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.isKnownToBeTailCall
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
|
||||
import org.jetbrains.kotlin.ir.types.isUnit
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.util.isSuspend
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
@@ -35,72 +32,60 @@ internal val tailCallOptimizationPhase = makeIrFilePhase(
|
||||
"Add or move returns to suspension points on tail-call positions"
|
||||
)
|
||||
|
||||
// TODO: Make this lowering common
|
||||
private class TailCallOptimizationLowering(private val context: JvmBackendContext) : IrElementVisitorVoid, FileLoweringPass {
|
||||
// Find all tail-calls inside suspend function. We should add IrReturn before them, so the codegen will generate
|
||||
// code which is understandable by old BE's tail-call optimizer.
|
||||
private class TailCallOptimizationLowering(private val context: JvmBackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
visitFile(irFile)
|
||||
}
|
||||
irFile.transformChildren(object : IrElementTransformer<TailCallOptimizationData?> {
|
||||
override fun visitFunction(declaration: IrFunction, data: TailCallOptimizationData?) =
|
||||
super.visitFunction(declaration, TailCallOptimizationData(declaration))
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitFunction(function: IrFunction) {
|
||||
if (!function.isSuspend || function.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA || function.isKnownToBeTailCall()) return
|
||||
// Disable tail-call optimization for functions, returning Unit and overriding function, returning non-unit.
|
||||
if (function.returnType.isUnit() && function.anyOfOverriddenFunctionsReturnsNonUnit()) return
|
||||
|
||||
val tailCalls = mutableSetOf<IrCall>()
|
||||
|
||||
// Find all tail-calls inside suspend function.
|
||||
// We should add IrReturn before them, so the codegen will generate code, which is understandable by old BE's tail-call optimizer.
|
||||
// This function collect all possible tail-calls, if they are not prepended by IrReturns, so we can prepend them.
|
||||
// If the call has IrReturn before it, we do not need to add another one.
|
||||
// If the call is inside a branch of `when` statement (or `if`, which is lowered to `when`), go through the branches and
|
||||
// find tail-calls there.
|
||||
fun findCallsOnTailPositionWithoutImmediateReturn(statement: IrStatement, immediateReturn: Boolean = false) {
|
||||
when (statement) {
|
||||
is IrCall -> if (statement.isSuspend && !immediateReturn) {
|
||||
tailCalls += statement
|
||||
}
|
||||
is IrBlock -> findCallsOnTailPositionWithoutImmediateReturn(
|
||||
statement.statements.findTailCall(function.returnType.isUnit()) ?: return
|
||||
override fun visitCall(expression: IrCall, data: TailCallOptimizationData?): IrExpression {
|
||||
val transformed = super.visitCall(expression, data) as IrExpression
|
||||
return if (data == null || expression !in data.tailCalls) transformed else IrReturnImpl(
|
||||
expression.startOffset, expression.endOffset, context.irBuiltIns.nothingType, data.function.symbol,
|
||||
if (data.returnsUnit) transformed.coerceToUnit() else transformed
|
||||
)
|
||||
is IrWhen -> for (branch in statement.branches) {
|
||||
findCallsOnTailPositionWithoutImmediateReturn(branch.result)
|
||||
}
|
||||
is IrReturn -> findCallsOnTailPositionWithoutImmediateReturn(statement.value, immediateReturn = true)
|
||||
is IrTypeOperatorCall -> if (statement.operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT) {
|
||||
findCallsOnTailPositionWithoutImmediateReturn(statement.argument)
|
||||
}
|
||||
else -> {
|
||||
// Not a call, or something containing a tail-call, break
|
||||
// TODO: Support binary logical operations and elvis, though. KT-23826 and KT-23825
|
||||
}
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
|
||||
private fun IrExpression.coerceToUnit() = IrTypeOperatorCallImpl(
|
||||
startOffset, endOffset, context.irBuiltIns.unitType, IrTypeOperator.IMPLICIT_COERCION_TO_UNIT, context.irBuiltIns.unitType, this
|
||||
)
|
||||
}
|
||||
|
||||
private class TailCallOptimizationData(val function: IrFunction) {
|
||||
val returnsUnit = function.returnType.isUnit()
|
||||
val tailCalls = mutableSetOf<IrCall>()
|
||||
|
||||
// Collect all tail calls, including those nested in `when`s, which are not arguments to `return`s.
|
||||
private fun findCallsOnTailPositionWithoutImmediateReturn(statement: IrStatement, immediateReturn: Boolean = false) {
|
||||
when {
|
||||
statement is IrCall && statement.isSuspend && !immediateReturn && (returnsUnit || statement.type == function.returnType) ->
|
||||
tailCalls += statement
|
||||
statement is IrBlock ->
|
||||
statement.statements.findTailCall(returnsUnit)?.let(::findCallsOnTailPositionWithoutImmediateReturn)
|
||||
statement is IrWhen ->
|
||||
statement.branches.forEach { findCallsOnTailPositionWithoutImmediateReturn(it.result) }
|
||||
statement is IrReturn ->
|
||||
findCallsOnTailPositionWithoutImmediateReturn(statement.value, immediateReturn = true)
|
||||
statement is IrTypeOperatorCall && statement.operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT ->
|
||||
findCallsOnTailPositionWithoutImmediateReturn(statement.argument)
|
||||
// TODO: Support binary logical operations and elvis, though. KT-23826 and KT-23825
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
if (function.isSuspend && function.origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA && !function.isKnownToBeTailCall() &&
|
||||
// See `disableTailCallOptimizationForFunctionReturningUnit` in `generateStateMachineForNamedFunction`:
|
||||
!(returnsUnit && function.anyOfOverriddenFunctionsReturnsNonUnit())
|
||||
) {
|
||||
when (val body = function.body) {
|
||||
is IrBlockBody -> body.statements.findTailCall(returnsUnit)?.let(::findCallsOnTailPositionWithoutImmediateReturn)
|
||||
is IrExpressionBody -> findCallsOnTailPositionWithoutImmediateReturn(body.expression)
|
||||
}
|
||||
}
|
||||
|
||||
when (val body = function.body) {
|
||||
null -> return
|
||||
is IrBlockBody -> findCallsOnTailPositionWithoutImmediateReturn(
|
||||
body.statements.findTailCall(function.returnType.isUnit()) ?: return
|
||||
)
|
||||
is IrExpressionBody -> findCallsOnTailPositionWithoutImmediateReturn(body.expression)
|
||||
else -> error("Unexpected $body")
|
||||
}
|
||||
|
||||
function.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitCall(call: IrCall): IrExpression {
|
||||
if (call !in tailCalls) return call
|
||||
if (!function.returnType.isUnit() && call.type != function.returnType) return call
|
||||
// Replace ARETURN with { POP, GETSTATIC kotlin/Unit.INSTANCE, ARETURN } during codegen later.
|
||||
// Otherwise, additional CHECKCAST will break tail-call optimization
|
||||
if (function.returnType.isUnit()) {
|
||||
context.suspendTailCallsWithUnitReplacement += call.attributeOwnerId
|
||||
}
|
||||
return IrReturnImpl(call.startOffset, call.endOffset, context.irBuiltIns.nothingType, function.symbol, call)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-4
@@ -33,7 +33,6 @@ public final class CrossinlineKt$box$1$invokeSuspend$$inlined$filter$1$2 {
|
||||
inner class CrossinlineKt$box$1$invokeSuspend$$inlined$filter$1$2
|
||||
public method <init>(p0: Sink): void
|
||||
public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void
|
||||
public @org.jetbrains.annotations.Nullable method send$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
|
||||
@@ -42,7 +41,6 @@ public final class CrossinlineKt$box$1$invokeSuspend$$inlined$filter$1 {
|
||||
synthetic final field $this$inlined: SourceCrossinline
|
||||
inner class CrossinlineKt$box$1$invokeSuspend$$inlined$filter$1
|
||||
public method <init>(p0: SourceCrossinline): void
|
||||
public @org.jetbrains.annotations.Nullable method consume$$forInline(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public @org.jetbrains.annotations.Nullable method consume(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
|
||||
@@ -66,7 +64,6 @@ public final class CrossinlineKt$box$1$invokeSuspend$$inlined$fold$1 {
|
||||
inner class CrossinlineKt$box$1$invokeSuspend$$inlined$fold$1
|
||||
public method <init>(p0: kotlin.jvm.internal.Ref$ObjectRef): void
|
||||
public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void
|
||||
public @org.jetbrains.annotations.Nullable method send$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
|
||||
@@ -326,7 +323,6 @@ public final class CrossinlineKt$range$$inlined$source$1 {
|
||||
synthetic final field $start$inlined: int
|
||||
inner class CrossinlineKt$range$$inlined$source$1
|
||||
public method <init>(p0: int, p1: int): void
|
||||
public @org.jetbrains.annotations.Nullable method consume$$forInline(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public @org.jetbrains.annotations.Nullable method consume(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
|
||||
|
||||
Vendored
-46
@@ -19,63 +19,25 @@ final class flow/InnerObjectRetransformationKt$box$1 {
|
||||
public final @org.jetbrains.annotations.Nullable method invokeSuspend(@org.jetbrains.annotations.NotNull p0: java.lang.Object): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class flow/InnerObjectRetransformationKt$check$$inlined$collect$1$1 {
|
||||
field label: int
|
||||
@org.jetbrains.annotations.NotNull field result: java.lang.Object
|
||||
synthetic final field this$0: flow.InnerObjectRetransformationKt$check$$inlined$collect$1
|
||||
public method <init>(p0: flow.InnerObjectRetransformationKt$check$$inlined$collect$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 flow/InnerObjectRetransformationKt$check$$inlined$collect$1 {
|
||||
inner class flow/InnerObjectRetransformationKt$check$$inlined$collect$1
|
||||
public method <init>(): void
|
||||
public @org.jetbrains.annotations.Nullable method emit$$forInline(@org.jetbrains.annotations.NotNull p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public @org.jetbrains.annotations.Nullable method emit(@org.jetbrains.annotations.NotNull p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
@kotlin.coroutines.jvm.internal.DebugMetadata
|
||||
final class flow/InnerObjectRetransformationKt$check$$inlined$flow$1$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
field L$2: java.lang.Object
|
||||
field label: int
|
||||
@org.jetbrains.annotations.NotNull field result: java.lang.Object
|
||||
synthetic final field this$0: flow.InnerObjectRetransformationKt$check$$inlined$flow$1
|
||||
public method <init>(p0: flow.InnerObjectRetransformationKt$check$$inlined$flow$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 flow/InnerObjectRetransformationKt$check$$inlined$flow$1 {
|
||||
inner class flow/InnerObjectRetransformationKt$check$$inlined$flow$1
|
||||
public method <init>(): void
|
||||
public @org.jetbrains.annotations.Nullable method collect$$forInline(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public @org.jetbrains.annotations.Nullable method collect(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
@kotlin.coroutines.jvm.internal.DebugMetadata
|
||||
final class flow/InnerObjectRetransformationKt$check$$inlined$flowWith$1$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
field L$2: java.lang.Object
|
||||
field label: int
|
||||
@org.jetbrains.annotations.NotNull field result: java.lang.Object
|
||||
synthetic final field this$0: flow.InnerObjectRetransformationKt$check$$inlined$flowWith$1
|
||||
public method <init>(p0: flow.InnerObjectRetransformationKt$check$$inlined$flowWith$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 flow/InnerObjectRetransformationKt$check$$inlined$flowWith$1 {
|
||||
synthetic final field $this$inlined: flow.Flow
|
||||
inner class flow/InnerObjectRetransformationKt$check$$inlined$flowWith$1
|
||||
public method <init>(p0: flow.Flow): void
|
||||
public @org.jetbrains.annotations.Nullable method collect$$forInline(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public @org.jetbrains.annotations.Nullable method collect(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
|
||||
@@ -134,11 +96,7 @@ public final class flow/InnerObjectRetransformationKt$flow$1 {
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
@kotlin.coroutines.jvm.internal.DebugMetadata
|
||||
final class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$1$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
field L$2: java.lang.Object
|
||||
field label: int
|
||||
@org.jetbrains.annotations.NotNull field result: java.lang.Object
|
||||
synthetic final field this$0: flow.InnerObjectRetransformationKt$flowWith$$inlined$flow$1
|
||||
@@ -157,11 +115,7 @@ public final class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$1 {
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
@kotlin.coroutines.jvm.internal.DebugMetadata
|
||||
final class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$2$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
field L$2: java.lang.Object
|
||||
field label: int
|
||||
@org.jetbrains.annotations.NotNull field result: java.lang.Object
|
||||
synthetic final field this$0: flow.InnerObjectRetransformationKt$flowWith$$inlined$flow$2
|
||||
|
||||
-12
@@ -3,17 +3,6 @@ public interface Base {
|
||||
public abstract @org.jetbrains.annotations.Nullable method generic(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
@kotlin.coroutines.jvm.internal.DebugMetadata
|
||||
final class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1$1 {
|
||||
field L$0: java.lang.Object
|
||||
field label: int
|
||||
@org.jetbrains.annotations.NotNull field result: java.lang.Object
|
||||
synthetic final field this$0: Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1
|
||||
public method <init>(p0: Override5Kt$box$1$invokeSuspend$$inlined$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$box$1$invokeSuspend$$inlined$inlineMe$1$2 {
|
||||
inner class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1
|
||||
@@ -28,7 +17,6 @@ public final class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1 {
|
||||
inner class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1
|
||||
inner class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1$2
|
||||
public method <init>(): 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
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
|
||||
// FILE: test.kt
|
||||
// COMMON_COROUTINES_TEST
|
||||
// WITH_RUNTIME
|
||||
|
||||
Reference in New Issue
Block a user