diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt index d2f080d8eb1..3b4e709686a 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt @@ -245,6 +245,7 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC val arrayConcat = getInternalWithoutPackage("arrayConcat") val primitiveArrayConcat = getInternalWithoutPackage("primitiveArrayConcat") + val taggedArrayCopy = getInternalWithoutPackage("taggedArrayCopy") val jsArraySlice = defineJsSliceIntrinsic().symbol diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/VarargLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/VarargLowering.kt index 856c7d34843..36cda0b477a 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/VarargLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/VarargLowering.kt @@ -15,8 +15,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl -import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.classifierOrNull +import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid @@ -139,11 +138,18 @@ private class VarargTransformer( if (segments.size == 1) { val segment = segments.first() val argument = if (expression.elements.any { it is IrSpreadElement }) { + val elementType = arrayInfo.primitiveElementType + val copyFunction = + if (elementType.isChar() || elementType.isBoolean() || elementType.isLong()) + context.intrinsics.taggedArrayCopy + else + context.intrinsics.jsArraySlice + IrCallImpl( expression.startOffset, expression.endOffset, arrayInfo.primitiveArrayType, - context.intrinsics.jsArraySlice + copyFunction ).apply { putTypeArgument(0, arrayInfo.primitiveArrayType) putValueArgument(0, segment) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrBoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrBoxJsTestGenerated.java index b5bc6ab2627..d96ba2ace56 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrBoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrBoxJsTestGenerated.java @@ -6795,6 +6795,11 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { public void testEmptyVarargInConstructorCall() throws Exception { runTest("js/js.translator/testData/box/regression/typeChecks/emptyVarargInConstructorCall.kt"); } + + @TestMetadata("taggedArrayCopy.kt") + public void testTaggedArrayCopy() throws Exception { + runTest("js/js.translator/testData/box/regression/typeChecks/taggedArrayCopy.kt"); + } } } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index e787fbbdeb5..329eef01a9d 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -6830,6 +6830,11 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { public void testEmptyVarargInConstructorCall() throws Exception { runTest("js/js.translator/testData/box/regression/typeChecks/emptyVarargInConstructorCall.kt"); } + + @TestMetadata("taggedArrayCopy.kt") + public void testTaggedArrayCopy() throws Exception { + runTest("js/js.translator/testData/box/regression/typeChecks/taggedArrayCopy.kt"); + } } } diff --git a/js/js.translator/testData/box/regression/typeChecks/taggedArrayCopy.kt b/js/js.translator/testData/box/regression/typeChecks/taggedArrayCopy.kt new file mode 100644 index 00000000000..7eccaccfd4a --- /dev/null +++ b/js/js.translator/testData/box/regression/typeChecks/taggedArrayCopy.kt @@ -0,0 +1,43 @@ +// IGNORE_BACKEND: JS +// KJS_WITH_FULL_RUNTIME +// EXPECTED_REACHABLE_NODES: 1281 + +package foo + +fun checkBooleanVararg(vararg xs: Boolean) { + assertTrue(xs is BooleanArray) +} + +fun checkLongVararg(vararg xs: Long) { + assertTrue(xs is LongArray) +} + +fun checkCharVararg(vararg xs: Char) { + assertTrue(xs is CharArray) +} + +fun box(): String { + checkBooleanVararg() + checkBooleanVararg(true) + checkBooleanVararg(true, false) + checkBooleanVararg(*booleanArrayOf()) + checkBooleanVararg(*booleanArrayOf(true, false)) + checkBooleanVararg(true, *booleanArrayOf(false), false, *booleanArrayOf()) + + checkLongVararg() + checkLongVararg(1L) + checkLongVararg(2L, 3L) + checkLongVararg(*longArrayOf()) + checkLongVararg(*longArrayOf(4L, 5L)) + checkLongVararg(*longArrayOf(4L, 5L), 10L, 20L, 30L) + + checkCharVararg() + checkCharVararg('a') + checkCharVararg('b', 'c') + checkCharVararg(*charArrayOf()) + checkCharVararg(*charArrayOf('d', 'e')) + checkCharVararg(*charArrayOf(), *charArrayOf(), *charArrayOf()) + checkCharVararg('e', *charArrayOf(), 'f', *charArrayOf(), 'x', *charArrayOf(), 'd') + + return "OK" +} \ No newline at end of file diff --git a/libraries/stdlib/js-ir/runtime/noPackageHacks.kt b/libraries/stdlib/js-ir/runtime/noPackageHacks.kt index 2257a7670f7..1cb463fd1e5 100644 --- a/libraries/stdlib/js-ir/runtime/noPackageHacks.kt +++ b/libraries/stdlib/js-ir/runtime/noPackageHacks.kt @@ -44,6 +44,12 @@ internal fun primitiveArrayConcat(vararg args: T): T { return result.unsafeCast() } +internal fun taggedArrayCopy(array: dynamic): T { + val res = array.slice() + res.`$type$` = array.`$type$` + return res.unsafeCast() +} + @PublishedApi internal inline fun withType(type: String, array: dynamic): dynamic { array.`$type$` = type