[IR] Refactor optimization of eliminating removing extra boxes

Signed-off-by: Evgeniy.Zhelenskiy <Evgeniy.Zhelenskiy@jetbrains.com>

#KT-1179
This commit is contained in:
Evgeniy.Zhelenskiy
2022-10-20 03:06:42 +02:00
committed by Space Team
parent f2d98eac5e
commit 1660dc21b9
6 changed files with 57 additions and 42 deletions
@@ -697,7 +697,7 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
irCastIfNeeded(irGet(bridgeParameter), targetParameterType), irCastIfNeeded(irGet(bridgeParameter), targetParameterType),
getOptimizedPublicAccess(target, targetRemappedParameter.rootMfvcNode.mfvc) getOptimizedPublicAccess(target, targetRemappedParameter.rootMfvcNode.mfvc)
) { error("Not applicable") } ) { error("Not applicable") }
val newArguments = instance.makeFlattenedGetterExpressions(this) val newArguments = instance.makeFlattenedGetterExpressions(this, registerPossibleExtraBoxCreation = {})
for (newArgument in newArguments) { for (newArgument in newArguments) {
irCall.putArgument(targetExplicitParameters[targetIndex++], newArgument) irCall.putArgument(targetExplicitParameters[targetIndex++], newArgument)
} }
@@ -712,7 +712,7 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
irGet(bridgeExplicitParameters[bridgeIndex++]) irGet(bridgeExplicitParameters[bridgeIndex++])
} }
val boxCall = bridgeRemappedParameter.rootMfvcNode.makeBoxedExpression( val boxCall = bridgeRemappedParameter.rootMfvcNode.makeBoxedExpression(
this, bridgeRemappedParameter.typeArguments, valueArguments this, bridgeRemappedParameter.typeArguments, valueArguments, registerPossibleExtraBoxCreation = {}
) )
irCall.putArgument(targetParameter, irCastIfNeeded(boxCall, targetParameter.type.upperBound)) irCall.putArgument(targetParameter, irCastIfNeeded(boxCall, targetParameter.type.upperBound))
} }
@@ -140,7 +140,7 @@ private class InheritedDefaultMethodsOnClassesLowering(val context: JvmBackendCo
irGet(sourceFullValueParameterList[flattenedIndex++]) irGet(sourceFullValueParameterList[flattenedIndex++])
} }
val boxedExpression = remappedParameter.rootMfvcNode.makeBoxedExpression( val boxedExpression = remappedParameter.rootMfvcNode.makeBoxedExpression(
this@irBlockBody, remappedParameter.typeArguments, valueArguments this@irBlockBody, remappedParameter.typeArguments, valueArguments, registerPossibleExtraBoxCreation = {}
) )
putValueArgument(i, boxedExpression) putValueArgument(i, boxedExpression)
} }
@@ -61,7 +61,14 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
} }
} }
private val boxUsageGenerated = mutableSetOf<IrDeclaration>() private val possibleExtraBoxUsageGenerated = mutableSetOf<IrDeclaration>()
private val irCurrentScope
get() = currentScope!!.irElement as IrDeclaration
private fun registerPossibleExtraBoxUsage() {
possibleExtraBoxUsageGenerated.add(irCurrentScope)
}
/** /**
* The class is used to get replacing expression and MFVC instance if present for the given old value declaration. * The class is used to get replacing expression and MFVC instance if present for the given old value declaration.
@@ -89,15 +96,11 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
fun IrBuilderWithScope.makeReplacement(expression: IrGetValue): IrExpression? { fun IrBuilderWithScope.makeReplacement(expression: IrGetValue): IrExpression? {
oldValueSymbol2NewValueSymbol[expression.symbol]?.let { return irGet(it.owner) } oldValueSymbol2NewValueSymbol[expression.symbol]?.let { return irGet(it.owner) }
val instance = oldSymbol2MfvcNodeInstance[expression.symbol] ?: return null val instance = oldSymbol2MfvcNodeInstance[expression.symbol] ?: return null
val res = instance.makeGetterExpression(this) val res = instance.makeGetterExpression(this, ::registerPossibleExtraBoxUsage)
boxUsageGenerated.add(irCurrentScope)
expression2MfvcNodeInstanceAccessor[res] = MfvcNodeInstanceAccessor.Getter(instance) expression2MfvcNodeInstanceAccessor[res] = MfvcNodeInstanceAccessor.Getter(instance)
return res return res
} }
private val irCurrentScope
get() = currentScope!!.irElement as IrDeclaration
private fun splitExpressions(expressions: List<IrExpression>): Pair<List<IrExpression>, List<IrExpression>> { private fun splitExpressions(expressions: List<IrExpression>): Pair<List<IrExpression>, List<IrExpression>> {
val repeatable = expressions.takeLastWhile { it.isRepeatableGetter() } val repeatable = expressions.takeLastWhile { it.isRepeatableGetter() }
return expressions.subList(0, expressions.size - repeatable.size) to repeatable return expressions.subList(0, expressions.size - repeatable.size) to repeatable
@@ -141,8 +144,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
val typeArguments = makeTypeArgumentsFromField(expression) val typeArguments = makeTypeArgumentsFromField(expression)
val instance: ReceiverBasedMfvcNodeInstance = val instance: ReceiverBasedMfvcNodeInstance =
node.createInstanceFromBox(this, typeArguments, expression.receiver, AccessType.AlwaysPrivate, ::variablesSaver) node.createInstanceFromBox(this, typeArguments, expression.receiver, AccessType.AlwaysPrivate, ::variablesSaver)
val getterExpression = instance.makeGetterExpression(this) val getterExpression = instance.makeGetterExpression(this, ::registerPossibleExtraBoxUsage)
boxUsageGenerated.add(irCurrentScope)
expression2MfvcNodeInstanceAccessor[getterExpression] = MfvcNodeInstanceAccessor.Getter(instance) expression2MfvcNodeInstanceAccessor[getterExpression] = MfvcNodeInstanceAccessor.Getter(instance)
+getterExpression +getterExpression
return getterExpression return getterExpression
@@ -177,8 +179,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
} }
val instance: ReceiverBasedMfvcNodeInstance = val instance: ReceiverBasedMfvcNodeInstance =
node.createInstanceFromBox(this, typeArguments, dispatchReceiver, accessType, ::variablesSaver) node.createInstanceFromBox(this, typeArguments, dispatchReceiver, accessType, ::variablesSaver)
val getterExpression = instance.makeGetterExpression(this) val getterExpression = instance.makeGetterExpression(this, ::registerPossibleExtraBoxUsage)
boxUsageGenerated.add(irCurrentScope)
expression2MfvcNodeInstanceAccessor[getterExpression] = MfvcNodeInstanceAccessor.Getter(instance) expression2MfvcNodeInstanceAccessor[getterExpression] = MfvcNodeInstanceAccessor.Getter(instance)
+getterExpression +getterExpression
return getterExpression return getterExpression
@@ -227,9 +228,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
val newAccessor = accessor[name] ?: return@handleSavedExpression null val newAccessor = accessor[name] ?: return@handleSavedExpression null
val expression = when (newAccessor) { val expression = when (newAccessor) {
is MfvcNodeInstanceAccessor.Setter -> newAccessor.instance.makeSetterExpressions(scope, newAccessor.values) is MfvcNodeInstanceAccessor.Setter -> newAccessor.instance.makeSetterExpressions(scope, newAccessor.values)
is MfvcNodeInstanceAccessor.Getter -> newAccessor.instance.makeGetterExpression(scope).also { is MfvcNodeInstanceAccessor.Getter -> newAccessor.instance.makeGetterExpression(scope, ::registerPossibleExtraBoxUsage)
boxUsageGenerated.add(irCurrentScope)
}
} }
expression2MfvcNodeInstanceAccessor[expression] = newAccessor expression2MfvcNodeInstanceAccessor[expression] = newAccessor
expression expression
@@ -239,8 +238,9 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
scope: IrBuilderWithScope, scope: IrBuilderWithScope,
expression: IrExpression, expression: IrExpression,
handler: IrBlockBuilder.(values: List<IrExpression>) -> IrExpression handler: IrBlockBuilder.(values: List<IrExpression>) -> IrExpression
): IrExpression? = ): IrExpression? = scope.handleSavedExpression(expression) {
scope.handleSavedExpression(expression) { irBlock { +handler(it.instance.makeFlattenedGetterExpressions(this)) }.unwrapBlock() } irBlock { +handler(it.instance.makeFlattenedGetterExpressions(this, ::registerPossibleExtraBoxUsage)) }.unwrapBlock()
}
fun registerReplacement(expression: IrExpression, instance: MfvcNodeInstance) { fun registerReplacement(expression: IrExpression, instance: MfvcNodeInstance) {
expression2MfvcNodeInstanceAccessor[expression] = MfvcNodeInstanceAccessor.Getter(instance) expression2MfvcNodeInstanceAccessor[expression] = MfvcNodeInstanceAccessor.Getter(instance)
@@ -291,7 +291,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
is IrFunction -> replacingDeclaration.body = replacingDeclaration.body?.makeBodyWithAddedVariables( is IrFunction -> replacingDeclaration.body = replacingDeclaration.body?.makeBodyWithAddedVariables(
context, variablesToAdd[replacingDeclaration] ?: emptySet(), replacingDeclaration.symbol context, variablesToAdd[replacingDeclaration] ?: emptySet(), replacingDeclaration.symbol
)?.apply { )?.apply {
if (replacingDeclaration in boxUsageGenerated) { if (replacingDeclaration in possibleExtraBoxUsageGenerated) {
removeAllExtraBoxes() removeAllExtraBoxes()
} }
} }
@@ -299,7 +299,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
is IrAnonymousInitializer -> replacingDeclaration.body = replacingDeclaration.body.makeBodyWithAddedVariables( is IrAnonymousInitializer -> replacingDeclaration.body = replacingDeclaration.body.makeBodyWithAddedVariables(
context, variablesToAdd[replacingDeclaration.parent] ?: emptySet(), replacingDeclaration.symbol context, variablesToAdd[replacingDeclaration.parent] ?: emptySet(), replacingDeclaration.symbol
).apply { ).apply {
if (replacingDeclaration in boxUsageGenerated) { if (replacingDeclaration in possibleExtraBoxUsageGenerated) {
removeAllExtraBoxes() removeAllExtraBoxes()
} }
} as IrBlockBody } as IrBlockBody
@@ -554,7 +554,10 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
.map { irGet(it) } .map { irGet(it) }
val targetParameter = targetExplicitParameters[flattenedTargetIndex++] val targetParameter = targetExplicitParameters[flattenedTargetIndex++]
val boxedExpression = remappedSourceParameter.rootMfvcNode.makeBoxedExpression( val boxedExpression = remappedSourceParameter.rootMfvcNode.makeBoxedExpression(
this@irBlock, remappedSourceParameter.typeArguments, valueArguments this@irBlock,
remappedSourceParameter.typeArguments,
valueArguments,
::registerPossibleExtraBoxUsage
) )
putArgument(targetParameter, boxedExpression) putArgument(targetParameter, boxedExpression)
.also { flattenedSourceIndex += remappedSourceParameter.valueParameters.size } .also { flattenedSourceIndex += remappedSourceParameter.valueParameters.size }
@@ -569,7 +572,8 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
val instance = rootNode.createInstanceFromBox( val instance = rootNode.createInstanceFromBox(
this@irBlock, irGet(receiver), getOptimizedPublicAccess(rootNode.mfvc), ::variablesSaver, this@irBlock, irGet(receiver), getOptimizedPublicAccess(rootNode.mfvc), ::variablesSaver,
) )
val flattenedExpressions = instance.makeFlattenedGetterExpressions(this@irBlock) val flattenedExpressions =
instance.makeFlattenedGetterExpressions(this@irBlock, ::registerPossibleExtraBoxUsage)
for (expression in flattenedExpressions) { for (expression in flattenedExpressions) {
putArgument(targetExplicitParameters[flattenedTargetIndex++], expression) putArgument(targetExplicitParameters[flattenedTargetIndex++], expression)
} }
@@ -747,8 +751,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
this, function.constructedClassType as IrSimpleType, Name.identifier("constructor_tmp"), ::variablesSaver this, function.constructedClassType as IrSimpleType, Name.identifier("constructor_tmp"), ::variablesSaver
) )
flattenExpressionTo(expression, instance) flattenExpressionTo(expression, instance)
val getterExpression = instance.makeGetterExpression(this) val getterExpression = instance.makeGetterExpression(this, ::registerPossibleExtraBoxUsage)
boxUsageGenerated.add(currentScope)
valueDeclarationsRemapper.registerReplacement(getterExpression, instance) valueDeclarationsRemapper.registerReplacement(getterExpression, instance)
+getterExpression +getterExpression
} }
@@ -1117,7 +1120,9 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
} }
+irCall(rootNode.primaryConstructorImpl).apply { +irCall(rootNode.primaryConstructorImpl).apply {
copyTypeArgumentsFrom(expression) copyTypeArgumentsFrom(expression)
for ((index, leafExpression) in instance.makeFlattenedGetterExpressions(this@flattenExpressionTo).withIndex()) { val flattenedGetterExpressions =
instance.makeFlattenedGetterExpressions(this@flattenExpressionTo, ::registerPossibleExtraBoxUsage)
for ((index, leafExpression) in flattenedGetterExpressions.withIndex()) {
putValueArgument(index, leafExpression) putValueArgument(index, leafExpression)
} }
} }
@@ -1137,7 +1142,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
this, transformedExpression, getOptimizedPublicAccess(rootNode.mfvc), ::variablesSaver, this, transformedExpression, getOptimizedPublicAccess(rootNode.mfvc), ::variablesSaver,
) )
require(expressionInstance.size == instance.size) { "Incompatible assignment sizes: ${expressionInstance.size}, ${instance.size}" } require(expressionInstance.size == instance.size) { "Incompatible assignment sizes: ${expressionInstance.size}, ${instance.size}" }
instance.addSetterStatements(this, expressionInstance.makeFlattenedGetterExpressions(this)) instance.addSetterStatements(this, expressionInstance.makeFlattenedGetterExpressions(this, ::registerPossibleExtraBoxUsage))
} }
private fun getOptimizedPublicAccess(parent: IrClass): AccessType = private fun getOptimizedPublicAccess(parent: IrClass): AccessType =
@@ -142,7 +142,10 @@ sealed interface MfvcNodeWithSubnodes : MfvcNode {
} }
fun MfvcNodeWithSubnodes.makeBoxedExpression( fun MfvcNodeWithSubnodes.makeBoxedExpression(
scope: IrBuilderWithScope, typeArguments: TypeArguments, valueArguments: List<IrExpression> scope: IrBuilderWithScope,
typeArguments: TypeArguments,
valueArguments: List<IrExpression>,
registerPossibleExtraBoxCreation: () -> Unit,
): IrExpression = scope.irCall(boxMethod).apply { ): IrExpression = scope.irCall(boxMethod).apply {
val resultType = type.substitute(typeArguments) as IrSimpleType val resultType = type.substitute(typeArguments) as IrSimpleType
require(resultType.erasedUpperBound == type.erasedUpperBound) { "Substitution of $type led to $resultType" } require(resultType.erasedUpperBound == type.erasedUpperBound) { "Substitution of $type led to $resultType" }
@@ -152,6 +155,7 @@ fun MfvcNodeWithSubnodes.makeBoxedExpression(
for ((index, valueArgument) in valueArguments.withIndex()) { for ((index, valueArgument) in valueArguments.withIndex()) {
putValueArgument(index, valueArgument) putValueArgument(index, valueArgument)
} }
registerPossibleExtraBoxCreation()
} }
operator fun MfvcNodeWithSubnodes.get(names: List<Name>): MfvcNode? { operator fun MfvcNodeWithSubnodes.get(names: List<Name>): MfvcNode? {
@@ -234,7 +234,7 @@ fun createIntermediateMfvcNode(
) { receiver -> ) { receiver ->
val valueArguments = subnodes.flatMap { it.fields!! } val valueArguments = subnodes.flatMap { it.fields!! }
.map { field -> irGetField(if (field.isStatic) null else irGet(receiver!!), field) } .map { field -> irGetField(if (field.isStatic) null else irGet(receiver!!), field) }
rootNode.makeBoxedExpression(this, typeArguments, valueArguments) rootNode.makeBoxedExpression(this, typeArguments, valueArguments, registerPossibleExtraBoxCreation = {})
} }
val hasPureUnboxMethod = defaultMethodsImplementationSourceNode.isPure() && subnodes.all { it.hasPureUnboxMethod } val hasPureUnboxMethod = defaultMethodsImplementationSourceNode.isPure() && subnodes.all { it.hasPureUnboxMethod }
@@ -23,8 +23,8 @@ interface MfvcNodeInstance {
val typeArguments: TypeArguments val typeArguments: TypeArguments
val type: IrSimpleType val type: IrSimpleType
fun makeFlattenedGetterExpressions(scope: IrBlockBuilder): List<IrExpression> fun makeFlattenedGetterExpressions(scope: IrBlockBuilder, registerPossibleExtraBoxCreation: () -> Unit): List<IrExpression>
fun makeGetterExpression(scope: IrBuilderWithScope): IrExpression fun makeGetterExpression(scope: IrBuilderWithScope, registerPossibleExtraBoxCreation: () -> Unit): IrExpression
operator fun get(name: Name): MfvcNodeInstance? operator fun get(name: Name): MfvcNodeInstance?
fun makeStatements(scope: IrBuilderWithScope, values: List<IrExpression>): List<IrStatement> fun makeStatements(scope: IrBuilderWithScope, values: List<IrExpression>): List<IrStatement>
} }
@@ -57,13 +57,16 @@ class ValueDeclarationMfvcNodeInstance(
override val type: IrSimpleType = makeTypeFromMfvcNodeAndTypeArguments(node, typeArguments) override val type: IrSimpleType = makeTypeFromMfvcNodeAndTypeArguments(node, typeArguments)
override fun makeFlattenedGetterExpressions(scope: IrBlockBuilder): List<IrExpression> = override fun makeFlattenedGetterExpressions(scope: IrBlockBuilder, registerPossibleExtraBoxCreation: () -> Unit): List<IrExpression> =
makeFlattenedGetterExpressions(scope as IrBuilderWithScope) makeFlattenedGetterExpressions(scope as IrBuilderWithScope)
private fun makeFlattenedGetterExpressions(scope: IrBuilderWithScope): List<IrExpression> = valueDeclarations.map { scope.irGet(it) } private fun makeFlattenedGetterExpressions(scope: IrBuilderWithScope): List<IrExpression> = valueDeclarations.map { scope.irGet(it) }
override fun makeGetterExpression(scope: IrBuilderWithScope): IrExpression = when (node) { override fun makeGetterExpression(scope: IrBuilderWithScope, registerPossibleExtraBoxCreation: () -> Unit): IrExpression = when (node) {
is LeafMfvcNode -> makeFlattenedGetterExpressions(scope).single() is LeafMfvcNode -> makeFlattenedGetterExpressions(scope).single()
is MfvcNodeWithSubnodes -> node.makeBoxedExpression(scope, typeArguments, makeFlattenedGetterExpressions(scope)) is MfvcNodeWithSubnodes -> node.makeBoxedExpression(
scope, typeArguments, makeFlattenedGetterExpressions(scope), registerPossibleExtraBoxCreation
)
} }
override fun get(name: Name): ValueDeclarationMfvcNodeInstance? { override fun get(name: Name): ValueDeclarationMfvcNodeInstance? {
@@ -158,19 +161,21 @@ class ReceiverBasedMfvcNodeInstance(
require(node is RootMfvcNode == (unboxMethod == null)) { "Only root node has node getter" } require(node is RootMfvcNode == (unboxMethod == null)) { "Only root node has node getter" }
} }
override fun makeFlattenedGetterExpressions(scope: IrBlockBuilder): List<IrExpression> = when (node) { override fun makeFlattenedGetterExpressions(
is LeafMfvcNode -> listOf(makeGetterExpression(scope)) scope: IrBlockBuilder, registerPossibleExtraBoxCreation: () -> Unit
): List<IrExpression> = when (node) {
is LeafMfvcNode -> listOf(makeGetterExpression(scope, registerPossibleExtraBoxCreation))
is MfvcNodeWithSubnodes -> when { is MfvcNodeWithSubnodes -> when {
node is IntermediateMfvcNode && canUsePrivateAccessFor(node) && fields != null -> node is IntermediateMfvcNode && canUsePrivateAccessFor(node) && fields != null ->
fields.map { scope.irGetField(makeReceiverCopy(), it) } fields.map { scope.irGetField(makeReceiverCopy(), it) }
node !is IntermediateMfvcNode || node.hasPureUnboxMethod && (canUsePrivateAccessFor(node) || node.unboxMethod.parentAsClass.isMultiFieldValueClass) -> node !is IntermediateMfvcNode || node.hasPureUnboxMethod && (canUsePrivateAccessFor(node) || node.unboxMethod.parentAsClass.isMultiFieldValueClass) ->
// We cannot relay on purity of non-mfvc class getter because the incremental compiler will not recompile the code // We cannot rely on purity of non-mfvc class getter because the incremental compiler will not recompile the code
// that relayed after the change of purity if it is not local for the class. // that relayed after the change of purity if it is not local for the class.
node.subnodes.flatMap { get(it.name)!!.makeFlattenedGetterExpressions(scope) } node.subnodes.flatMap { get(it.name)!!.makeFlattenedGetterExpressions(scope, registerPossibleExtraBoxCreation) }
else -> { else -> {
val value = makeGetterExpression(scope) val value = makeGetterExpression(scope, registerPossibleExtraBoxCreation = { /* The box is definitely useful */ })
val asVariable = scope.savableStandaloneVariableWithSetter( val asVariable = scope.savableStandaloneVariableWithSetter(
value, value,
origin = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_PARAMETER, origin = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_PARAMETER,
@@ -180,16 +185,17 @@ class ReceiverBasedMfvcNodeInstance(
val root = node.rootNode val root = node.rootNode
val variableInstance = val variableInstance =
root.createInstanceFromBox(scope, typeArguments, scope.irGet(asVariable), accessType, saveVariable) root.createInstanceFromBox(scope, typeArguments, scope.irGet(asVariable), accessType, saveVariable)
variableInstance.makeFlattenedGetterExpressions(scope) variableInstance.makeFlattenedGetterExpressions(scope, registerPossibleExtraBoxCreation)
} }
} }
} }
override fun makeGetterExpression(scope: IrBuilderWithScope): IrExpression = with(scope) { override fun makeGetterExpression(scope: IrBuilderWithScope, registerPossibleExtraBoxCreation: () -> Unit): IrExpression = with(scope) {
when { when {
node is LeafMfvcNode && canUsePrivateAccessFor(node) && fields != null -> irGetField(makeReceiverCopy(), fields.single()) node is LeafMfvcNode && canUsePrivateAccessFor(node) && fields != null -> irGetField(makeReceiverCopy(), fields.single())
node is IntermediateMfvcNode && accessType == AccessType.AlwaysPrivate && fields != null -> node is IntermediateMfvcNode && accessType == AccessType.AlwaysPrivate && fields != null -> node.makeBoxedExpression(
node.makeBoxedExpression(this, typeArguments, fields.map { irGetField(makeReceiverCopy(), it) }) this, typeArguments, fields.map { irGetField(makeReceiverCopy(), it) }, registerPossibleExtraBoxCreation
)
unboxMethod != null -> irCall(unboxMethod).apply { unboxMethod != null -> irCall(unboxMethod).apply {
val dispatchReceiverParameter = unboxMethod.dispatchReceiverParameter val dispatchReceiverParameter = unboxMethod.dispatchReceiverParameter