Improve toString of platform types created by typeOf
In the stdlib implementation, render "!" if the type is only nullability-flexible. Otherwise, render "($lower..$upper)". Note that full kotlin-reflect has a much more complicated logic (see `DescriptorRendererImpl.renderFlexibleType`) that renders things like `(Mutable)List` and so on. It is not a goal of the stdlib implementation to replicate all of that, since it requires copying a large amount of code, namely the entirety of `JavaToKotlinClassMap` to map Java class names to Kotlin.
This commit is contained in:
+12
@@ -37521,6 +37521,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/nothing_before.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("primitiveJavaTypes.kt")
|
||||
public void testPrimitiveJavaTypes() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/primitiveJavaTypes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("rawTypes_after.kt")
|
||||
public void testRawTypes_after() throws Exception {
|
||||
@@ -37606,6 +37612,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/nothing_before.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("primitiveJavaTypes.kt")
|
||||
public void testPrimitiveJavaTypes() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/primitiveJavaTypes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("rawTypes_after.kt")
|
||||
public void testRawTypes_after() throws Exception {
|
||||
|
||||
+4
-5
@@ -15,12 +15,11 @@ fun check(expected: String, actual: KType) {
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
// String representation of platform types does not differ from non-nullable types in the stdlib implementation (without reflect).
|
||||
check("java.lang.String", returnTypeOf { J.nullabilityFlexible() })
|
||||
check("java.util.List<java.lang.String>", returnTypeOf { J.mutabilityFlexible() })
|
||||
check("java.util.List<java.lang.String>", returnTypeOf { J.bothFlexible() })
|
||||
check("java.lang.String!", returnTypeOf { J.nullabilityFlexible() })
|
||||
check("java.util.List<java.lang.String!>", returnTypeOf { J.mutabilityFlexible() })
|
||||
check("java.util.List<java.lang.String!>!", returnTypeOf { J.bothFlexible() })
|
||||
|
||||
// However, type flexibility affects equality! Platform type is neither nullable nor non-nullable.
|
||||
// Type flexibility affects equality! Platform type is neither nullable nor non-nullable.
|
||||
val platform = returnTypeOf { J.nullabilityFlexible() }
|
||||
if (platform == returnTypeOf { J.nullable() }) return "Fail: platform type should not be equal to nullable type"
|
||||
if (platform == returnTypeOf { J.notNull() }) return "Fail: platform type should not be equal to non-nullable type"
|
||||
|
||||
@@ -26,8 +26,7 @@ fun box(): String {
|
||||
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>()) })
|
||||
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).
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
// !API_VERSION: LATEST
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// FILE: box.kt
|
||||
|
||||
package test
|
||||
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
fun check(expected: String, actual: KType) {
|
||||
assertEquals(expected + " (Kotlin reflection is not available)", actual.toString())
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
check("int", returnTypeOf { J.primitive() })
|
||||
check("java.lang.Integer!", returnTypeOf { J.wrapper() })
|
||||
check("java.lang.Integer?", returnTypeOf { J.nullableWrapper() })
|
||||
check("java.lang.Integer", returnTypeOf { J.notNullWrapper() })
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
inline fun <reified T> returnTypeOf(block: () -> T) =
|
||||
typeOf<T>()
|
||||
|
||||
// FILE: J.java
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class J {
|
||||
public static int primitive() { return 0; }
|
||||
public static Integer wrapper() { return 0; }
|
||||
|
||||
@Nullable
|
||||
public static Integer nullableWrapper() { return 0; }
|
||||
|
||||
@NotNull
|
||||
public static Integer notNullWrapper() { return 0; }
|
||||
}
|
||||
+4
-4
@@ -18,10 +18,10 @@ fun check(expected: String, actual: KType) {
|
||||
class C<T, U : Number>
|
||||
|
||||
fun box(): String {
|
||||
check("test.C<java.lang.Object?, java.lang.Number>", returnTypeOf { J.raw() })
|
||||
check("test.C<java.lang.Object?, java.lang.Number>", returnTypeOf { J.rawNotNull() })
|
||||
check("java.util.List<java.lang.Object?>", returnTypeOf { J.rawList() })
|
||||
check("java.util.Map<java.lang.Object?, java.lang.Object?>", returnTypeOf { J.rawNotNullMap() })
|
||||
check("(test.C<java.lang.Object?, java.lang.Number>..test.C<*, *>?)", returnTypeOf { J.raw() })
|
||||
check("(test.C<java.lang.Object?, java.lang.Number>..test.C<*, *>)", returnTypeOf { J.rawNotNull() })
|
||||
check("(java.util.List<java.lang.Object?>..java.util.List<*>?)", returnTypeOf { J.rawList() })
|
||||
check("(java.util.Map<java.lang.Object?, java.lang.Object?>..java.util.Map<*, *>)", returnTypeOf { J.rawNotNullMap() })
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// !API_VERSION: LATEST
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_REFLECT
|
||||
// FILE: box.kt
|
||||
|
||||
package test
|
||||
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
fun check(expected: String, actual: KType) {
|
||||
assertEquals(expected, actual.toString())
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
check("kotlin.Int", returnTypeOf { J.primitive() })
|
||||
check("kotlin.Int!", returnTypeOf { J.wrapper() })
|
||||
check("kotlin.Int?", returnTypeOf { J.nullableWrapper() })
|
||||
check("kotlin.Int", returnTypeOf { J.notNullWrapper() })
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
inline fun <reified T> returnTypeOf(block: () -> T) =
|
||||
typeOf<T>()
|
||||
|
||||
// FILE: J.java
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class J {
|
||||
public static int primitive() { return 0; }
|
||||
public static Integer wrapper() { return 0; }
|
||||
|
||||
@Nullable
|
||||
public static Integer nullableWrapper() { return 0; }
|
||||
|
||||
@NotNull
|
||||
public static Integer notNullWrapper() { return 0; }
|
||||
}
|
||||
+12
@@ -37479,6 +37479,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/nothing_before.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("primitiveJavaTypes.kt")
|
||||
public void testPrimitiveJavaTypes() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/primitiveJavaTypes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("rawTypes_after.kt")
|
||||
public void testRawTypes_after() throws Exception {
|
||||
@@ -37564,6 +37570,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/nothing_before.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("primitiveJavaTypes.kt")
|
||||
public void testPrimitiveJavaTypes() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/primitiveJavaTypes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("rawTypes_after.kt")
|
||||
public void testRawTypes_after() throws Exception {
|
||||
|
||||
+12
@@ -37521,6 +37521,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/nothing_before.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("primitiveJavaTypes.kt")
|
||||
public void testPrimitiveJavaTypes() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/primitiveJavaTypes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("rawTypes_after.kt")
|
||||
public void testRawTypes_after() throws Exception {
|
||||
@@ -37606,6 +37612,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/nothing_before.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("primitiveJavaTypes.kt")
|
||||
public void testPrimitiveJavaTypes() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/primitiveJavaTypes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("rawTypes_after.kt")
|
||||
public void testRawTypes_after() throws Exception {
|
||||
|
||||
+10
@@ -29840,6 +29840,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/nothing_before.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("primitiveJavaTypes.kt")
|
||||
public void testPrimitiveJavaTypes() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/primitiveJavaTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("rawTypes_after.kt")
|
||||
public void testRawTypes_after() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/rawTypes_after.kt");
|
||||
@@ -29920,6 +29925,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/nothing_before.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("primitiveJavaTypes.kt")
|
||||
public void testPrimitiveJavaTypes() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/primitiveJavaTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("rawTypes_after.kt")
|
||||
public void testRawTypes_after() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/rawTypes_after.kt");
|
||||
|
||||
@@ -53,7 +53,22 @@ public class TypeReference /* @SinceKotlin("1.6") constructor */(
|
||||
else arguments.joinToString(", ", "<", ">") { it.asString() }
|
||||
val nullable = if (isMarkedNullable) "?" else ""
|
||||
|
||||
return klass + args + nullable
|
||||
val result = klass + args + nullable
|
||||
|
||||
return when (val upper = platformTypeUpperBound) {
|
||||
is TypeReference -> {
|
||||
when (val renderedUpper = upper.asString(true)) {
|
||||
result -> {
|
||||
// Rendered upper bound can be the same as rendered lower bound in cases when the type is mutability-flexible,
|
||||
// but not nullability-flexible, since both MutableCollection and Collection are rendered as "java.util.Collection".
|
||||
result
|
||||
}
|
||||
"$result?" -> "$result!"
|
||||
else -> "($result..$renderedUpper)"
|
||||
}
|
||||
}
|
||||
else -> result
|
||||
}
|
||||
}
|
||||
|
||||
private val Class<*>.arrayClassName
|
||||
|
||||
Reference in New Issue
Block a user