From ebe4a8ec89410f34eca06aee52c3031764ada9d8 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 13 Aug 2015 10:13:11 -0700 Subject: [PATCH] Provide equals/hashCode/toString for KType implementation --- .../platformTypeNotEqualToKotlinType/J.java | 5 +++ .../platformTypeNotEqualToKotlinType/K.kt | 11 ++++++ .../reflection/platformTypeToString/J.java | 11 ++++++ .../reflection/platformTypeToString/K.kt | 8 +++++ .../methodsFromAny/typeEqualsHashCode.kt | 28 +++++++++++++++ .../reflection/methodsFromAny/typeToString.kt | 35 +++++++++++++++++++ .../BlackBoxWithJavaCodegenTestGenerated.java | 12 +++++++ ...lackBoxWithStdlibCodegenTestGenerated.java | 12 +++++++ .../kotlin/reflect/jvm/internal/KTypeImpl.kt | 9 +++++ .../jvm/internal/ReflectionObjectRenderer.kt | 21 ++++++----- 10 files changed, 144 insertions(+), 8 deletions(-) create mode 100644 compiler/testData/codegen/boxWithJava/reflection/platformTypeNotEqualToKotlinType/J.java create mode 100644 compiler/testData/codegen/boxWithJava/reflection/platformTypeNotEqualToKotlinType/K.kt create mode 100644 compiler/testData/codegen/boxWithJava/reflection/platformTypeToString/J.java create mode 100644 compiler/testData/codegen/boxWithJava/reflection/platformTypeToString/K.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/typeEqualsHashCode.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/typeToString.kt diff --git a/compiler/testData/codegen/boxWithJava/reflection/platformTypeNotEqualToKotlinType/J.java b/compiler/testData/codegen/boxWithJava/reflection/platformTypeNotEqualToKotlinType/J.java new file mode 100644 index 00000000000..ef7ec61093c --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/reflection/platformTypeNotEqualToKotlinType/J.java @@ -0,0 +1,5 @@ +public class J { + public static String foo() { + return ""; + } +} diff --git a/compiler/testData/codegen/boxWithJava/reflection/platformTypeNotEqualToKotlinType/K.kt b/compiler/testData/codegen/boxWithJava/reflection/platformTypeNotEqualToKotlinType/K.kt new file mode 100644 index 00000000000..9c90ecfb1d8 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/reflection/platformTypeNotEqualToKotlinType/K.kt @@ -0,0 +1,11 @@ +import kotlin.test.assertNotEquals + +fun nonNullString(): String = "" +fun nullableString(): String? = "" + +fun box(): String { + assertNotEquals(J::foo.returnType, ::nonNullString.returnType) + assertNotEquals(J::foo.returnType, ::nullableString.returnType) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithJava/reflection/platformTypeToString/J.java b/compiler/testData/codegen/boxWithJava/reflection/platformTypeToString/J.java new file mode 100644 index 00000000000..f1774740e19 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/reflection/platformTypeToString/J.java @@ -0,0 +1,11 @@ +import java.util.List; + +public class J { + public static String string() { + return ""; + } + + public static List list() { + return null; + } +} diff --git a/compiler/testData/codegen/boxWithJava/reflection/platformTypeToString/K.kt b/compiler/testData/codegen/boxWithJava/reflection/platformTypeToString/K.kt new file mode 100644 index 00000000000..3b62a47b5e0 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/reflection/platformTypeToString/K.kt @@ -0,0 +1,8 @@ +import kotlin.test.assertEquals + +fun box(): String { + assertEquals("kotlin.String!", J::string.returnType.toString()) + assertEquals("kotlin.(Mutable)List!", J::list.returnType.toString()) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/typeEqualsHashCode.kt b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/typeEqualsHashCode.kt new file mode 100644 index 00000000000..921054c5a39 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/typeEqualsHashCode.kt @@ -0,0 +1,28 @@ +import kotlin.reflect.KType +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals + +fun unit(p: Unit): Unit {} + +fun nullable(s: String): String? = s + +class A { + fun typeParam(t: T): T = t +} + + +fun box(): String { + fun check(t1: KType, t2: KType) { + assertEquals(t1, t2) + assertEquals(t1.hashCode(), t2.hashCode()) + } + + check(::unit.parameters.single().type, ::unit.returnType) + + assertNotEquals(::nullable.parameters.single().type, ::nullable.returnType) + + val typeParam = A::class.members.single { it.name == "typeParam" } + check(typeParam.parameters.last().type, typeParam.returnType) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/typeToString.kt b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/typeToString.kt new file mode 100644 index 00000000000..15946e2ff4c --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/typeToString.kt @@ -0,0 +1,35 @@ +import kotlin.test.assertEquals + +fun String?.foo(x: Int, y: Array, z: IntArray, w: List>>) {} + +class A { + fun bar(t: T, u: U): T? = null +} + +fun baz(inProjection: A, outProjection: A) {} + +fun box(): String { + assertEquals( + listOf( + "kotlin.String?", + "kotlin.Int", + "kotlin.Array", + "kotlin.IntArray", + "kotlin.List>>" + ), + String?::foo.parameters.map { it.type.toString() } + ) + + assertEquals("kotlin.Unit", String?::foo.returnType.toString()) + + val bar = A::class.members.single { it.name == "bar" } + assertEquals(listOf("A", "T", "U"), bar.parameters.map { it.type.toString() }) + assertEquals("T?", bar.returnType.toString()) + + assertEquals( + listOf("A", "A"), + ::baz.parameters.map { it.type.toString() } + ) + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java index 89c609f3b16..7dd799c5048 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java @@ -345,6 +345,18 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege doTestWithJava(fileName); } + @TestMetadata("platformTypeNotEqualToKotlinType") + public void testPlatformTypeNotEqualToKotlinType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/platformTypeNotEqualToKotlinType/"); + doTestWithJava(fileName); + } + + @TestMetadata("platformTypeToString") + public void testPlatformTypeToString() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/platformTypeToString/"); + doTestWithJava(fileName); + } + @TestMetadata("referenceToJavaFieldOfKotlinSubclass") public void testReferenceToJavaFieldOfKotlinSubclass() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/referenceToJavaFieldOfKotlinSubclass/"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index b5ba716dc10..d351566b3cd 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -3503,6 +3503,18 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/propertyToString.kt"); doTestWithStdlib(fileName); } + + @TestMetadata("typeEqualsHashCode.kt") + public void testTypeEqualsHashCode() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/typeEqualsHashCode.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("typeToString.kt") + public void testTypeToString() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/typeToString.kt"); + doTestWithStdlib(fileName); + } } @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/noKotlinReflect") diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt index 7cf27288a0a..5dd64947279 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt @@ -28,4 +28,13 @@ class KTypeImpl( override val isMarkedNullable: Boolean get() = type.isMarkedNullable + + override fun equals(other: Any?) = + other is KTypeImpl && type.equals(other.type) + + override fun hashCode() = + type.hashCode() + + override fun toString() = + ReflectionObjectRenderer.renderType(type) } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionObjectRenderer.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionObjectRenderer.kt index ea104dfeb8d..edefb19c0b5 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionObjectRenderer.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionObjectRenderer.kt @@ -21,20 +21,21 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.renderer.DescriptorRenderer +import org.jetbrains.kotlin.types.JetType object ReflectionObjectRenderer { private val renderer = DescriptorRenderer.FQ_NAMES_IN_TYPES private fun StringBuilder.appendReceiverType(receiver: ReceiverParameterDescriptor?) { if (receiver != null) { - append(renderer.renderType(receiver.getType())) + append(renderType(receiver.type)) append(".") } } private fun StringBuilder.appendReceiversAndName(callable: CallableDescriptor) { - val dispatchReceiver = callable.getDispatchReceiverParameter() - val extensionReceiver = callable.getExtensionReceiverParameter() + val dispatchReceiver = callable.dispatchReceiverParameter + val extensionReceiver = callable.extensionReceiverParameter appendReceiverType(dispatchReceiver) @@ -43,13 +44,13 @@ object ReflectionObjectRenderer { appendReceiverType(extensionReceiver) if (addParentheses) append(")") - append(renderer.renderName(callable.getName())) + append(renderer.renderName(callable.name)) } // TODO: include visibility, return type fun renderProperty(descriptor: PropertyDescriptor): String { return StringBuilder { - append(if (descriptor.isVar()) "var " else "val ") + append(if (descriptor.isVar) "var " else "val ") appendReceiversAndName(descriptor) }.toString() } @@ -59,12 +60,16 @@ object ReflectionObjectRenderer { append("fun ") appendReceiversAndName(descriptor) - descriptor.getValueParameters().joinTo(this, separator = ", ", prefix = "(", postfix = ")") { - renderer.renderType(it.getType()) // TODO: vararg + descriptor.valueParameters.joinTo(this, separator = ", ", prefix = "(", postfix = ")") { + renderType(it.type) // TODO: vararg } append(": ") - append(renderer.renderType(descriptor.getReturnType()!!)) + append(renderType(descriptor.returnType!!)) }.toString() } + + fun renderType(type: JetType): String { + return renderer.renderType(type) + } }