diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 082a82c6ff4..cf7222d7a82 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2898,6 +2898,18 @@ public class ExpressionCodegen extends KtVisitor impleme KotlinType argumentKotlinType = kotlinType(argumentExpression); if (argument.getSpreadElement() != null) { gen(argumentExpression, OBJECT_TYPE, argumentKotlinType); + + if (argumentKotlinType != null && InlineClassesUtilsKt.isInlineClassType(argumentKotlinType)) { + // we're going to pass value of inline class type to j/l/Object, which would result in boxing and then + // will cause check cast error on toArray() call. To mitigate this problem, we unbox this value and pass + // primitive array to the method. Note that bytecode optimisations will remove box/unbox calls. + StackValue.coerce( + OBJECT_TYPE, argumentKotlinType, + asmType(argumentKotlinType), argumentKotlinType, + v + ); + } + v.invokevirtual(owner, "addSpread", "(Ljava/lang/Object;)V", false); } else { diff --git a/compiler/testData/codegen/box/unsignedTypes/varargsOfUnsignedTypes.kt b/compiler/testData/codegen/box/unsignedTypes/varargsOfUnsignedTypes.kt index b2c93e593c7..33ca0c6e6b4 100644 --- a/compiler/testData/codegen/box/unsignedTypes/varargsOfUnsignedTypes.kt +++ b/compiler/testData/codegen/box/unsignedTypes/varargsOfUnsignedTypes.kt @@ -1,6 +1,7 @@ // !LANGUAGE: +InlineClasses // !SKIP_METADATA_VERSION_CHECK // WITH_UNSIGNED +// IGNORE_BACKEND: JS, JS_IR fun uint(vararg us: UInt): UIntArray = us @@ -15,11 +16,17 @@ fun box(): String { val uints = uint(1u, 2u, 3u) if (sum(*uints) != 6u) return "Fail 1" + val complextUInts = uint(4u, *uints, 5u, *uints, 6u) + if (sum(*complextUInts) != 27u) return "Fail 2" + val nullableUInts = nullableUInt(1u, null, 2u, null) - if (sum(*nullableUInts) != 3u) return "Fail 2" + if (sum(*nullableUInts) != 3u) return "Fail 3" val inlinedUInts = inlinedUInt(1u, 3u) - if (sum(*inlinedUInts) != 4u) return "Fail 3" + if (sum(*inlinedUInts) != 4u) return "Fail 4" + + val complexInlinedUInts = inlinedUInt(*inlinedUInts, 3u, *inlinedUInts) + if (sum(*complexInlinedUInts) != 11u) return "Fail 5" return "OK" } diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/noBoxingOperationsOnNonTrivialSpread.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/noBoxingOperationsOnNonTrivialSpread.kt new file mode 100644 index 00000000000..57136d53e08 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/noBoxingOperationsOnNonTrivialSpread.kt @@ -0,0 +1,27 @@ +// !LANGUAGE: +InlineClasses +// !WITH_UNSIGNED +// !SKIP_METADATA_VERSION_CHECK + +fun uint(vararg us: UInt): UIntArray = us + +// FILE: NoBoxing.kt + +fun test1(us: UIntArray) { + uint(1u, *us, 2u, *us) +} + +// @NoBoxingKt.class: +// 0 INVOKESTATIC kotlin.UInt\$Erased.box +// 0 INVOKEVIRTUAL kotlin.UInt.unbox + +// FILE: Boxing.kt + +fun nullableUInt(vararg us: UInt?) {} + +fun test2(nullable: UInt?, ns: Array) { + nullableUInt(1u, nullable, 3u, *ns) +} + +// @BoxingKt.class: +// 2 INVOKESTATIC kotlin.UInt\$Erased.box +// 0 INVOKEVIRTUAL kotlin.UInt.unbox \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 26dc8fe93e9..f877acd3e18 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -2080,6 +2080,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/inlineClasses/noAssertionsForInlineClassesBasedOnNullableTypes.kt"); } + @TestMetadata("noBoxingOperationsOnNonTrivialSpread.kt") + public void testNoBoxingOperationsOnNonTrivialSpread() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/inlineClasses/noBoxingOperationsOnNonTrivialSpread.kt"); + } + @TestMetadata("passInlineClassesWithSpreadOperatorToVarargs.kt") public void testPassInlineClassesWithSpreadOperatorToVarargs() throws Exception { runTest("compiler/testData/codegen/bytecodeText/inlineClasses/passInlineClassesWithSpreadOperatorToVarargs.kt");