Apply @OnlyInputTypes on type parameter for contains, indexOf, lastIndexOf extensions for Iterables, Sequences and Arrays instead of @NoInfer on element parameter.

Provide covariant extensions annotated with @OnlyInputTypes:
 - Collection<T>: containsAll(Collection<T>),
 - MutableCollection<out T>: remove(T), removeAll, retainAll (Collection<T>),
 - List<T>: indexOf(T), lastIndexOf(T)
 - Map<out K, V>: get(K), containsKey(K), contains(K)
 - Map<K, V>: containsValue(V)
 - MutableMap<out K, V>: remove(K)
All *Raw extensions are deprecated.
This commit is contained in:
Ilya Gorbunov
2015-11-22 20:55:54 +03:00
parent f6616e6e42
commit a25f23a286
7 changed files with 161 additions and 80 deletions
@@ -12,7 +12,7 @@ fun elements(): List<GenericFunction> {
only(Iterables, Sequences, ArraysOfObjects, ArraysOfPrimitives)
doc { f -> "Returns `true` if [element] is found in the ${f.collection}." }
customSignature(Iterables, ArraysOfObjects, Sequences) { "contains(element: @kotlin.internal.NoInfer T)" }
typeParam("@kotlin.internal.OnlyInputTypes T")
returns("Boolean")
body(Iterables) {
"""
@@ -34,7 +34,7 @@ fun elements(): List<GenericFunction> {
only(Iterables, Sequences, ArraysOfObjects)
doc { "Returns `true` if [element] is found in the collection." }
returns("Boolean")
deprecate(Deprecation("Use 'containsRaw' instead.", "containsRaw(element)"))
deprecate { f -> with(DocExtensions) { Deprecation("${f.collection.capitalize()} and element have incompatible types. Upcast element to Any? if you're sure.", "contains(element as Any?)") } }
annotations("""
@kotlin.jvm.JvmName("containsAny")
@kotlin.internal.LowPriorityInOverloadResolution
@@ -51,15 +51,15 @@ fun elements(): List<GenericFunction> {
}
receiverAsterisk(Iterables, Sequences) { true }
inline(true)
deprecate { f -> with(DocExtensions) { Deprecation("${f.collection.capitalize()} and element have incompatible types. Upcast element to Any? if you're sure.", "contains(element as Any?)") } }
annotations("""@Suppress("NOTHING_TO_INLINE")""")
returns("Boolean")
body { "return contains<Any?>(element)" }
}
templates add f("indexOf(element: T)") {
only(Iterables, Sequences, ArraysOfObjects, ArraysOfPrimitives)
doc { f -> "Returns first index of [element], or -1 if the ${f.collection} does not contain element." }
customSignature(Iterables, ArraysOfObjects, Sequences) { "indexOf(element: @kotlin.internal.NoInfer T)" }
typeParam("@kotlin.internal.OnlyInputTypes T")
returns("Int")
body { f ->
"""
@@ -108,7 +108,7 @@ fun elements(): List<GenericFunction> {
only(Iterables, Sequences, ArraysOfObjects)
doc { "Returns first index of [element], or -1 if the collection does not contain element." }
returns("Int")
deprecate(Deprecation("Use 'indexOfRaw' instead.", "indexOfRaw(element)"))
deprecate { f -> with(DocExtensions) { Deprecation("${f.collection.capitalize()} and element have incompatible types. Upcast element to Any? if you're sure.", "indexOf(element as Any?)") } }
annotations("""
@kotlin.jvm.JvmName("indexOfAny")
@kotlin.internal.LowPriorityInOverloadResolution
@@ -126,16 +126,16 @@ fun elements(): List<GenericFunction> {
}
receiverAsterisk(Iterables, Sequences) { true }
inline(true)
deprecate { f -> with(DocExtensions) { Deprecation("${f.collection.capitalize()} and element have incompatible types. Upcast element to Any? if you're sure.", "indexOf(element as Any?)") } }
annotations("""@Suppress("NOTHING_TO_INLINE")""")
returns("Int")
body { "return indexOf<Any?>(element)" }
body(Lists) { "return (this as List<Any?>).indexOf(element)" }
}
templates add f("lastIndexOf(element: T)") {
only(Iterables, Sequences, ArraysOfObjects, ArraysOfPrimitives)
doc { f -> "Returns last index of [element], or -1 if the ${f.collection} does not contain element." }
customSignature(Iterables, ArraysOfObjects, Sequences) { "lastIndexOf(element: @kotlin.internal.NoInfer T)" }
typeParam("@kotlin.internal.OnlyInputTypes T")
returns("Int")
body { f ->
"""
@@ -185,7 +185,7 @@ fun elements(): List<GenericFunction> {
only(Iterables, Sequences, ArraysOfObjects)
doc { "Returns last index of [element], or -1 if the collection does not contain element." }
returns("Int")
deprecate(Deprecation("Use 'indexOfRaw' instead.", "indexOfRaw(element)"))
deprecate { f -> with(DocExtensions) { Deprecation("${f.collection.capitalize()} and element have incompatible types. Upcast element to Any? if you're sure.", "lastIndexOf(element as Any?)") } }
annotations("""
@kotlin.jvm.JvmName("lastIndexOfAny")
@kotlin.internal.LowPriorityInOverloadResolution
@@ -203,9 +203,9 @@ fun elements(): List<GenericFunction> {
}
receiverAsterisk(Iterables, Sequences) { true }
inline(true)
deprecate { f -> with(DocExtensions) { Deprecation("${f.collection.capitalize()} and element have incompatible types. Upcast element to Any? if you're sure.", "lastIndexOf(element as Any?)") } }
annotations("""@Suppress("NOTHING_TO_INLINE")""")
returns("Int")
body { "return lastIndexOf<Any?>(element)" }
body(Lists) { "return (this as List<Any?>).lastIndexOf(element)" }
}
@@ -316,8 +316,11 @@ class GenericFunction(val signature: String, val keyword: String = "fun") {
fun String.renderType(): String = renderType(this, receiver)
fun effectiveTypeParams(): List<String> {
fun removeAnnotations(typeParam: String) =
typeParam.replace("""^(@[\w\.]+\s+)+""".toRegex(), "")
fun getGenericTypeParameters(genericType: String) =
genericType
removeAnnotations(genericType)
.dropWhile { it != '<' }
.drop(1)
.takeWhile { it != '>' }
@@ -328,7 +331,7 @@ class GenericFunction(val signature: String, val keyword: String = "fun") {
val types = ArrayList(typeParams)
if (f == Generic) {
// ensure type parameter T, if it's not added to typeParams before
if (!types.any { it == "T" || it.startsWith("T:")}) {
if (!types.any { removeAnnotations(it).let { it == "T" || it.startsWith("T:") } }) {
types.add("T")
}
return types
@@ -336,7 +339,7 @@ class GenericFunction(val signature: String, val keyword: String = "fun") {
else if (primitive == null && f != Strings && f != CharSequences) {
val implicitTypeParameters = getGenericTypeParameters(receiver) + types.flatMap { getGenericTypeParameters(it) }
for (implicit in implicitTypeParameters.reversed()) {
if (implicit != "*" && !types.any { it.startsWith(implicit) || it.startsWith("reified " + implicit) }) {
if (implicit != "*" && !types.any { removeAnnotations(it).let { it.startsWith(implicit) || it.startsWith("reified " + implicit) } }) {
types.add(0, implicit)
}
}
@@ -345,7 +348,7 @@ class GenericFunction(val signature: String, val keyword: String = "fun") {
} else {
// remove T as parameter
// TODO: Substitute primitive or String instead of T in other parameters from effective types not from original typeParams
return typeParams.filter { !it.startsWith("T") }
return typeParams.filterNot { removeAnnotations(it).startsWith("T") }
}
}