Support Nothing type in typeOf

The proper support will come in KT-15518, but that would be a breaking
change even for stable Kotlin without kotlin-reflect. Before that issue
is fixed, represent Nothing in types with the Void class, and use a flag
in the no-reflect implementation to remember that it's not actually the
Void class itself.

 #KT-39166 Fixed
This commit is contained in:
Alexander Udalov
2021-07-07 13:04:59 +02:00
parent 02774fae0c
commit ddfa94e7e9
15 changed files with 338 additions and 15 deletions
@@ -0,0 +1,48 @@
// !API_VERSION: LATEST
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// FILE: box.kt
package test
import kotlin.reflect.KType
import kotlin.reflect.KTypeParameter
import kotlin.reflect.typeOf
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
class C<V>(v: V)
fun <T : Nothing?> nothingBound() =
(typeOf<C<T>>().arguments.single().type!!.classifier as KTypeParameter).upperBounds.single()
fun check(expected: String, actual: KType) {
assertEquals(expected + " (Kotlin reflection is not available)", actual.toString())
}
fun box(): String {
check("test.C<kotlin.Nothing>", typeOf<C<Nothing>>())
check("test.C<kotlin.Nothing?>", typeOf<C<Nothing?>>())
check("kotlin.Nothing?", nothingBound<Nothing?>())
// String representation of platform types does not differ from non-nullable types in the stdlib implementation (without reflect).
check("test.C<kotlin.Nothing>", returnTypeOf { C(J.platformType<Nothing>()) })
// Such type's classifier is still Void::class, until KT-15518 is fixed.
// TODO: support a special KClass instance for Nothing (KT-15518).
assertEquals(Void::class, typeOf<C<Nothing>>().arguments.single().type!!.classifier)
assertNotEquals(typeOf<C<Nothing>>(), typeOf<C<Void>>())
return "OK"
}
inline fun <reified Z> returnTypeOf(block: () -> Z) =
typeOf<Z>()
// FILE: J.java
public class J {
public static <X> X platformType() { return null; }
}
@@ -0,0 +1,44 @@
// !API_VERSION: 1.5
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// FILE: box.kt
package test
import kotlin.reflect.KType
import kotlin.reflect.KTypeParameter
import kotlin.reflect.typeOf
import kotlin.test.assertEquals
class C<V>(v: V)
fun <T : Nothing?> nothingBound() =
(typeOf<C<T>>().arguments.single().type!!.classifier as KTypeParameter).upperBounds.single()
fun check(expected: String, actual: KType) {
assertEquals(expected + " (Kotlin reflection is not available)", actual.toString())
}
fun box(): String {
check("test.C<java.lang.Void>", typeOf<C<Nothing>>())
check("test.C<java.lang.Void?>", typeOf<C<Nothing?>>())
check("java.lang.Void?", nothingBound<Nothing?>())
check("test.C<java.lang.Void>", returnTypeOf { C(J.platformType<Nothing>()) })
assertEquals(Void::class, typeOf<C<Nothing>>().arguments.single().type!!.classifier)
assertEquals(typeOf<C<Nothing>>(), typeOf<C<Void>>())
return "OK"
}
inline fun <reified Z> returnTypeOf(block: () -> Z) =
typeOf<Z>()
// FILE: J.java
public class J {
public static <X> X platformType() { return null; }
}
@@ -0,0 +1,47 @@
// !API_VERSION: LATEST
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JVM
// WITH_REFLECT
// FILE: box.kt
package test
import kotlin.reflect.KType
import kotlin.reflect.KTypeParameter
import kotlin.reflect.typeOf
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
class C<V>(v: V)
fun <T : Nothing?> nothingBound() =
(typeOf<C<T>>().arguments.single().type!!.classifier as KTypeParameter).upperBounds.single()
fun check(expected: String, actual: KType) {
assertEquals(expected, actual.toString())
}
fun box(): String {
check("test.C<kotlin.Nothing>", typeOf<C<Nothing>>())
check("test.C<kotlin.Nothing?>", typeOf<C<Nothing?>>())
check("kotlin.Nothing?", nothingBound<Nothing?>())
check("test.C<kotlin.Nothing!>", returnTypeOf { C(J.platformType<Nothing>()) })
// Such type's classifier is still Void::class, until KT-15518 is fixed.
// TODO: support a special KClass instance for Nothing (KT-15518).
assertEquals(Void::class, typeOf<C<Nothing>>().arguments.single().type!!.classifier)
assertNotEquals(typeOf<C<Nothing>>(), typeOf<C<Void>>())
return "OK"
}
inline fun <reified Z> returnTypeOf(block: () -> Z) =
typeOf<Z>()
// FILE: J.java
public class J {
public static <X> X platformType() { return null; }
}
@@ -0,0 +1,44 @@
// !API_VERSION: 1.5
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JVM
// WITH_REFLECT
// FILE: box.kt
package test
import kotlin.reflect.KType
import kotlin.reflect.KTypeParameter
import kotlin.reflect.typeOf
import kotlin.test.assertEquals
class C<V>(v: V)
fun <T : Nothing?> nothingBound() =
(typeOf<C<T>>().arguments.single().type!!.classifier as KTypeParameter).upperBounds.single()
fun check(expected: String, actual: KType) {
assertEquals(expected, actual.toString())
}
fun box(): String {
check("test.C<java.lang.Void>", typeOf<C<Nothing>>())
check("test.C<java.lang.Void?>", typeOf<C<Nothing?>>())
check("kotlin.Nothing?", nothingBound<Nothing?>())
check("test.C<java.lang.Void>", returnTypeOf { C(J.platformType<Nothing>()) })
assertEquals(Void::class, typeOf<C<Nothing>>().arguments.single().type!!.classifier)
assertEquals(typeOf<C<Nothing>>(), typeOf<C<Void>>())
return "OK"
}
inline fun <reified Z> returnTypeOf(block: () -> Z) =
typeOf<Z>()
// FILE: J.java
public class J {
public static <X> X platformType() { return null; }
}