From 4cd2ba1e30c3b6e0f44fc02eb46555d5b4f36c46 Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Mon, 22 Dec 2014 23:08:41 +0300 Subject: [PATCH] Fix Array variance in stdlib #KT-6482 Fixed --- libraries/stdlib/src/generated/_Filtering.kt | 4 +- libraries/stdlib/src/generated/_Generators.kt | 64 +++++++++---------- libraries/stdlib/src/generated/_Guards.kt | 4 +- libraries/stdlib/src/generated/_Mapping.kt | 4 +- .../src/kotlin/collections/ArraysJVM.kt | 2 +- .../kotlin/collections/MutableCollections.kt | 6 +- .../stdlib/test/collections/ArraysJVMTest.kt | 7 +- .../stdlib/test/collections/ArraysTest.kt | 5 ++ .../kotlin-stdlib-gen/src/templates/Engine.kt | 23 +++---- .../src/templates/Generators.kt | 6 +- .../src/templates/SpecialJVM.kt | 2 + 11 files changed, 66 insertions(+), 61 deletions(-) diff --git a/libraries/stdlib/src/generated/_Filtering.kt b/libraries/stdlib/src/generated/_Filtering.kt index e61164a49f6..9674752548c 100644 --- a/libraries/stdlib/src/generated/_Filtering.kt +++ b/libraries/stdlib/src/generated/_Filtering.kt @@ -522,7 +522,7 @@ public inline fun String.filterNot(predicate: (Char) -> Boolean): String { /** * Returns a list containing all elements that are not null */ -public fun Array.filterNotNull(): List { +public fun Array.filterNotNull(): List { return filterNotNullTo(ArrayList()) } @@ -543,7 +543,7 @@ public fun Stream.filterNotNull(): Stream { /** * Appends all elements that are not null to the given *destination* */ -public fun , T : Any> Array.filterNotNullTo(destination: C): C { +public fun , T : Any> Array.filterNotNullTo(destination: C): C { for (element in this) if (element != null) destination.add(element) return destination } diff --git a/libraries/stdlib/src/generated/_Generators.kt b/libraries/stdlib/src/generated/_Generators.kt index 4949aa2280c..21b8cc77c28 100644 --- a/libraries/stdlib/src/generated/_Generators.kt +++ b/libraries/stdlib/src/generated/_Generators.kt @@ -10,7 +10,7 @@ import java.util.* /** * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. */ -public inline fun Array.merge(array: Array, transform: (T, R) -> V): List { +public inline fun Array.merge(array: Array, transform: (T, R) -> V): List { val first = iterator() val second = array.iterator() val list = arrayListOf() @@ -23,7 +23,7 @@ public inline fun Array.merge(array: Array, transform: (T, R /** * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. */ -public inline fun BooleanArray.merge(array: Array, transform: (Boolean, R) -> V): List { +public inline fun BooleanArray.merge(array: Array, transform: (Boolean, R) -> V): List { val first = iterator() val second = array.iterator() val list = arrayListOf() @@ -36,7 +36,7 @@ public inline fun BooleanArray.merge(array: Array, transform: (Boolean /** * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. */ -public inline fun ByteArray.merge(array: Array, transform: (Byte, R) -> V): List { +public inline fun ByteArray.merge(array: Array, transform: (Byte, R) -> V): List { val first = iterator() val second = array.iterator() val list = arrayListOf() @@ -49,7 +49,7 @@ public inline fun ByteArray.merge(array: Array, transform: (Byte, R) - /** * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. */ -public inline fun CharArray.merge(array: Array, transform: (Char, R) -> V): List { +public inline fun CharArray.merge(array: Array, transform: (Char, R) -> V): List { val first = iterator() val second = array.iterator() val list = arrayListOf() @@ -62,7 +62,7 @@ public inline fun CharArray.merge(array: Array, transform: (Char, R) - /** * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. */ -public inline fun DoubleArray.merge(array: Array, transform: (Double, R) -> V): List { +public inline fun DoubleArray.merge(array: Array, transform: (Double, R) -> V): List { val first = iterator() val second = array.iterator() val list = arrayListOf() @@ -75,7 +75,7 @@ public inline fun DoubleArray.merge(array: Array, transform: (Double, /** * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. */ -public inline fun FloatArray.merge(array: Array, transform: (Float, R) -> V): List { +public inline fun FloatArray.merge(array: Array, transform: (Float, R) -> V): List { val first = iterator() val second = array.iterator() val list = arrayListOf() @@ -88,7 +88,7 @@ public inline fun FloatArray.merge(array: Array, transform: (Float, R) /** * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. */ -public inline fun IntArray.merge(array: Array, transform: (Int, R) -> V): List { +public inline fun IntArray.merge(array: Array, transform: (Int, R) -> V): List { val first = iterator() val second = array.iterator() val list = arrayListOf() @@ -101,7 +101,7 @@ public inline fun IntArray.merge(array: Array, transform: (Int, R) -> /** * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. */ -public inline fun LongArray.merge(array: Array, transform: (Long, R) -> V): List { +public inline fun LongArray.merge(array: Array, transform: (Long, R) -> V): List { val first = iterator() val second = array.iterator() val list = arrayListOf() @@ -114,7 +114,7 @@ public inline fun LongArray.merge(array: Array, transform: (Long, R) - /** * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. */ -public inline fun ShortArray.merge(array: Array, transform: (Short, R) -> V): List { +public inline fun ShortArray.merge(array: Array, transform: (Short, R) -> V): List { val first = iterator() val second = array.iterator() val list = arrayListOf() @@ -127,7 +127,7 @@ public inline fun ShortArray.merge(array: Array, transform: (Short, R) /** * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. */ -public inline fun Iterable.merge(array: Array, transform: (T, R) -> V): List { +public inline fun Iterable.merge(array: Array, transform: (T, R) -> V): List { val first = iterator() val second = array.iterator() val list = arrayListOf() @@ -140,7 +140,7 @@ public inline fun Iterable.merge(array: Array, transform: (T, R) /** * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. */ -public inline fun String.merge(array: Array, transform: (Char, R) -> V): List { +public inline fun String.merge(array: Array, transform: (Char, R) -> V): List { val first = iterator() val second = array.iterator() val list = arrayListOf() @@ -519,7 +519,7 @@ public inline fun String.partition(predicate: (Char) -> Boolean): Pair Array.plus(array: Array): List { +public fun Array.plus(array: Array): List { val answer = toArrayList() answer.addAll(array) return answer @@ -528,7 +528,7 @@ public fun Array.plus(array: Array): List { /** * Returns a list containing all elements of original collection and then all elements of the given *collection* */ -public fun BooleanArray.plus(array: Array): List { +public fun BooleanArray.plus(array: Array): List { val answer = toArrayList() answer.addAll(array) return answer @@ -537,7 +537,7 @@ public fun BooleanArray.plus(array: Array): List { /** * Returns a list containing all elements of original collection and then all elements of the given *collection* */ -public fun ByteArray.plus(array: Array): List { +public fun ByteArray.plus(array: Array): List { val answer = toArrayList() answer.addAll(array) return answer @@ -546,7 +546,7 @@ public fun ByteArray.plus(array: Array): List { /** * Returns a list containing all elements of original collection and then all elements of the given *collection* */ -public fun CharArray.plus(array: Array): List { +public fun CharArray.plus(array: Array): List { val answer = toArrayList() answer.addAll(array) return answer @@ -555,7 +555,7 @@ public fun CharArray.plus(array: Array): List { /** * Returns a list containing all elements of original collection and then all elements of the given *collection* */ -public fun DoubleArray.plus(array: Array): List { +public fun DoubleArray.plus(array: Array): List { val answer = toArrayList() answer.addAll(array) return answer @@ -564,7 +564,7 @@ public fun DoubleArray.plus(array: Array): List { /** * Returns a list containing all elements of original collection and then all elements of the given *collection* */ -public fun FloatArray.plus(array: Array): List { +public fun FloatArray.plus(array: Array): List { val answer = toArrayList() answer.addAll(array) return answer @@ -573,7 +573,7 @@ public fun FloatArray.plus(array: Array): List { /** * Returns a list containing all elements of original collection and then all elements of the given *collection* */ -public fun IntArray.plus(array: Array): List { +public fun IntArray.plus(array: Array): List { val answer = toArrayList() answer.addAll(array) return answer @@ -582,7 +582,7 @@ public fun IntArray.plus(array: Array): List { /** * Returns a list containing all elements of original collection and then all elements of the given *collection* */ -public fun LongArray.plus(array: Array): List { +public fun LongArray.plus(array: Array): List { val answer = toArrayList() answer.addAll(array) return answer @@ -591,7 +591,7 @@ public fun LongArray.plus(array: Array): List { /** * Returns a list containing all elements of original collection and then all elements of the given *collection* */ -public fun ShortArray.plus(array: Array): List { +public fun ShortArray.plus(array: Array): List { val answer = toArrayList() answer.addAll(array) return answer @@ -600,7 +600,7 @@ public fun ShortArray.plus(array: Array): List { /** * Returns a list containing all elements of original collection and then all elements of the given *collection* */ -public fun Iterable.plus(array: Array): List { +public fun Iterable.plus(array: Array): List { val answer = toArrayList() answer.addAll(array) return answer @@ -810,77 +810,77 @@ public fun Stream.plus(stream: Stream): Stream { /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun Array.zip(array: Array): List> { +public fun Array.zip(array: Array): List> { return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun BooleanArray.zip(array: Array): List> { +public fun BooleanArray.zip(array: Array): List> { return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun ByteArray.zip(array: Array): List> { +public fun ByteArray.zip(array: Array): List> { return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun CharArray.zip(array: Array): List> { +public fun CharArray.zip(array: Array): List> { return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun DoubleArray.zip(array: Array): List> { +public fun DoubleArray.zip(array: Array): List> { return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun FloatArray.zip(array: Array): List> { +public fun FloatArray.zip(array: Array): List> { return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun IntArray.zip(array: Array): List> { +public fun IntArray.zip(array: Array): List> { return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun LongArray.zip(array: Array): List> { +public fun LongArray.zip(array: Array): List> { return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun ShortArray.zip(array: Array): List> { +public fun ShortArray.zip(array: Array): List> { return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun Iterable.zip(array: Array): List> { +public fun Iterable.zip(array: Array): List> { return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun String.zip(array: Array): List> { +public fun String.zip(array: Array): List> { return merge(array) { (t1, t2) -> t1 to t2 } } diff --git a/libraries/stdlib/src/generated/_Guards.kt b/libraries/stdlib/src/generated/_Guards.kt index 82d1664be8f..9295acac949 100644 --- a/libraries/stdlib/src/generated/_Guards.kt +++ b/libraries/stdlib/src/generated/_Guards.kt @@ -10,13 +10,13 @@ import java.util.* /** * Returns an original collection containing all the non-*null* elements, throwing an [[IllegalArgumentException]] if there are any null elements */ -public fun Array.requireNoNulls(): Array { +public fun Array.requireNoNulls(): Array { for (element in this) { if (element == null) { throw IllegalArgumentException("null element found in $this") } } - return this as Array + return this as Array } /** diff --git a/libraries/stdlib/src/generated/_Mapping.kt b/libraries/stdlib/src/generated/_Mapping.kt index 775428ea960..894b7d7c0ef 100644 --- a/libraries/stdlib/src/generated/_Mapping.kt +++ b/libraries/stdlib/src/generated/_Mapping.kt @@ -790,7 +790,7 @@ public inline fun > String.mapIndexedTo(destinati /** * Returns a list containing the results of applying the given *transform* function to each non-null element of the original collection */ -public inline fun Array.mapNotNull(transform: (T) -> R): List { +public inline fun Array.mapNotNull(transform: (T) -> R): List { return mapNotNullTo(ArrayList(), transform) } @@ -812,7 +812,7 @@ public fun Stream.mapNotNull(transform: (T) -> R): Stream { * Appends transformed non-null elements of original collection using the given *transform* function * to the given *destination* */ -public inline fun > Array.mapNotNullTo(destination: C, transform: (T) -> R): C { +public inline fun > Array.mapNotNullTo(destination: C, transform: (T) -> R): C { for (element in this) { if (element != null) { destination.add(transform(element)) diff --git a/libraries/stdlib/src/kotlin/collections/ArraysJVM.kt b/libraries/stdlib/src/kotlin/collections/ArraysJVM.kt index a106a0568ce..6c360a8a5d2 100644 --- a/libraries/stdlib/src/kotlin/collections/ArraysJVM.kt +++ b/libraries/stdlib/src/kotlin/collections/ArraysJVM.kt @@ -37,4 +37,4 @@ public fun ByteArray.toString(charset: Charset): String = String(this, charset) throw UnsupportedOperationException() /** Returns the List if its not null otherwise returns the empty list */ -public inline fun Array?.orEmpty(): Array = this ?: array() +public inline fun Array?.orEmpty(): Array = this ?: array() diff --git a/libraries/stdlib/src/kotlin/collections/MutableCollections.kt b/libraries/stdlib/src/kotlin/collections/MutableCollections.kt index 0aa9191f8d7..3cc6e0aebae 100644 --- a/libraries/stdlib/src/kotlin/collections/MutableCollections.kt +++ b/libraries/stdlib/src/kotlin/collections/MutableCollections.kt @@ -20,7 +20,7 @@ public fun MutableCollection.addAll(stream: Stream) { /** * Adds all elements of the given *array* to this [[MutableCollection]] */ -public fun MutableCollection.addAll(array: Array) { +public fun MutableCollection.addAll(array: Array) { for (item in array) add(item) } @@ -44,7 +44,7 @@ public fun MutableCollection.removeAll(stream: Stream) { /** * Removes all elements of the given *array* from this [[MutableCollection]] */ -public fun MutableCollection.removeAll(array: Array) { +public fun MutableCollection.removeAll(array: Array) { for (item in array) remove(item) } @@ -61,6 +61,6 @@ public fun MutableCollection.retainAll(iterable: Iterable) { /** * Retains only elements of the given *array* in this [[MutableCollection]] */ -public fun MutableCollection.retainAll(array: Array) { +public fun MutableCollection.retainAll(array: Array) { retainAll(array.toSet()) } diff --git a/libraries/stdlib/test/collections/ArraysJVMTest.kt b/libraries/stdlib/test/collections/ArraysJVMTest.kt index 4fe72d09029..c1e4b321be3 100644 --- a/libraries/stdlib/test/collections/ArraysJVMTest.kt +++ b/libraries/stdlib/test/collections/ArraysJVMTest.kt @@ -200,13 +200,16 @@ class ArraysJVMTest { test fun orEmptyNull() { val x: Array? = null - val xArray: Array = x.orEmpty() + val y: Array? = null + val xArray = x.orEmpty() + val yArray = y.orEmpty() expect(0) { xArray.size() } + expect(0) { yArray.size() } } test fun orEmptyNotNull() { val x: Array? = array("1", "2") - val xArray: Array = x.orEmpty() + val xArray = x.orEmpty() expect(2) { xArray.size() } expect("1") { xArray[0] } expect("2") { xArray[1] } diff --git a/libraries/stdlib/test/collections/ArraysTest.kt b/libraries/stdlib/test/collections/ArraysTest.kt index 9687f90ae3a..8aa1c0fed39 100644 --- a/libraries/stdlib/test/collections/ArraysTest.kt +++ b/libraries/stdlib/test/collections/ArraysTest.kt @@ -170,6 +170,11 @@ class ArraysTest { assertEquals(listOf("1","2","3","4"), listOf("1", "2") + array("3", "4")) } + test fun plusVararg() { + fun onePlus(vararg a: String) = array("1") + a + assertEquals(listOf("1","2"), onePlus("2")) + } + test fun first() { expect(1) { array(1,2,3).first() } expect(2) { array(1,2,3).first { it % 2 == 0 } } diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Engine.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Engine.kt index 8c51e1accbe..fab7590798e 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Engine.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Engine.kt @@ -39,8 +39,8 @@ class GenericFunction(val signature: String) : Comparable { var receiverAsterisk = false val inlineFamilies = HashMap() - val buildFamilies = HashSet(defaultFamilies.toList()) - private val buildPrimitives = HashSet(PrimitiveType.values().toList()) + val buildFamilies = HashSet(defaultFamilies.toList()) + private val buildPrimitives = HashSet(PrimitiveType.values().toList()) var deprecate: String = "" val deprecates = HashMap() @@ -106,7 +106,7 @@ class GenericFunction(val signature: String) : Comparable { } fun receiverAsterisk(v: Boolean) { - receiverAsterisk = true + receiverAsterisk = v } fun inline(value: Boolean, vararg families: Family) { @@ -183,7 +183,7 @@ class GenericFunction(val signature: String) : Comparable { while (t.hasMoreTokens()) { val token = t.nextToken() answer.append(when (token) { - "SELF" -> receiver + "SELF" -> if (receiver == "Array") "Array" else receiver "PRIMITIVE" -> primitive?.name() ?: token "SUM" -> { when (primitive) { @@ -257,17 +257,12 @@ class GenericFunction(val signature: String) : Comparable { val types = effectiveTypeParams() if (!types.isEmpty()) { - builder.append(types.makeString(separator = ", ", prefix = "<", postfix = "> ").renderType()) + builder.append(types.join(separator = ", ", prefix = "<", postfix = "> ").renderType()) } - val receiverType = ( - if (toNullableT) { - receiver.replace("T>", "T?>") - } else { - if (receiver == "Array") - "Array" - else - receiver + val receiverType = (when (receiver) { + "Array" -> if (toNullableT) "Array" else "Array" + else -> if (toNullableT) receiver.replace("T>", "T?>") else receiver }).renderType() @@ -275,7 +270,7 @@ class GenericFunction(val signature: String) : Comparable { builder.append(".${signature.renderType()}: ${returnType.renderType()} {") val body = (bodies[f] ?: defaultBody).trim("\n") - val indent: Int = body.takeWhile { it == ' ' }.length + val indent: Int = body.takeWhile { it == ' ' }.length() builder.append('\n') StringReader(body).forEachLine { diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt index 1345cff7f72..2fa21cb6394 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt @@ -39,7 +39,7 @@ fun generators(): List { } } - templates add f("plus(array: Array)") { + templates add f("plus(array: Array)") { exclude(Strings, Streams) doc { "Returns a list containing all elements of original collection and then all elements of the given *collection*" } returns("List") @@ -142,7 +142,7 @@ fun generators(): List { } } - templates add f("merge(array: Array, transform: (T, R) -> V)") { + templates add f("merge(array: Array, transform: (T, R) -> V)") { exclude(Streams) doc { """ @@ -222,7 +222,7 @@ fun generators(): List { } } - templates add f("zip(array: Array)") { + templates add f("zip(array: Array)") { exclude(Streams) doc { """ diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJVM.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJVM.kt index b2a4aa3aa37..48e4ad6f0e8 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJVM.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJVM.kt @@ -9,6 +9,7 @@ fun specialJVM(): List { only(ArraysOfObjects, ArraysOfPrimitives) doc { "Returns new array which is a copy of range of original array" } returns("SELF") + returns(ArraysOfObjects) { "Array" } body { "return Arrays.copyOfRange(this, from, to)" } @@ -18,6 +19,7 @@ fun specialJVM(): List { only(ArraysOfObjects, ArraysOfPrimitives) doc { "Returns new array which is a copy of the original array" } returns("SELF") + returns(ArraysOfObjects) { "Array" } body { "return Arrays.copyOf(this, size())" }