Make KClasses for primitives equal to KClasses for wrapper types

Both primitive int and wrapper type java.lang.Integer are represented by the
single type kotlin.Int in Kotlin, so inequality between the corresponding
KClasses was confusing here. To keep the old behavior, one may call 'k1.java ==
k2.java' instead of `k1 == k2`

 #KT-13462 Fixed
This commit is contained in:
Alexander Udalov
2016-08-09 15:42:42 +03:00
parent 3efa738bc0
commit 5b1ee13db8
7 changed files with 53 additions and 16 deletions
@@ -0,0 +1,15 @@
// WITH_RUNTIME
import kotlin.test.assertEquals
import kotlin.test.assertFalse
fun box(): String {
val x = Int::class.javaPrimitiveType!!.kotlin
val y = Int::class.javaObjectType.kotlin
assertEquals(x, y)
assertEquals(x.hashCode(), y.hashCode())
assertFalse(x === y)
return "OK"
}
@@ -0,0 +1,15 @@
// WITH_REFLECT
import kotlin.test.assertEquals
import kotlin.test.assertFalse
fun box(): String {
val x = Int::class.javaPrimitiveType!!.kotlin
val y = Int::class.javaObjectType.kotlin
assertEquals(x, y)
assertEquals(x.hashCode(), y.hashCode())
assertFalse(x === y)
return "OK"
}
@@ -11,10 +11,9 @@ fun box(): String {
assertTrue(primitiveInt.isSubclassOf(primitiveInt)) assertTrue(primitiveInt.isSubclassOf(primitiveInt))
assertTrue(wrapperInt.isSubclassOf(wrapperInt)) assertTrue(wrapperInt.isSubclassOf(wrapperInt))
// Currently KClass for int != KClass for java.lang.Integer, thus they are not a subclass of each other either // KClass for int equals KClass for java.lang.Integer, so they are also a subclass of each other
// TODO: reconsider this decision assertTrue(primitiveInt.isSubclassOf(wrapperInt))
assertFalse(primitiveInt.isSubclassOf(wrapperInt)) assertTrue(wrapperInt.isSubclassOf(primitiveInt))
assertFalse(wrapperInt.isSubclassOf(primitiveInt))
return "OK" return "OK"
} }
@@ -2356,6 +2356,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/classLiteral"), Pattern.compile("^(.+)\\.kt$"), true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/classLiteral"), Pattern.compile("^(.+)\\.kt$"), true);
} }
@TestMetadata("primitiveKClassEquality.kt")
public void testPrimitiveKClassEquality() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/classLiteral/primitiveKClassEquality.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/codegen/box/classLiteral/bound") @TestMetadata("compiler/testData/codegen/box/classLiteral/bound")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -12003,6 +12009,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("primitiveKClassEquality.kt")
public void testPrimitiveKClassEquality() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/classes/primitiveKClassEquality.kt");
doTest(fileName);
}
@TestMetadata("qualifiedName.kt") @TestMetadata("qualifiedName.kt")
public void testQualifiedName() throws Exception { public void testQualifiedName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/classes/qualifiedName.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/classes/qualifiedName.kt");
+4 -8
View File
@@ -123,15 +123,11 @@ public interface KClass<T : Any> : KDeclarationContainer, KAnnotatedElement, KCl
/** /**
* Returns `true` if [other] is a [KClass] instance representing the same class on a given platform. * Returns `true` if [other] is a [KClass] instance representing the same class on a given platform.
* On JVM this means that all of the following conditions are satisfied:
* *
* On JVM this means that the given instance is backed by the same [Class] object as this one. In particular, it requires * 1. [other] has the same fully qualified name as this instance.
* that the two classes are loaded with the same class loader and have the same name. Note that there are cases where the behavior * 2. [other]'s backing [Class] object is loaded with the same class loader as the [Class] object of this instance.
* of this method may seem unintuitive: * 3. If the classes represent [Array], then [Class] objects of their element types are equal.
* * For each JVM primitive type, there are two classes at runtime: one for the primitive itself, and another for the wrapper class.
* [KClass] instances for those classes are different: [KClass] for `int` is **not equal** to [KClass] for `java.lang.Integer`,
* although both have the same qualified name [kotlin.Int].
* * For JVM arrays of different types, [KClass] instances are different,
* although all of them have the same qualified name [kotlin.Array].
*/ */
override fun equals(other: Any?): Boolean override fun equals(other: Any?): Boolean
@@ -196,10 +196,10 @@ internal class KClassImpl<T : Any>(override val jClass: Class<T>) :
get() = descriptor.isCompanionObject get() = descriptor.isCompanionObject
override fun equals(other: Any?): Boolean = override fun equals(other: Any?): Boolean =
other is KClassImpl<*> && jClass == other.jClass other is KClassImpl<*> && javaObjectType == other.javaObjectType
override fun hashCode(): Int = override fun hashCode(): Int =
jClass.hashCode() javaObjectType.hashCode()
override fun toString(): String { override fun toString(): String {
return "class " + classId.let { classId -> return "class " + classId.let { classId ->
@@ -75,10 +75,10 @@ class ClassReference(override val jClass: Class<*>) : KClass<Any>, ClassBasedDec
private fun error(): Nothing = throw KotlinReflectionNotSupportedError() private fun error(): Nothing = throw KotlinReflectionNotSupportedError()
override fun equals(other: Any?) = override fun equals(other: Any?) =
other is ClassReference && jClass == other.jClass other is ClassReference && javaObjectType == other.javaObjectType
override fun hashCode() = override fun hashCode() =
jClass.hashCode() javaObjectType.hashCode()
override fun toString() = override fun toString() =
jClass.toString() + Reflection.REFLECTION_NOT_AVAILABLE jClass.toString() + Reflection.REFLECTION_NOT_AVAILABLE