From 4c808e8691856f911e2a2464ee7e5ef26c68f20c Mon Sep 17 00:00:00 2001 From: Anton Bannykh Date: Mon, 13 Feb 2017 15:27:48 +0300 Subject: [PATCH] JS: concat vararg arguments using Kotlin.concat and Kotlin.concatPrimitive functions in order to be binary compatible with (Kotlin PrimitiveArray -> JS TypedArrays) mapping. --- js/js.libraries/src/core/builtins.kt | 21 +++ .../src/core/generated/_ArraysJs.kt | 44 +++-- .../functions/factories/ArrayFIF.java | 2 +- .../reference/CallArgumentTranslator.kt | 45 +++-- .../testData/box/native/vararg.kt | 8 + .../src/generators/GenerateStandardLib.kt | 3 + .../src/templates/SpecialJVM.kt | 174 +++++++++++------- 7 files changed, 197 insertions(+), 100 deletions(-) diff --git a/js/js.libraries/src/core/builtins.kt b/js/js.libraries/src/core/builtins.kt index d175028d8ac..b0317691544 100644 --- a/js/js.libraries/src/core/builtins.kt +++ b/js/js.libraries/src/core/builtins.kt @@ -93,4 +93,25 @@ public class BoxedChar(val c: Char) : Comparable { public fun valueOf(): Int { return js("this.c") } +} + +/* For future binary compatibility with TypedArrays + * TODO: concat normal Array's and TypedArrays into an Array + */ +@PublishedApi +@JsName("arrayConcat") +internal fun arrayConcat(a: T, b: T): T { + return a.asDynamic().concat.apply(js("[]"), js("arguments")); +} + +/* For future binary compatibility with TypedArrays + * TODO: concat primitive arrays. + * For Byte-, Short-, Int-, Float-, and DoubleArray concat result into a TypedArray. + * For Boolean-, Char-, and LongArray return an Array with corresponding type property. + * Default to Array.prototype.concat for compatibility. + */ +@PublishedApi +@JsName("primitiveArrayConcat") +internal fun primitiveArrayConcat(a: T, b: T): T { + return a.asDynamic().concat.apply(js("[]"), js("arguments")); } \ No newline at end of file diff --git a/js/js.libraries/src/core/generated/_ArraysJs.kt b/js/js.libraries/src/core/generated/_ArraysJs.kt index 9cace5d15ff..c533ef6e7e0 100644 --- a/js/js.libraries/src/core/generated/_ArraysJs.kt +++ b/js/js.libraries/src/core/generated/_ArraysJs.kt @@ -9,6 +9,7 @@ package kotlin.collections // import kotlin.js.* +import primitiveArrayConcat import kotlin.comparisons.* /** @@ -12944,8 +12945,15 @@ public inline fun BooleanArray.asList(): List { /** * Returns a [List] that wraps the original array. */ -public inline fun CharArray.asList(): List { - return this.toTypedArray().asList() +public fun CharArray.asList(): List { + return object : AbstractList(), RandomAccess { + override val size: Int get() = this@asList.size + override fun isEmpty(): Boolean = this@asList.isEmpty() + override fun contains(element: Char): Boolean = this@asList.contains(element) + override fun get(index: Int): Char = this@asList[index] + override fun indexOf(element: Char): Int = this@asList.indexOf(element) + override fun lastIndexOf(element: Char): Int = this@asList.lastIndexOf(element) + } } /** @@ -13168,7 +13176,7 @@ public inline operator fun Array.plus(element: T): Array { */ @Suppress("NOTHING_TO_INLINE") public inline operator fun ByteArray.plus(element: Byte): ByteArray { - return this.asDynamic().concat(arrayOf(element)) + return plus(byteArrayOf(element)) } /** @@ -13176,7 +13184,7 @@ public inline operator fun ByteArray.plus(element: Byte): ByteArray { */ @Suppress("NOTHING_TO_INLINE") public inline operator fun ShortArray.plus(element: Short): ShortArray { - return this.asDynamic().concat(arrayOf(element)) + return plus(shortArrayOf(element)) } /** @@ -13184,7 +13192,7 @@ public inline operator fun ShortArray.plus(element: Short): ShortArray { */ @Suppress("NOTHING_TO_INLINE") public inline operator fun IntArray.plus(element: Int): IntArray { - return this.asDynamic().concat(arrayOf(element)) + return plus(intArrayOf(element)) } /** @@ -13192,7 +13200,7 @@ public inline operator fun IntArray.plus(element: Int): IntArray { */ @Suppress("NOTHING_TO_INLINE") public inline operator fun LongArray.plus(element: Long): LongArray { - return this.asDynamic().concat(arrayOf(element)) + return plus(longArrayOf(element)) } /** @@ -13200,7 +13208,7 @@ public inline operator fun LongArray.plus(element: Long): LongArray { */ @Suppress("NOTHING_TO_INLINE") public inline operator fun FloatArray.plus(element: Float): FloatArray { - return this.asDynamic().concat(arrayOf(element)) + return plus(floatArrayOf(element)) } /** @@ -13208,7 +13216,7 @@ public inline operator fun FloatArray.plus(element: Float): FloatArray { */ @Suppress("NOTHING_TO_INLINE") public inline operator fun DoubleArray.plus(element: Double): DoubleArray { - return this.asDynamic().concat(arrayOf(element)) + return plus(doubleArrayOf(element)) } /** @@ -13216,7 +13224,7 @@ public inline operator fun DoubleArray.plus(element: Double): DoubleArray { */ @Suppress("NOTHING_TO_INLINE") public inline operator fun BooleanArray.plus(element: Boolean): BooleanArray { - return this.asDynamic().concat(arrayOf(element)) + return plus(booleanArrayOf(element)) } /** @@ -13224,7 +13232,7 @@ public inline operator fun BooleanArray.plus(element: Boolean): BooleanArray { */ @Suppress("NOTHING_TO_INLINE") public inline operator fun CharArray.plus(element: Char): CharArray { - return this.asDynamic().concat(arrayOf(element)) + return plus(charArrayOf(element)) } /** @@ -13303,7 +13311,7 @@ public inline operator fun Array.plus(elements: Array): Array< */ @Suppress("NOTHING_TO_INLINE") public inline operator fun ByteArray.plus(elements: ByteArray): ByteArray { - return this.asDynamic().concat(elements) + return primitiveArrayConcat(this, elements) } /** @@ -13311,7 +13319,7 @@ public inline operator fun ByteArray.plus(elements: ByteArray): ByteArray { */ @Suppress("NOTHING_TO_INLINE") public inline operator fun ShortArray.plus(elements: ShortArray): ShortArray { - return this.asDynamic().concat(elements) + return primitiveArrayConcat(this, elements) } /** @@ -13319,7 +13327,7 @@ public inline operator fun ShortArray.plus(elements: ShortArray): ShortArray { */ @Suppress("NOTHING_TO_INLINE") public inline operator fun IntArray.plus(elements: IntArray): IntArray { - return this.asDynamic().concat(elements) + return primitiveArrayConcat(this, elements) } /** @@ -13327,7 +13335,7 @@ public inline operator fun IntArray.plus(elements: IntArray): IntArray { */ @Suppress("NOTHING_TO_INLINE") public inline operator fun LongArray.plus(elements: LongArray): LongArray { - return this.asDynamic().concat(elements) + return primitiveArrayConcat(this, elements) } /** @@ -13335,7 +13343,7 @@ public inline operator fun LongArray.plus(elements: LongArray): LongArray { */ @Suppress("NOTHING_TO_INLINE") public inline operator fun FloatArray.plus(elements: FloatArray): FloatArray { - return this.asDynamic().concat(elements) + return primitiveArrayConcat(this, elements) } /** @@ -13343,7 +13351,7 @@ public inline operator fun FloatArray.plus(elements: FloatArray): FloatArray { */ @Suppress("NOTHING_TO_INLINE") public inline operator fun DoubleArray.plus(elements: DoubleArray): DoubleArray { - return this.asDynamic().concat(elements) + return primitiveArrayConcat(this, elements) } /** @@ -13351,7 +13359,7 @@ public inline operator fun DoubleArray.plus(elements: DoubleArray): DoubleArray */ @Suppress("NOTHING_TO_INLINE") public inline operator fun BooleanArray.plus(elements: BooleanArray): BooleanArray { - return this.asDynamic().concat(elements) + return primitiveArrayConcat(this, elements) } /** @@ -13359,7 +13367,7 @@ public inline operator fun BooleanArray.plus(elements: BooleanArray): BooleanArr */ @Suppress("NOTHING_TO_INLINE") public inline operator fun CharArray.plus(elements: CharArray): CharArray { - return this.asDynamic().concat(elements) + return primitiveArrayConcat(this, elements) } /** diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/ArrayFIF.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/ArrayFIF.java index 7e0e79347b3..c223af55507 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/ArrayFIF.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/ArrayFIF.java @@ -17,11 +17,11 @@ package org.jetbrains.kotlin.js.translate.intrinsic.functions.factories; import com.google.common.collect.Lists; -import org.jetbrains.kotlin.js.backend.ast.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.PrimitiveType; +import org.jetbrains.kotlin.js.backend.ast.*; import org.jetbrains.kotlin.js.patterns.DescriptorPredicate; import org.jetbrains.kotlin.js.patterns.NamePredicate; import org.jetbrains.kotlin.js.translate.context.Namer; 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 1e4fe89cd77..4dee0a535e6 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 @@ -16,12 +16,12 @@ package org.jetbrains.kotlin.js.translate.reference +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor 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 -import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.context.TemporaryConstVariable import org.jetbrains.kotlin.js.translate.context.TranslationContext @@ -83,6 +83,7 @@ class CallArgumentTranslator private constructor( var argsBeforeVararg: List? = null var concatArguments: MutableList? = null val argsToJsExpr = translateUnresolvedArguments(context(), resolvedCall) + var isVarargTypePrimitive: Boolean? = null for (parameterDescriptor in valueParameters) { val actualArgument = valueArgumentsByIndex[parameterDescriptor.index] @@ -95,6 +96,8 @@ class CallArgumentTranslator private constructor( hasSpreadOperator = arguments.any { it.getSpreadElement() != null } } + isVarargTypePrimitive = KotlinBuiltIns.isPrimitiveType(parameterDescriptor.original.varargElementType!!) + if (hasSpreadOperator) { if (isNativeFunctionCall) { argsBeforeVararg = result @@ -102,7 +105,10 @@ class CallArgumentTranslator private constructor( concatArguments = prepareConcatArguments(arguments, translateResolvedArgument(actualArgument, argsToJsExpr)) } else { - result.addAll(translateVarargArgument(actualArgument, argsToJsExpr, actualArgument.arguments.size > 1)) + result.addAll(translateVarargArgument(actualArgument, + argsToJsExpr, + actualArgument.arguments.size > 1, + isVarargTypePrimitive)) } } else { @@ -110,7 +116,7 @@ class CallArgumentTranslator private constructor( result.addAll(translateResolvedArgument(actualArgument, argsToJsExpr)) } else { - result.addAll(translateVarargArgument(actualArgument, argsToJsExpr, true)) + result.addAll(translateVarargArgument(actualArgument, argsToJsExpr, true, isVarargTypePrimitive)) } } } @@ -123,13 +129,15 @@ class CallArgumentTranslator private constructor( assert(argsBeforeVararg != null) { "argsBeforeVararg should not be null" } assert(concatArguments != null) { "concatArguments should not be null" } - concatArguments!!.addAll(result) - - if (!argsBeforeVararg!!.isEmpty()) { - concatArguments.add(0, JsArrayLiteral(argsBeforeVararg).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE }) + if (!result.isEmpty()) { + concatArguments!!.add(JsArrayLiteral(result).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE }) } - result = mutableListOf(concatArgumentsIfNeeded(concatArguments)) + if (!argsBeforeVararg!!.isEmpty()) { + concatArguments!!.add(0, JsArrayLiteral(argsBeforeVararg).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE }) + } + + result = mutableListOf(concatArgumentsIfNeeded(concatArguments!!, isVarargTypePrimitive!!, true)) if (receiver != null) { cachedReceiver = context().getOrDeclareTemporaryConstVariable(receiver) @@ -235,7 +243,8 @@ class CallArgumentTranslator private constructor( private fun translateVarargArgument( resolvedArgument: ResolvedValueArgument, translatedArgs: Map, - shouldWrapVarargInArray: Boolean + shouldWrapVarargInArray: Boolean, + isVarargTypePrimitive: Boolean ): List { val arguments = resolvedArgument.arguments if (arguments.isEmpty()) { @@ -251,7 +260,7 @@ class CallArgumentTranslator private constructor( return if (shouldWrapVarargInArray) { val concatArguments = prepareConcatArguments(arguments, list) - val concatExpression = concatArgumentsIfNeeded(concatArguments) + val concatExpression = concatArgumentsIfNeeded(concatArguments, isVarargTypePrimitive, false) listOf(concatExpression) } else { @@ -259,12 +268,22 @@ class CallArgumentTranslator private constructor( } } - private fun concatArgumentsIfNeeded(concatArguments: List): JsExpression { + private fun concatArgumentsIfNeeded( + concatArguments: List, + isVarargTypePrimitive: Boolean, + isMixed: Boolean + ): JsExpression { assert(concatArguments.isNotEmpty()) { "concatArguments.size should not be 0" } if (concatArguments.size > 1) { - return JsInvocation(JsNameRef("concat", concatArguments[0]), concatArguments.subList(1, concatArguments.size)) - + if (isVarargTypePrimitive) { + val method = if (isMixed) "arrayConcat" else "primitiveArrayConcat" + return JsAstUtils.invokeKotlinFunction(method, concatArguments[0], + *concatArguments.subList(1, concatArguments.size).toTypedArray()) + } + else { + return JsInvocation(JsNameRef("concat", concatArguments[0]), concatArguments.subList(1, concatArguments.size)) + } } else { return concatArguments[0] diff --git a/js/js.translator/testData/box/native/vararg.kt b/js/js.translator/testData/box/native/vararg.kt index 05fcc890964..dac32fdd5b9 100644 --- a/js/js.translator/testData/box/native/vararg.kt +++ b/js/js.translator/testData/box/native/vararg.kt @@ -56,6 +56,12 @@ external fun sumFunValuesOnParameters(x: Int, y: Int, vararg a: Int, f: (Int) -> external fun idArrayVarArg(vararg a: Array): Array = definedExternally +@JsName("paramCount") +external fun oneMoreParamCount(before: IntArray, vararg middle: Int, after: IntArray): Int + +@JsName("paramCount") +external fun oneMoreGenericParamCount(before: Array, vararg middle: T, after: Array): Int + fun box(): String { if (paramCount() != 0) return "failed when call native function without args" @@ -138,5 +144,7 @@ fun box(): String { assertEquals(3, idArrayVarArg(arrayOf(1, 2), *arrayOf(arrayOf(3, 4), arrayOf(5, 6))).size) assertEquals(6, idArrayVarArg(arrayOf(1, 2), *arrayOf(arrayOf(3, 4), arrayOf(5, 6)), arrayOf(7), *arrayOf(arrayOf(8, 9), arrayOf(10, 11))).size) + assertEquals(6, oneMoreParamCount(intArrayOf(1, 2), 3, *intArrayOf(4, 5), 6, after = intArrayOf(7, 8))) + assertEquals(6, oneMoreGenericParamCount(arrayOf("1", "2"), "3", *arrayOf("4", "5"), "6", after = arrayOf("7", "8"))) return "OK" } \ No newline at end of file diff --git a/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt b/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt index 5009faf0021..f6d6b604963 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt @@ -101,6 +101,9 @@ private fun List.writeTo(file: File, sourceFile: SourceFile, p writer.append("$COMMON_AUTOGENERATED_WARNING\n\n") if (platform == Platform.JS) { writer.appendln("import kotlin.js.*") + if (sourceFile == SourceFile.Arrays) { + writer.appendln("import primitiveArrayConcat") + } } writer.append("import kotlin.comparisons.*\n\n") diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJVM.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJVM.kt index 78f359325ae..820487289c4 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJVM.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJVM.kt @@ -175,32 +175,41 @@ object CommonArrays { } } - fun f_plusElementOperator() = f("plus(element: T)") { - operator(true) + fun f_plusElementOperator() = + (listOf(InvariantArraysOfObjects to null) + PrimitiveType.defaultPrimitives.map { ArraysOfPrimitives to it }).map { + val (family, primitive) = it + f("plus(element: T)") { + operator(true) - inline(Platform.JS, Inline.Yes) - annotations(Platform.JS, """@Suppress("NOTHING_TO_INLINE")""") + only(family) + if (family == InvariantArraysOfObjects) { + only(Platform.JS, ArraysOfObjects) + } - only(InvariantArraysOfObjects, ArraysOfPrimitives) - only(Platform.JS, ArraysOfObjects, ArraysOfPrimitives) + inline(Platform.JS, Inline.Yes) + annotations(Platform.JS, """@Suppress("NOTHING_TO_INLINE")""") - returns("SELF") - returns(Platform.JS, ArraysOfObjects) { "Array" } - doc { "Returns an array containing all elements of the original array and then the given [element]." } - body(Platform.JVM) { - """ - val index = size - val result = java.util.Arrays.copyOf(this, index + 1) - result[index] = element - return result - """ - } - body(Platform.JS) { - """ - return this.asDynamic().concat(arrayOf(element)) - """ - } - } + returns("SELF") + returns(Platform.JS, ArraysOfObjects) { "Array" } + doc { "Returns an array containing all elements of the original array and then the given [element]." } + body(Platform.JVM) { + """ + val index = size + val result = java.util.Arrays.copyOf(this, index + 1) + result[index] = element + return result + """ + } + + if (primitive == null) { + body(Platform.JS) { "return this.asDynamic().concat(arrayOf(element))" } + } + else { + only(primitive) + body(Platform.JS, ArraysOfPrimitives) { "return plus(${primitive.name.toLowerCase()}ArrayOf(element))" } + } + } + } fun f_plusCollection() = f("plus(elements: Collection)") { operator(true) @@ -258,6 +267,12 @@ object CommonArrays { return this.asDynamic().concat(elements) """ } + body(Platform.JS, ArraysOfPrimitives) { + """ + return primitiveArrayConcat(this, elements) + """ + } + } fun f_copyOfRange() = f("copyOfRange(fromIndex: Int, toIndex: Int)") { @@ -318,7 +333,7 @@ object CommonArrays { returns("SELF") defaultValue = when (primitive) { PrimitiveType.Boolean -> false.toString() - PrimitiveType.Char -> "'\\u0000'" + PrimitiveType.Char -> "0" else -> "ZERO" } } else { @@ -399,69 +414,92 @@ object CommonArrays { } fun f_asList() = f("asList()") { - only(ArraysOfObjects, ArraysOfPrimitives) + only(ArraysOfObjects) doc { "Returns a [List] that wraps the original array." } returns("List") - body(Platform.JVM, ArraysOfObjects) { + body(Platform.JVM) { """ return ArraysUtilJVM.asList(this) """ } - body(Platform.JS, ArraysOfObjects) { + body(Platform.JS) { """ return ArrayList(this.unsafeCast>()) """ } + } - body(Platform.JVM, ArraysOfPrimitives) { - """ - return object : AbstractList(), RandomAccess { - override val size: Int get() = this@asList.size - override fun isEmpty(): Boolean = this@asList.isEmpty() - override fun contains(element: T): Boolean = this@asList.contains(element) - override fun get(index: Int): T = this@asList[index] - override fun indexOf(element: T): Int = this@asList.indexOf(element) - override fun lastIndexOf(element: T): Int = this@asList.lastIndexOf(element) + fun f_asListPrimitives() = + PrimitiveType.defaultPrimitives.map { primitive -> + f("asList()") { + only(ArraysOfPrimitives) + only(primitive) + doc { "Returns a [List] that wraps the original array." } + returns("List") + + val objectLiteralImpl = """ + return object : AbstractList(), RandomAccess { + override val size: Int get() = this@asList.size + override fun isEmpty(): Boolean = this@asList.isEmpty() + override fun contains(element: T): Boolean = this@asList.contains(element) + override fun get(index: Int): T = this@asList[index] + override fun indexOf(element: T): Int = this@asList.indexOf(element) + override fun lastIndexOf(element: T): Int = this@asList.lastIndexOf(element) + } + """ + + body(Platform.JVM) { objectLiteralImpl } + + if (primitive == PrimitiveType.Char) { + body(Platform.JS) { objectLiteralImpl } + } + else { + inline(Platform.JS, Inline.Yes, ArraysOfPrimitives) + body(Platform.JS) { "return this.unsafeCast>().asList()" } + } + } } - """ - } + fun f_toTypedArray() = + PrimitiveType.defaultPrimitives.map { primitive -> + f("toTypedArray()") { + only(ArraysOfPrimitives) + only(primitive) + returns("Array") + doc { + """ + Returns a *typed* object array containing all of the elements of this primitive array. + """ + } + body(Platform.JVM) { + """ + val result = arrayOfNulls(size) + for (index in indices) + result[index] = this[index] + @Suppress("UNCHECKED_CAST") + return result as Array + """ + } - inline(Platform.JS, Inline.Yes, ArraysOfPrimitives) - body(Platform.JS, ArraysOfPrimitives) {"""return this.unsafeCast>().asList()"""} + if (primitive == PrimitiveType.Char) { + body(Platform.JS) { "return Array(size, { i -> this[i] })" } + } + else { + body(Platform.JS) { "return copyOf().unsafeCast>()" } + } + } + } - } - - fun f_toTypedArray() = f("toTypedArray()") { - only(ArraysOfPrimitives) - returns("Array") - doc { - """ - Returns a *typed* object array containing all of the elements of this primitive array. - """ - } - body(Platform.JVM) { - """ - val result = arrayOfNulls(size) - for (index in indices) - result[index] = this[index] - @Suppress("UNCHECKED_CAST") - return result as Array - """ - } - body(Platform.JS) { - """ - return copyOf().unsafeCast>() - """ - } - } // TODO: use reflection later to get all functions of matching type fun templates() = - listOf(f_plusElement(), f_plusElementOperator(), f_plusCollection(), f_plusArray()) + - listOf(f_copyOf(), f_copyOfRange()) + + listOf(f_plusElement()) + + f_plusElementOperator() + + listOf(f_plusCollection(), f_plusArray(), f_copyOf(), f_copyOfRange()) + f_copyOfResized() + f_sortPrimitives() + - listOf(f_sort(), f_sortWith(), f_asList(), f_toTypedArray()) + listOf(f_sort(), f_sortWith(), f_asList()) + + f_asListPrimitives() + + f_toTypedArray() } \ No newline at end of file