Reflection: add KClass.{isSubclassOf,isSuperclassOf}, KType.{isSubtypeOf,isSupertypeOf}
The behavior in primitives.kt is likely to be reconsidered #KT-8998 Fixed
This commit is contained in:
+48
@@ -0,0 +1,48 @@
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.*
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.assertFalse
|
||||
|
||||
open class Klass
|
||||
interface Interface<T>
|
||||
class Bar : Interface<String>, Klass()
|
||||
|
||||
fun check(subclass: KClass<*>, superclass: KClass<*>, shouldBeSubclass: Boolean) {
|
||||
if (shouldBeSubclass) {
|
||||
assertTrue(subclass.isSubclassOf(superclass))
|
||||
assertTrue(superclass.isSuperclassOf(subclass))
|
||||
} else {
|
||||
assertFalse(subclass.isSubclassOf(superclass))
|
||||
assertFalse(superclass.isSuperclassOf(subclass))
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
check(Any::class, Any::class, true)
|
||||
check(String::class, Any::class, true)
|
||||
check(Any::class, String::class, false)
|
||||
check(String::class, String::class, true)
|
||||
|
||||
check(Int::class, Int::class, true)
|
||||
check(Int::class, Any::class, true)
|
||||
|
||||
check(List::class, Collection::class, true)
|
||||
check(List::class, Iterable::class, true)
|
||||
check(Collection::class, Iterable::class, true)
|
||||
check(Set::class, List::class, false)
|
||||
|
||||
check(Array<String>::class, Array<Any>::class, false)
|
||||
check(Array<Any>::class, Array<String>::class, false)
|
||||
|
||||
check(Function3::class, Function4::class, false)
|
||||
check(Function4::class, Function3::class, false)
|
||||
|
||||
check(Bar::class, Klass::class, true)
|
||||
check(Bar::class, Interface::class, true)
|
||||
check(Klass::class, Bar::class, false)
|
||||
check(Interface::class, Bar::class, false)
|
||||
check(Klass::class, Interface::class, false)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.isSubclassOf
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.assertFalse
|
||||
|
||||
fun box(): String {
|
||||
// KClass instances for primitive int and wrapper java.lang.Integer are different
|
||||
val primitiveInt = Int::class.javaPrimitiveType!!.kotlin
|
||||
val wrapperInt = Int::class.javaObjectType.kotlin
|
||||
assertTrue(primitiveInt.isSubclassOf(primitiveInt))
|
||||
assertTrue(wrapperInt.isSubclassOf(wrapperInt))
|
||||
|
||||
// Currently KClass for int != KClass for java.lang.Integer, thus they are not a subclass of each other either
|
||||
// TODO: reconsider this decision
|
||||
assertFalse(primitiveInt.isSubclassOf(wrapperInt))
|
||||
assertFalse(wrapperInt.isSubclassOf(primitiveInt))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// WITH_REFLECT
|
||||
// FILE: J.java
|
||||
|
||||
public interface J {
|
||||
String platformString();
|
||||
}
|
||||
|
||||
// FILE: K.kt
|
||||
|
||||
import kotlin.reflect.*
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
fun string(): String = null!!
|
||||
fun nullableString(): String? = null!!
|
||||
|
||||
fun check(subCallable: KCallable<*>, superCallable: KCallable<*>) {
|
||||
val subtype = subCallable.returnType
|
||||
val supertype = superCallable.returnType
|
||||
assertTrue(subtype.isSubtypeOf(supertype))
|
||||
assertTrue(supertype.isSupertypeOf(subtype))
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
check(::string, J::platformString)
|
||||
check(J::platformString, ::string)
|
||||
check(::nullableString, J::platformString)
|
||||
check(J::platformString, ::nullableString)
|
||||
check(J::platformString, J::platformString)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.*
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.assertFalse
|
||||
|
||||
open class G<T>
|
||||
class A : G<String>()
|
||||
|
||||
fun gOfString(): G<String> = null!!
|
||||
fun gOfInt(): G<Int> = null!!
|
||||
|
||||
fun box(): String {
|
||||
val gs = ::gOfString.returnType
|
||||
val gi = ::gOfInt.returnType
|
||||
val a = ::A.returnType
|
||||
|
||||
assertTrue(a.isSubtypeOf(gs))
|
||||
assertTrue(gs.isSupertypeOf(a))
|
||||
|
||||
assertFalse(a.isSubtypeOf(gi))
|
||||
assertFalse(gi.isSupertypeOf(a))
|
||||
|
||||
assertFalse(gs.isSubtypeOf(gi))
|
||||
assertFalse(gs.isSupertypeOf(gi))
|
||||
assertFalse(gi.isSubtypeOf(gs))
|
||||
assertFalse(gi.isSupertypeOf(gs))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.*
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.assertFalse
|
||||
|
||||
fun check(subCallable: KCallable<*>, superCallable: KCallable<*>, shouldBeSubtype: Boolean) {
|
||||
val subtype = subCallable.returnType
|
||||
val supertype = superCallable.returnType
|
||||
if (shouldBeSubtype) {
|
||||
assertTrue(subtype.isSubtypeOf(supertype))
|
||||
assertTrue(supertype.isSupertypeOf(subtype))
|
||||
} else {
|
||||
assertFalse(subtype.isSubtypeOf(supertype))
|
||||
assertFalse(supertype.isSupertypeOf(subtype))
|
||||
}
|
||||
}
|
||||
|
||||
open class O
|
||||
class X : O()
|
||||
|
||||
fun any(): Any = null!!
|
||||
fun string(): String = null!!
|
||||
fun nullableString(): String? = null!!
|
||||
fun int(): Int = null!!
|
||||
fun nothing(): Nothing = null!!
|
||||
fun nullableNothing(): Nothing? = null!!
|
||||
fun function2(): (Any, Any) -> Any = null!!
|
||||
fun function3(): (Any, Any, Any) -> Any = null!!
|
||||
|
||||
fun box(): String {
|
||||
check(::any, ::any, true)
|
||||
check(::int, ::int, true)
|
||||
check(::nothing, ::nothing, true)
|
||||
check(::nullableNothing, ::nullableNothing, true)
|
||||
|
||||
check(::string, ::any, true)
|
||||
check(::nullableString, ::any, false)
|
||||
check(::int, ::any, true)
|
||||
check(::O, ::any, true)
|
||||
check(::X, ::any, true)
|
||||
|
||||
check(::nothing, ::any, true)
|
||||
check(::nothing, ::string, true)
|
||||
check(::nothing, ::nullableString, true)
|
||||
check(::nullableNothing, ::nullableString, true)
|
||||
check(::nullableNothing, ::string, false)
|
||||
|
||||
check(::string, ::nullableString, true)
|
||||
check(::nullableString, ::string, false)
|
||||
|
||||
check(::X, ::O, true)
|
||||
check(::O, ::X, false)
|
||||
|
||||
check(::int, ::string, false)
|
||||
check(::string, ::int, false)
|
||||
check(::any, ::string, false)
|
||||
check(::any, ::nullableString, false)
|
||||
|
||||
check(::function2, ::function3, false)
|
||||
check(::function3, ::function2, false)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.isSubtypeOf
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.assertFalse
|
||||
|
||||
class G<T>
|
||||
|
||||
fun number(): G<Number> = null!!
|
||||
fun outNumber(): G<out Number> = null!!
|
||||
fun inNumber(): G<in Number> = null!!
|
||||
fun star(): G<*> = null!!
|
||||
|
||||
fun box(): String {
|
||||
val n = ::number.returnType
|
||||
val o = ::outNumber.returnType
|
||||
val i = ::inNumber.returnType
|
||||
val st = ::star.returnType
|
||||
|
||||
// G<Number> <: G<out Number>
|
||||
assertTrue(n.isSubtypeOf(o))
|
||||
assertFalse(o.isSubtypeOf(n))
|
||||
|
||||
// G<Number> <: G<in Number>
|
||||
assertTrue(n.isSubtypeOf(i))
|
||||
assertFalse(i.isSubtypeOf(n))
|
||||
|
||||
// G<Number> <: G<*>
|
||||
assertTrue(n.isSubtypeOf(st))
|
||||
assertFalse(st.isSubtypeOf(n))
|
||||
|
||||
// G<out Number> <: G<*>
|
||||
assertTrue(o.isSubtypeOf(st))
|
||||
assertFalse(st.isSubtypeOf(o))
|
||||
|
||||
// G<in Number> <: G<*>
|
||||
assertTrue(i.isSubtypeOf(st))
|
||||
assertFalse(st.isSubtypeOf(i))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user