diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxingInterpreter.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxingInterpreter.kt index c5a994fb779..8fc4e84fc7e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxingInterpreter.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxingInterpreter.kt @@ -69,6 +69,19 @@ open class BoxingInterpreter( return when { insn.isBoxing(generationState) -> { + /* + * It's possible to have chain of several boxings and it's important to retain these boxing methods, consider: + * + * inline class AsAny(val a: Any) + * + * fun takeAny(a: Any) + * + * fun foo() { + * takeAny(AsAny(42)) // valueOf -> AsAny$Erased.box + * } + * + * */ + values.markBoxedArgumentValues() createNewBoxing(insn, value.type, null) } insn.isUnboxing(generationState) && firstArg is BoxedBasicValue -> { @@ -94,16 +107,20 @@ open class BoxingInterpreter( // N-ary operation should be a method call or multinewarray. // Arguments for multinewarray could be only numeric, // so if there are boxed values in args, it's not a case of multinewarray. - for (arg in values) { - if (arg is BoxedBasicValue) { - onMethodCallWithBoxedValue(arg) - } - } + values.markBoxedArgumentValues() value } } } + private fun List.markBoxedArgumentValues() { + for (arg in this) { + if (arg is BoxedBasicValue) { + onMethodCallWithBoxedValue(arg) + } + } + } + override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? { checkUsedValue(value) diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/boxResultInlineClassOfConstructorCall.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/boxResultInlineClassOfConstructorCall.kt index 1da4603dc88..ae6541870e9 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/boxResultInlineClassOfConstructorCall.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/boxResultInlineClassOfConstructorCall.kt @@ -6,11 +6,11 @@ fun test() { val a = Result(1) // valueOf val b = Result("sample") - val c = Result>(a) // box - val d = Result>(Result(1)) // valueOf, box + val c = Result>(a) + val d = Result>(Result(1)) // valueOf } -// 2 INVOKESTATIC Result\$Erased.box +// 0 INVOKESTATIC Result\$Erased.box // 0 INVOKEVIRTUAL Result.unbox // 2 valueOf