diff --git a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/FunctionsFromAnyGenerator.kt b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/FunctionsFromAnyGenerator.kt index f44ae11e293..ef6ea195151 100644 --- a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/FunctionsFromAnyGenerator.kt +++ b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/FunctionsFromAnyGenerator.kt @@ -60,7 +60,7 @@ abstract class FunctionsFromAnyGenerator(protected val declaration: KtClassOrObj generateEqualsMethod(function, properties) } - private val primaryConstructorProperties: List + protected val primaryConstructorProperties: List get() = primaryConstructorParameters .filter { it.hasValOrVar() } .map { bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, it)!! } diff --git a/compiler/testData/codegen/box/unsignedTypes/iterateOverArrayOfUnsignedValues.kt b/compiler/testData/codegen/box/unsignedTypes/iterateOverArrayOfUnsignedValues.kt index df9786ba0f3..ab642d56920 100644 --- a/compiler/testData/codegen/box/unsignedTypes/iterateOverArrayOfUnsignedValues.kt +++ b/compiler/testData/codegen/box/unsignedTypes/iterateOverArrayOfUnsignedValues.kt @@ -1,7 +1,6 @@ // WITH_UNSIGNED // IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR -// IGNORE_BACKEND: JS fun box(): String { var sum = 0u diff --git a/compiler/testData/codegen/box/unsignedTypes/varargsOfUnsignedTypes.kt b/compiler/testData/codegen/box/unsignedTypes/varargsOfUnsignedTypes.kt index 7a51ebfa7de..48bb64a394d 100644 --- a/compiler/testData/codegen/box/unsignedTypes/varargsOfUnsignedTypes.kt +++ b/compiler/testData/codegen/box/unsignedTypes/varargsOfUnsignedTypes.kt @@ -1,6 +1,6 @@ // IGNORE_BACKEND: JVM_IR // WITH_UNSIGNED -// IGNORE_BACKEND: JS, JS_IR +// IGNORE_BACKEND: JS_IR fun uint(vararg us: UInt): UIntArray = us 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 8c39384bdc8..431cb0973c1 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 @@ -2495,6 +2495,11 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { runTest("js/js.translator/testData/box/expression/function/vararg.kt"); } + @TestMetadata("varargUInt.kt") + public void testVarargUInt() throws Exception { + runTest("js/js.translator/testData/box/expression/function/varargUInt.kt"); + } + @TestMetadata("whenFunction.kt") public void testWhenFunction() throws Exception { runTest("js/js.translator/testData/box/expression/function/whenFunction.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java index 34c38ecf302..f5e80e5b612 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java @@ -2495,6 +2495,11 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { runTest("js/js.translator/testData/box/expression/function/vararg.kt"); } + @TestMetadata("varargUInt.kt") + public void testVarargUInt() throws Exception { + runTest("js/js.translator/testData/box/expression/function/varargUInt.kt"); + } + @TestMetadata("whenFunction.kt") public void testWhenFunction() throws Exception { runTest("js/js.translator/testData/box/expression/function/whenFunction.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/JsDataClassGenerator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/JsDataClassGenerator.java index de5857ac2e8..a91008e725e 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/JsDataClassGenerator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/JsDataClassGenerator.java @@ -18,13 +18,18 @@ package org.jetbrains.kotlin.js.translate.declaration; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.backend.common.CodegenUtil; import org.jetbrains.kotlin.backend.common.DataClassMethodGenerator; import org.jetbrains.kotlin.descriptors.*; +import org.jetbrains.kotlin.descriptors.annotations.Annotations; +import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl; +import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl; import org.jetbrains.kotlin.js.backend.ast.*; import org.jetbrains.kotlin.js.translate.context.Namer; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; import org.jetbrains.kotlin.js.translate.utils.UtilsKt; +import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.KtClassOrObject; import org.jetbrains.kotlin.psi.KtParameter; import org.jetbrains.kotlin.resolve.BindingContext; @@ -49,6 +54,15 @@ class JsDataClassGenerator extends DataClassMethodGenerator { this.isInline = isInline; } + @Override + public void generate() { + if (isInline) { + generateUnboxFunction(); + } + + super.generate(); + } + @Override public void generateComponentFunction(@NotNull FunctionDescriptor function, @NotNull ValueParameterDescriptor parameter) { if (isInline) return; @@ -213,6 +227,18 @@ class JsDataClassGenerator extends DataClassMethodGenerator { functionObj.getBody().getStatements().add(returnStatement); } + private void generateUnboxFunction() { + PropertyDescriptor boxee = getPrimaryConstructorProperties().get(0); + + JsFunction unboxFunction = context.createRootScopedFunction("unbox"); + JsExpression prototypeRef = JsAstUtils.prototypeOf(context.getInnerReference(getClassDescriptor())); + JsExpression functionRef = new JsNameRef("unbox", prototypeRef); + + unboxFunction.getBody().getStatements().add(new JsReturn(JsAstUtils.pureFqn(context.getNameForDescriptor(boxee), new JsThisRef()))); + + context.addDeclarationStatement(JsAstUtils.assignment(functionRef, unboxFunction).makeStmt()); + } + private JsFunction generateJsMethod(@NotNull FunctionDescriptor functionDescriptor) { JsFunction functionObject = context.createRootScopedFunction(functionDescriptor); functionObject.setSource(getDeclaration()); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/ArrayFIF.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/ArrayFIF.kt index 3d688519680..091b728d747 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/ArrayFIF.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/ArrayFIF.kt @@ -40,6 +40,8 @@ import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntri import org.jetbrains.kotlin.js.translate.utils.JsAstUtils import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.inline.InlineStrategy +import org.jetbrains.kotlin.resolve.isInlineClassType +import org.jetbrains.kotlin.types.KotlinType import java.util.* object ArrayFIF : CompositeFIF() { @@ -64,14 +66,38 @@ object ArrayFIF : CompositeFIF() { @JvmStatic fun typedArraysEnabled(config: JsConfig) = config.configuration.get(JSConfigurationKeys.TYPED_ARRAYS_ENABLED, true) - fun castOrCreatePrimitiveArray(ctx: TranslationContext, type: PrimitiveType?, arg: JsArrayLiteral): JsExpression { - if (type == null || !typedArraysEnabled(ctx.config)) return arg + fun unsignedPrimitiveToSigned(type: KotlinType): PrimitiveType? { + // short-circuit + if (!type.isInlineClassType() || type.isMarkedNullable) return null - return if (type in TYPED_ARRAY_MAP) { - createTypedArray(type, arg) + return when { + KotlinBuiltIns.isUByte(type) -> BYTE + KotlinBuiltIns.isUShort(type) -> SHORT + KotlinBuiltIns.isUInt(type) -> INT + KotlinBuiltIns.isULong(type) -> LONG + else -> null + } + } + + fun castOrCreatePrimitiveArray(ctx: TranslationContext, type: KotlinType, arg: JsArrayLiteral): JsExpression { + if (type.isMarkedNullable) return arg + + val unsignedPrimitiveType = unsignedPrimitiveToSigned(type) + + if (unsignedPrimitiveType != null) { + val conversionFunction = "to${unsignedPrimitiveType.typeName}" + arg.expressions.replaceAll { JsInvocation(JsNameRef(conversionFunction, it)) } + } + + val primitiveType = unsignedPrimitiveType ?: KotlinBuiltIns.getPrimitiveType(type)?.takeUnless { type.isMarkedNullable} + + if (primitiveType == null || !typedArraysEnabled(ctx.config)) return arg + + return if (primitiveType in TYPED_ARRAY_MAP) { + createTypedArray(primitiveType, arg) } else { - JsAstUtils.invokeKotlinFunction(type.lowerCaseName + "ArrayOf", *arg.expressions.toTypedArray()) + JsAstUtils.invokeKotlinFunction(primitiveType.lowerCaseName + "ArrayOf", *arg.expressions.toTypedArray()) } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt index fc986f68062..ce7256a0b12 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt @@ -5,12 +5,13 @@ package org.jetbrains.kotlin.js.translate.reference -import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor import org.jetbrains.kotlin.builtins.getFunctionalClassKind +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects @@ -25,6 +26,8 @@ import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.js.translate.utils.JsAstUtils import org.jetbrains.kotlin.js.translate.utils.TranslationUtils import org.jetbrains.kotlin.js.translate.utils.getReferenceToJsClass +import org.jetbrains.kotlin.name.FqNameUnsafe +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.ValueArgument import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.components.isVararg @@ -33,6 +36,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType import java.util.* class CallArgumentTranslator private constructor( @@ -77,7 +81,7 @@ class CallArgumentTranslator private constructor( var argsBeforeVararg: List? = null var concatArguments: MutableList? = null val argsToJsExpr = translateUnresolvedArguments(context(), resolvedCall) - var varargPrimitiveType: PrimitiveType? = null + var varargElementType: KotlinType? = null for (parameterDescriptor in valueParameters) { val actualArgument = valueArgumentsByIndex[parameterDescriptor.index] @@ -90,8 +94,7 @@ class CallArgumentTranslator private constructor( hasSpreadOperator = arguments.any { it.getSpreadElement() != null } } - val varargElementType = parameterDescriptor.original.varargElementType!! - varargPrimitiveType = KotlinBuiltIns.getPrimitiveType(varargElementType).takeUnless { varargElementType.isMarkedNullable } + varargElementType = parameterDescriptor.original.varargElementType!! if (hasSpreadOperator) { if (isNativeFunctionCall) { @@ -102,10 +105,10 @@ class CallArgumentTranslator private constructor( null) } else { - result.addAll(translateVarargArgument(actualArgument, - argsToJsExpr, - actualArgument.arguments.size > 1, - varargPrimitiveType)) + translateVarargArgument(actualArgument, + argsToJsExpr, + actualArgument.arguments.size > 1, + varargElementType)?.let { result.add(it) } } } else { @@ -113,7 +116,7 @@ class CallArgumentTranslator private constructor( result.addAll(translateResolvedArgument(actualArgument, argsToJsExpr)) } else { - result.addAll(translateVarargArgument(actualArgument, argsToJsExpr, true, varargPrimitiveType)) + translateVarargArgument(actualArgument, argsToJsExpr, true, varargElementType)?.let { result.add(it) } } } } @@ -134,7 +137,7 @@ class CallArgumentTranslator private constructor( concatArguments!!.add(0, toArray(null, argsBeforeVararg)) } - result = mutableListOf(concatArgumentsIfNeeded(concatArguments!!, varargPrimitiveType, true)) + result = mutableListOf(concatArgumentsIfNeeded(concatArguments!!, varargElementType, true)) if (receiver != null) { cachedReceiver = context().getOrDeclareTemporaryConstVariable(receiver) @@ -207,44 +210,64 @@ class CallArgumentTranslator private constructor( return result } + // Cache UTypeArray descriptor lookup + private val typeToUTypeArray = mutableMapOf() + + private fun JsExpression.wrapInUArray(elementType: KotlinType): JsExpression { + return ArrayFIF.unsignedPrimitiveToSigned(elementType)?.let { primitiveType -> + val kotlinMemberScope = context.currentModule.getPackage(FqNameUnsafe("kotlin").toSafe()).memberScope + val classDescriptor = typeToUTypeArray.computeIfAbsent(primitiveType) { + val className = Name.identifier("U${primitiveType.typeName}Array") + kotlinMemberScope.getContributedClassifier(className, NoLookupLocation.FROM_BACKEND) as ClassDescriptor + } + JsNew(ReferenceTranslator.translateAsTypeReference(classDescriptor, context), listOf(this)) + } ?: this + } + private fun translateVarargArgument( - resolvedArgument: ResolvedValueArgument, - translatedArgs: Map, - shouldWrapVarargInArray: Boolean, - varargPrimitiveType: PrimitiveType? - ): List { + resolvedArgument: ResolvedValueArgument, + translatedArgs: Map, + shouldWrapVarargInArray: Boolean, + varargElementType: KotlinType + ): JsExpression? { val arguments = resolvedArgument.arguments if (arguments.isEmpty()) { return if (shouldWrapVarargInArray) { - return listOf(toArray(varargPrimitiveType, listOf())) - } - else { - listOf() + return toArray(varargElementType, listOf()).wrapInUArray(varargElementType) + } else { + null } } val list = translateResolvedArgument(resolvedArgument, translatedArgs) return if (shouldWrapVarargInArray) { - val concatArguments = prepareConcatArguments(arguments, list, varargPrimitiveType) - val concatExpression = concatArgumentsIfNeeded(concatArguments, varargPrimitiveType, false) - listOf(concatExpression) - } - else { - listOf(JsAstUtils.invokeMethod(list[0], "slice")) - } + val concatArguments = prepareConcatArguments(arguments, list, varargElementType) + val concatExpression = concatArgumentsIfNeeded(concatArguments, varargElementType, false) + concatExpression + } else { + val arg = ArrayFIF.unsignedPrimitiveToSigned(varargElementType)?.let {type -> + JsInvocation(JsNameRef("unbox", list[0])) + } ?: list[0] + JsAstUtils.invokeMethod(arg, "slice") + }.wrapInUArray(varargElementType) } - private fun toArray(varargPrimitiveType: PrimitiveType?, elements: List): JsExpression { - return ArrayFIF.castOrCreatePrimitiveArray(context(), - varargPrimitiveType, - JsArrayLiteral(elements).apply { sideEffects = SideEffectKind.PURE }) + private fun toArray(varargElementType: KotlinType?, elements: List): JsExpression { + val argument = JsArrayLiteral(elements).apply { sideEffects = SideEffectKind.PURE } + + if (varargElementType == null) return argument + + return ArrayFIF.castOrCreatePrimitiveArray( + context(), + varargElementType, + argument) } private fun prepareConcatArguments( - arguments: List, - list: List, - varargPrimitiveType: PrimitiveType? + arguments: List, + list: List, + varargElementType: KotlinType? ): MutableList { assert(arguments.isNotEmpty()) { "arguments.size should not be 0" } assert(arguments.size == list.size) { "arguments.size: " + arguments.size + " != list.size: " + list.size } @@ -259,17 +282,19 @@ class CallArgumentTranslator private constructor( if (valueArgument.getSpreadElement() != null) { if (lastArrayContent.size > 0) { - concatArguments.add(toArray(varargPrimitiveType, lastArrayContent)) + concatArguments.add(toArray(varargElementType, lastArrayContent)) lastArrayContent = mutableListOf() } - concatArguments.add(expressionArgument) - } - else { + val e = if (varargElementType != null && ArrayFIF.unsignedPrimitiveToSigned(varargElementType) != null) { + JsInvocation(JsNameRef("unbox", expressionArgument)) + } else expressionArgument + concatArguments.add(e) + } else { lastArrayContent.add(expressionArgument) } } if (lastArrayContent.size > 0) { - concatArguments.add(toArray(varargPrimitiveType, lastArrayContent)) + concatArguments.add(toArray(varargElementType, lastArrayContent)) } return concatArguments @@ -306,23 +331,23 @@ class CallArgumentTranslator private constructor( } private fun concatArgumentsIfNeeded( - concatArguments: List, - varargPrimitiveType: PrimitiveType?, - isMixed: Boolean + concatArguments: List, + varargElementType: KotlinType?, + isMixed: Boolean ): JsExpression { assert(concatArguments.isNotEmpty()) { "concatArguments.size should not be 0" } return if (concatArguments.size > 1) { - if (varargPrimitiveType != null) { + if (varargElementType != null && (varargElementType.isPrimitiveNumberType() || ArrayFIF.unsignedPrimitiveToSigned(varargElementType) != null)) { val method = if (isMixed) "arrayConcat" else "primitiveArrayConcat" - JsAstUtils.invokeKotlinFunction(method, concatArguments[0], - *concatArguments.subList(1, concatArguments.size).toTypedArray()) - } - else { + JsAstUtils.invokeKotlinFunction( + method, concatArguments[0], + *concatArguments.subList(1, concatArguments.size).toTypedArray() + ) + } else { JsInvocation(JsNameRef("concat", concatArguments[0]), concatArguments.subList(1, concatArguments.size)) } - } - else { + } else { concatArguments[0] } } diff --git a/js/js.translator/testData/box/expression/function/varargUInt.kt b/js/js.translator/testData/box/expression/function/varargUInt.kt new file mode 100644 index 00000000000..530b2772332 --- /dev/null +++ b/js/js.translator/testData/box/expression/function/varargUInt.kt @@ -0,0 +1,113 @@ +// LANGUAGE_VERSION: 1.3 +// IGNORE_BACKEND: JS_IR +// EXPECTED_REACHABLE_NODES: 1566 +package foo + +fun testSize(expectedSize: Int, vararg i: UInt): Boolean { + return (i.size == expectedSize) +} + +fun testSum(expectedSum: UInt, vararg i: UInt): Boolean { + var sum = 0u + for (j in i) { + sum += j + } + + return (expectedSum == sum) +} + +fun testSpreadOperator(vararg args: UInt): Boolean { + var sum = 0u + for (a in args) sum += a + + return testSize(args.size, *args) && testSum(sum, *args) +} + +class Bar(val size: Int, val sum: UInt) { + fun test(vararg args: UInt) = testSize(size, *args) && testSum(sum, *args) +} + +object obj { + fun test(size: Int, sum: UInt, vararg args: UInt) = testSize(size, *args) && testSum(sum, *args) +} + +fun spreadInMethodCall(size: Int, sum: UInt, vararg args: UInt) = Bar(size, sum).test(*args) + +fun spreadInObjectMethodCall(size: Int, sum: UInt, vararg args: UInt) = obj.test(size, sum, *args) + +fun testVarargWithFunLit(vararg args: UInt, f: (a: UIntArray) -> Boolean): Boolean = f(args) + +fun idVarArgs(vararg a: T) = a + +fun idArrayVarArg(vararg a: Array) = a + +fun sumFunValuesOnParameters(x: UInt, y: UInt, vararg a: UInt, f: (UInt) -> UInt): UInt { + var result = f(x) + f(y) + for(u in a) { + result += f(u) + } + return result +} + +fun box(): String { + if (!testSize(0)) + return "wrong vararg size when call function without args" + + if (!testSum(0u)) + return "wrong vararg sum (arguments) when call function without args" + + if (!testSize(6, 1u, 1u, 1u, 2u, 3u, 4u)) + return "wrong vararg size when call function with some args (1)" + + if (!testSum(30, 10u, 20u, 0u)) + return "wrong vararg sum (arguments) when call function with some args (1)" + + if (!testSpreadOperator(30u, 10u, 20u, 0u)) + return "failed when call function using spread operator" + + if (!Bar(3, 30u).test(10u, 20u, 0u)) + return "failed when call method" + + if (!spreadInMethodCall(2, 3u, 1u, 2u)) + return "failed when call method using spread operator" + + if (!obj.test(5, 15u, 1u, 2u, 3u, 4u, 5u)) + return "failed when call method of object" + + if (!spreadInObjectMethodCall(2, 3u, 1u, 2u)) + return "failed when call method of object using spread operator" + + if (!testVarargWithFunLit(1u, 2u, 3u) { args -> args.size == 3 }) + return "failed when call function with vararg and fun literal" + + val a = arrayOf(1u, 2u, 3u) + val b = arrayOf(4u, 5u) + + assertEquals(5, arrayOf(*a, *b).size) + assertEquals(8, arrayOf(10u, *a, 20u, *b, 30u).size) + + assertEquals(5, idVarArgs(*a, *b).size) + assertEquals(8, idVarArgs(10u, *a, 20u, *b, 30u).size) + + assertEquals(9, arrayOf(1u, *a, *a, 1u, 2u).size) + assertEquals(9, idVarArgs(1u, *a, *a, 1u, 2u).size) + + assertEquals(9, arrayOf(1u, *a, *arrayOf(1u, 2u, 3u), 1u, 2u).size) + assertEquals(9, idVarArgs(1u, *a, *arrayOf(1u, 2u, 3u), 1u, 2u).size) + + assertEquals(90u, sumFunValuesOnParameters(1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u) { 2u*it }) + assertEquals(90u, sumFunValuesOnParameters(1u, 2u, *uintArrayOf(3u, 4u, 5u, 6u, 7u, 8u, 9u)) { 2u*it }) + assertEquals(90u, sumFunValuesOnParameters(1u, 2u, 3u, 4u, *uintArrayOf(5u, 6u, 7u, 8u, 9u)) { 2u*it }) + assertEquals(90u, sumFunValuesOnParameters(1u, 2u, *uintArrayOf(3u, 4u, 5u, 6u, 7u), 8u, 9u) { 2u*it }) + assertEquals(90u, sumFunValuesOnParameters(1u, 2u, *uintArrayOf(3u, 4u, 5u), *uintArrayOf(6u, 7u, 8u, 9u)) { 2u*it }) + assertEquals(90u, sumFunValuesOnParameters(1u, 2u, *uintArrayOf(3u, 4u), 5u, 6u, *uintArrayOf(7u, 8u, 9u)) { 2u*it }) + + assertEquals(2, idArrayVarArg(arrayOf(1u), *arrayOf(arrayOf(2u, 3u, 4u))).size) + assertEquals(3, idArrayVarArg(arrayOf(1u, 2u), *arrayOf(arrayOf(3u, 4u), arrayOf(5u, 6u))).size) + assertEquals(6, idArrayVarArg(arrayOf(1u, 2u), *arrayOf(arrayOf(3u, 4u), arrayOf(5u, 6u)), arrayOf(7u), *arrayOf(arrayOf(8u, 9u), arrayOf(10u, 11u))).size) + + val c = arrayOf(*a) + assertFalse(a === c, "Spread operator should copy its argument") + + return "OK" +} \ No newline at end of file