Fix Array<out> variance in stdlib #KT-6482 Fixed

This commit is contained in:
Ilya Ryzhenkov
2014-12-22 23:08:41 +03:00
parent 377988cb7b
commit 4cd2ba1e30
11 changed files with 66 additions and 61 deletions
+2 -2
View File
@@ -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 <T : Any> Array<T?>.filterNotNull(): List<T> {
public fun <T : Any> Array<out T?>.filterNotNull(): List<T> {
return filterNotNullTo(ArrayList<T>())
}
@@ -543,7 +543,7 @@ public fun <T : Any> Stream<T?>.filterNotNull(): Stream<T> {
/**
* Appends all elements that are not null to the given *destination*
*/
public fun <C : MutableCollection<in T>, T : Any> Array<T?>.filterNotNullTo(destination: C): C {
public fun <C : MutableCollection<in T>, T : Any> Array<out T?>.filterNotNullTo(destination: C): C {
for (element in this) if (element != null) destination.add(element)
return destination
}
+32 -32
View File
@@ -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 <T, R, V> Array<out T>.merge(array: Array<R>, transform: (T, R) -> V): List<V> {
public inline fun <T, R, V> Array<out T>.merge(array: Array<out R>, transform: (T, R) -> V): List<V> {
val first = iterator()
val second = array.iterator()
val list = arrayListOf<V>()
@@ -23,7 +23,7 @@ public inline fun <T, R, V> Array<out T>.merge(array: Array<R>, 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 <R, V> BooleanArray.merge(array: Array<R>, transform: (Boolean, R) -> V): List<V> {
public inline fun <R, V> BooleanArray.merge(array: Array<out R>, transform: (Boolean, R) -> V): List<V> {
val first = iterator()
val second = array.iterator()
val list = arrayListOf<V>()
@@ -36,7 +36,7 @@ public inline fun <R, V> BooleanArray.merge(array: Array<R>, 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 <R, V> ByteArray.merge(array: Array<R>, transform: (Byte, R) -> V): List<V> {
public inline fun <R, V> ByteArray.merge(array: Array<out R>, transform: (Byte, R) -> V): List<V> {
val first = iterator()
val second = array.iterator()
val list = arrayListOf<V>()
@@ -49,7 +49,7 @@ public inline fun <R, V> ByteArray.merge(array: Array<R>, 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 <R, V> CharArray.merge(array: Array<R>, transform: (Char, R) -> V): List<V> {
public inline fun <R, V> CharArray.merge(array: Array<out R>, transform: (Char, R) -> V): List<V> {
val first = iterator()
val second = array.iterator()
val list = arrayListOf<V>()
@@ -62,7 +62,7 @@ public inline fun <R, V> CharArray.merge(array: Array<R>, 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 <R, V> DoubleArray.merge(array: Array<R>, transform: (Double, R) -> V): List<V> {
public inline fun <R, V> DoubleArray.merge(array: Array<out R>, transform: (Double, R) -> V): List<V> {
val first = iterator()
val second = array.iterator()
val list = arrayListOf<V>()
@@ -75,7 +75,7 @@ public inline fun <R, V> DoubleArray.merge(array: Array<R>, 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 <R, V> FloatArray.merge(array: Array<R>, transform: (Float, R) -> V): List<V> {
public inline fun <R, V> FloatArray.merge(array: Array<out R>, transform: (Float, R) -> V): List<V> {
val first = iterator()
val second = array.iterator()
val list = arrayListOf<V>()
@@ -88,7 +88,7 @@ public inline fun <R, V> FloatArray.merge(array: Array<R>, 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 <R, V> IntArray.merge(array: Array<R>, transform: (Int, R) -> V): List<V> {
public inline fun <R, V> IntArray.merge(array: Array<out R>, transform: (Int, R) -> V): List<V> {
val first = iterator()
val second = array.iterator()
val list = arrayListOf<V>()
@@ -101,7 +101,7 @@ public inline fun <R, V> IntArray.merge(array: Array<R>, 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 <R, V> LongArray.merge(array: Array<R>, transform: (Long, R) -> V): List<V> {
public inline fun <R, V> LongArray.merge(array: Array<out R>, transform: (Long, R) -> V): List<V> {
val first = iterator()
val second = array.iterator()
val list = arrayListOf<V>()
@@ -114,7 +114,7 @@ public inline fun <R, V> LongArray.merge(array: Array<R>, 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 <R, V> ShortArray.merge(array: Array<R>, transform: (Short, R) -> V): List<V> {
public inline fun <R, V> ShortArray.merge(array: Array<out R>, transform: (Short, R) -> V): List<V> {
val first = iterator()
val second = array.iterator()
val list = arrayListOf<V>()
@@ -127,7 +127,7 @@ public inline fun <R, V> ShortArray.merge(array: Array<R>, 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 <T, R, V> Iterable<T>.merge(array: Array<R>, transform: (T, R) -> V): List<V> {
public inline fun <T, R, V> Iterable<T>.merge(array: Array<out R>, transform: (T, R) -> V): List<V> {
val first = iterator()
val second = array.iterator()
val list = arrayListOf<V>()
@@ -140,7 +140,7 @@ public inline fun <T, R, V> Iterable<T>.merge(array: Array<R>, 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 <R, V> String.merge(array: Array<R>, transform: (Char, R) -> V): List<V> {
public inline fun <R, V> String.merge(array: Array<out R>, transform: (Char, R) -> V): List<V> {
val first = iterator()
val second = array.iterator()
val list = arrayListOf<V>()
@@ -519,7 +519,7 @@ public inline fun String.partition(predicate: (Char) -> Boolean): Pair<String, S
/**
* Returns a list containing all elements of original collection and then all elements of the given *collection*
*/
public fun <T> Array<out T>.plus(array: Array<T>): List<T> {
public fun <T> Array<out T>.plus(array: Array<out T>): List<T> {
val answer = toArrayList()
answer.addAll(array)
return answer
@@ -528,7 +528,7 @@ public fun <T> Array<out T>.plus(array: Array<T>): List<T> {
/**
* Returns a list containing all elements of original collection and then all elements of the given *collection*
*/
public fun BooleanArray.plus(array: Array<Boolean>): List<Boolean> {
public fun BooleanArray.plus(array: Array<out Boolean>): List<Boolean> {
val answer = toArrayList()
answer.addAll(array)
return answer
@@ -537,7 +537,7 @@ public fun BooleanArray.plus(array: Array<Boolean>): List<Boolean> {
/**
* Returns a list containing all elements of original collection and then all elements of the given *collection*
*/
public fun ByteArray.plus(array: Array<Byte>): List<Byte> {
public fun ByteArray.plus(array: Array<out Byte>): List<Byte> {
val answer = toArrayList()
answer.addAll(array)
return answer
@@ -546,7 +546,7 @@ public fun ByteArray.plus(array: Array<Byte>): List<Byte> {
/**
* Returns a list containing all elements of original collection and then all elements of the given *collection*
*/
public fun CharArray.plus(array: Array<Char>): List<Char> {
public fun CharArray.plus(array: Array<out Char>): List<Char> {
val answer = toArrayList()
answer.addAll(array)
return answer
@@ -555,7 +555,7 @@ public fun CharArray.plus(array: Array<Char>): List<Char> {
/**
* Returns a list containing all elements of original collection and then all elements of the given *collection*
*/
public fun DoubleArray.plus(array: Array<Double>): List<Double> {
public fun DoubleArray.plus(array: Array<out Double>): List<Double> {
val answer = toArrayList()
answer.addAll(array)
return answer
@@ -564,7 +564,7 @@ public fun DoubleArray.plus(array: Array<Double>): List<Double> {
/**
* Returns a list containing all elements of original collection and then all elements of the given *collection*
*/
public fun FloatArray.plus(array: Array<Float>): List<Float> {
public fun FloatArray.plus(array: Array<out Float>): List<Float> {
val answer = toArrayList()
answer.addAll(array)
return answer
@@ -573,7 +573,7 @@ public fun FloatArray.plus(array: Array<Float>): List<Float> {
/**
* Returns a list containing all elements of original collection and then all elements of the given *collection*
*/
public fun IntArray.plus(array: Array<Int>): List<Int> {
public fun IntArray.plus(array: Array<out Int>): List<Int> {
val answer = toArrayList()
answer.addAll(array)
return answer
@@ -582,7 +582,7 @@ public fun IntArray.plus(array: Array<Int>): List<Int> {
/**
* Returns a list containing all elements of original collection and then all elements of the given *collection*
*/
public fun LongArray.plus(array: Array<Long>): List<Long> {
public fun LongArray.plus(array: Array<out Long>): List<Long> {
val answer = toArrayList()
answer.addAll(array)
return answer
@@ -591,7 +591,7 @@ public fun LongArray.plus(array: Array<Long>): List<Long> {
/**
* Returns a list containing all elements of original collection and then all elements of the given *collection*
*/
public fun ShortArray.plus(array: Array<Short>): List<Short> {
public fun ShortArray.plus(array: Array<out Short>): List<Short> {
val answer = toArrayList()
answer.addAll(array)
return answer
@@ -600,7 +600,7 @@ public fun ShortArray.plus(array: Array<Short>): List<Short> {
/**
* Returns a list containing all elements of original collection and then all elements of the given *collection*
*/
public fun <T> Iterable<T>.plus(array: Array<T>): List<T> {
public fun <T> Iterable<T>.plus(array: Array<out T>): List<T> {
val answer = toArrayList()
answer.addAll(array)
return answer
@@ -810,77 +810,77 @@ public fun <T> Stream<T>.plus(stream: Stream<T>): Stream<T> {
/**
* Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection.
*/
public fun <T, R> Array<out T>.zip(array: Array<R>): List<Pair<T, R>> {
public fun <T, R> Array<out T>.zip(array: Array<out R>): List<Pair<T, R>> {
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 <R> BooleanArray.zip(array: Array<R>): List<Pair<Boolean, R>> {
public fun <R> BooleanArray.zip(array: Array<out R>): List<Pair<Boolean, R>> {
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 <R> ByteArray.zip(array: Array<R>): List<Pair<Byte, R>> {
public fun <R> ByteArray.zip(array: Array<out R>): List<Pair<Byte, R>> {
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 <R> CharArray.zip(array: Array<R>): List<Pair<Char, R>> {
public fun <R> CharArray.zip(array: Array<out R>): List<Pair<Char, R>> {
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 <R> DoubleArray.zip(array: Array<R>): List<Pair<Double, R>> {
public fun <R> DoubleArray.zip(array: Array<out R>): List<Pair<Double, R>> {
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 <R> FloatArray.zip(array: Array<R>): List<Pair<Float, R>> {
public fun <R> FloatArray.zip(array: Array<out R>): List<Pair<Float, R>> {
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 <R> IntArray.zip(array: Array<R>): List<Pair<Int, R>> {
public fun <R> IntArray.zip(array: Array<out R>): List<Pair<Int, R>> {
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 <R> LongArray.zip(array: Array<R>): List<Pair<Long, R>> {
public fun <R> LongArray.zip(array: Array<out R>): List<Pair<Long, R>> {
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 <R> ShortArray.zip(array: Array<R>): List<Pair<Short, R>> {
public fun <R> ShortArray.zip(array: Array<out R>): List<Pair<Short, R>> {
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 <T, R> Iterable<T>.zip(array: Array<R>): List<Pair<T, R>> {
public fun <T, R> Iterable<T>.zip(array: Array<out R>): List<Pair<T, R>> {
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 <R> String.zip(array: Array<R>): List<Pair<Char, R>> {
public fun <R> String.zip(array: Array<out R>): List<Pair<Char, R>> {
return merge(array) { (t1, t2) -> t1 to t2 }
}
+2 -2
View File
@@ -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 <T : Any> Array<T?>.requireNoNulls(): Array<T> {
public fun <T : Any> Array<out T?>.requireNoNulls(): Array<out T> {
for (element in this) {
if (element == null) {
throw IllegalArgumentException("null element found in $this")
}
}
return this as Array<T>
return this as Array<out T>
}
/**
+2 -2
View File
@@ -790,7 +790,7 @@ public inline fun <R, C : MutableCollection<in R>> 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 <T : Any, R> Array<T?>.mapNotNull(transform: (T) -> R): List<R> {
public inline fun <T : Any, R> Array<out T?>.mapNotNull(transform: (T) -> R): List<R> {
return mapNotNullTo(ArrayList<R>(), transform)
}
@@ -812,7 +812,7 @@ public fun <T : Any, R> Stream<T?>.mapNotNull(transform: (T) -> R): Stream<R> {
* Appends transformed non-null elements of original collection using the given *transform* function
* to the given *destination*
*/
public inline fun <T : Any, R, C : MutableCollection<in R>> Array<T?>.mapNotNullTo(destination: C, transform: (T) -> R): C {
public inline fun <T : Any, R, C : MutableCollection<in R>> Array<out T?>.mapNotNullTo(destination: C, transform: (T) -> R): C {
for (element in this) {
if (element != null) {
destination.add(transform(element))
@@ -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 <reified T> Array<T>?.orEmpty(): Array<T> = this ?: array<T>()
public inline fun <reified T> Array<out T>?.orEmpty(): Array<out T> = this ?: array<T>()
@@ -20,7 +20,7 @@ public fun <T> MutableCollection<in T>.addAll(stream: Stream<T>) {
/**
* Adds all elements of the given *array* to this [[MutableCollection]]
*/
public fun <T> MutableCollection<in T>.addAll(array: Array<T>) {
public fun <T> MutableCollection<in T>.addAll(array: Array<out T>) {
for (item in array) add(item)
}
@@ -44,7 +44,7 @@ public fun <T> MutableCollection<in T>.removeAll(stream: Stream<T>) {
/**
* Removes all elements of the given *array* from this [[MutableCollection]]
*/
public fun <T> MutableCollection<in T>.removeAll(array: Array<T>) {
public fun <T> MutableCollection<in T>.removeAll(array: Array<out T>) {
for (item in array) remove(item)
}
@@ -61,6 +61,6 @@ public fun <T> MutableCollection<in T>.retainAll(iterable: Iterable<T>) {
/**
* Retains only elements of the given *array* in this [[MutableCollection]]
*/
public fun <T> MutableCollection<in T>.retainAll(array: Array<T>) {
public fun <T> MutableCollection<in T>.retainAll(array: Array<out T>) {
retainAll(array.toSet())
}
@@ -200,13 +200,16 @@ class ArraysJVMTest {
test fun orEmptyNull() {
val x: Array<String>? = null
val xArray: Array<String> = x.orEmpty()
val y: Array<out String>? = null
val xArray = x.orEmpty()
val yArray = y.orEmpty()
expect(0) { xArray.size() }
expect(0) { yArray.size() }
}
test fun orEmptyNotNull() {
val x: Array<String>? = array("1", "2")
val xArray: Array<String> = x.orEmpty()
val xArray = x.orEmpty()
expect(2) { xArray.size() }
expect("1") { xArray[0] }
expect("2") { xArray[1] }
@@ -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 } }
@@ -39,8 +39,8 @@ class GenericFunction(val signature: String) : Comparable<GenericFunction> {
var receiverAsterisk = false
val inlineFamilies = HashMap<Family, Boolean>()
val buildFamilies = HashSet<Family>(defaultFamilies.toList())
private val buildPrimitives = HashSet<PrimitiveType>(PrimitiveType.values().toList())
val buildFamilies = HashSet(defaultFamilies.toList())
private val buildPrimitives = HashSet(PrimitiveType.values().toList())
var deprecate: String = ""
val deprecates = HashMap<Family, String>()
@@ -106,7 +106,7 @@ class GenericFunction(val signature: String) : Comparable<GenericFunction> {
}
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<GenericFunction> {
while (t.hasMoreTokens()) {
val token = t.nextToken()
answer.append(when (token) {
"SELF" -> receiver
"SELF" -> if (receiver == "Array<T>") "Array<out T>" else receiver
"PRIMITIVE" -> primitive?.name() ?: token
"SUM" -> {
when (primitive) {
@@ -257,17 +257,12 @@ class GenericFunction(val signature: String) : Comparable<GenericFunction> {
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<T>")
"Array<out T>"
else
receiver
val receiverType = (when (receiver) {
"Array<T>" -> if (toNullableT) "Array<out T?>" else "Array<out T>"
else -> if (toNullableT) receiver.replace("T>", "T?>") else receiver
}).renderType()
@@ -275,7 +270,7 @@ class GenericFunction(val signature: String) : Comparable<GenericFunction> {
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 {
@@ -39,7 +39,7 @@ fun generators(): List<GenericFunction> {
}
}
templates add f("plus(array: Array<T>)") {
templates add f("plus(array: Array<out T>)") {
exclude(Strings, Streams)
doc { "Returns a list containing all elements of original collection and then all elements of the given *collection*" }
returns("List<T>")
@@ -142,7 +142,7 @@ fun generators(): List<GenericFunction> {
}
}
templates add f("merge(array: Array<R>, transform: (T, R) -> V)") {
templates add f("merge(array: Array<out R>, transform: (T, R) -> V)") {
exclude(Streams)
doc {
"""
@@ -222,7 +222,7 @@ fun generators(): List<GenericFunction> {
}
}
templates add f("zip(array: Array<R>)") {
templates add f("zip(array: Array<out R>)") {
exclude(Streams)
doc {
"""
@@ -9,6 +9,7 @@ fun specialJVM(): List<GenericFunction> {
only(ArraysOfObjects, ArraysOfPrimitives)
doc { "Returns new array which is a copy of range of original array" }
returns("SELF")
returns(ArraysOfObjects) { "Array<T>" }
body {
"return Arrays.copyOfRange(this, from, to)"
}
@@ -18,6 +19,7 @@ fun specialJVM(): List<GenericFunction> {
only(ArraysOfObjects, ArraysOfPrimitives)
doc { "Returns new array which is a copy of the original array" }
returns("SELF")
returns(ArraysOfObjects) { "Array<T>" }
body {
"return Arrays.copyOf(this, size())"
}