diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index afdf1999c1b..ec88541baca 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -26072,6 +26072,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/types"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @TestMetadata("allSupertypes.kt") + public void testAllSupertypes() throws Exception { + runTest("compiler/testData/codegen/box/reflection/mapping/types/allSupertypes.kt"); + } + @TestMetadata("annotationConstructorParameters.kt") public void testAnnotationConstructorParameters() throws Exception { runTest("compiler/testData/codegen/box/reflection/mapping/types/annotationConstructorParameters.kt"); @@ -26087,6 +26092,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/reflection/mapping/types/constructors.kt"); } + @TestMetadata("createType.kt") + public void testCreateType() throws Exception { + runTest("compiler/testData/codegen/box/reflection/mapping/types/createType.kt"); + } + @TestMetadata("genericArrayElementType.kt") public void testGenericArrayElementType() throws Exception { runTest("compiler/testData/codegen/box/reflection/mapping/types/genericArrayElementType.kt"); diff --git a/compiler/testData/codegen/box/reflection/mapping/types/allSupertypes.kt b/compiler/testData/codegen/box/reflection/mapping/types/allSupertypes.kt new file mode 100644 index 00000000000..caddfa2d311 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/mapping/types/allSupertypes.kt @@ -0,0 +1,21 @@ +// TARGET_BACKEND: JVM +// WITH_REFLECT + +package test + +import kotlin.reflect.full.allSupertypes +import kotlin.reflect.jvm.javaType +import kotlin.test.assertEquals + +interface I + +abstract class A : Map, Array>> + +fun box(): String { + assertEquals( + "java.util.Map, java.util.List[]>", + A::class.allSupertypes.single { it.classifier == Map::class }.javaType.toString() + ) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/mapping/types/createType.kt b/compiler/testData/codegen/box/reflection/mapping/types/createType.kt new file mode 100644 index 00000000000..d0c7a6dcd0f --- /dev/null +++ b/compiler/testData/codegen/box/reflection/mapping/types/createType.kt @@ -0,0 +1,27 @@ +// TARGET_BACKEND: JVM +// WITH_REFLECT + +package test + +import kotlin.reflect.KTypeProjection +import kotlin.reflect.full.createType +import kotlin.reflect.jvm.javaType +import kotlin.test.assertEquals + +class A + +fun box(): String { + val nullableAOfInString = A::class.createType(listOf( + KTypeProjection.contravariant(String::class.createType()) + ), true) + assertEquals("test.A", nullableAOfInString.javaType.toString()) + + val arrayOfListOfInteger = Array::class.createType(listOf( + KTypeProjection.invariant(List::class.createType(listOf( + KTypeProjection.invariant(Int::class.createType()) + ))) + )) + assertEquals("java.util.List[]", arrayOfListOfInteger.javaType.toString()) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/mapping/types/typeParameters.kt b/compiler/testData/codegen/box/reflection/mapping/types/typeParameters.kt index 6bae2b0804f..17c650f95d8 100644 --- a/compiler/testData/codegen/box/reflection/mapping/types/typeParameters.kt +++ b/compiler/testData/codegen/box/reflection/mapping/types/typeParameters.kt @@ -7,7 +7,7 @@ import java.lang.reflect.TypeVariable import kotlin.reflect.jvm.* import kotlin.test.assertEquals -class A { +class A { fun foo(t: T) {} } @@ -19,5 +19,8 @@ fun box(): String { assertEquals("T", t.name) assertEquals(A::class.java, (t.genericDeclaration as Class<*>)) + val tp = A::class.typeParameters + assertEquals(CharSequence::class.java, tp.single().upperBounds.single().javaType) + return "OK" } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index affbb7f6916..e8b5caa796b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -27663,6 +27663,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/types"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @TestMetadata("allSupertypes.kt") + public void testAllSupertypes() throws Exception { + runTest("compiler/testData/codegen/box/reflection/mapping/types/allSupertypes.kt"); + } + @TestMetadata("annotationConstructorParameters.kt") public void testAnnotationConstructorParameters() throws Exception { runTest("compiler/testData/codegen/box/reflection/mapping/types/annotationConstructorParameters.kt"); @@ -27678,6 +27683,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/reflection/mapping/types/constructors.kt"); } + @TestMetadata("createType.kt") + public void testCreateType() throws Exception { + runTest("compiler/testData/codegen/box/reflection/mapping/types/createType.kt"); + } + @TestMetadata("genericArrayElementType.kt") public void testGenericArrayElementType() throws Exception { runTest("compiler/testData/codegen/box/reflection/mapping/types/genericArrayElementType.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 36caf7bd289..3856df07eb2 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -25297,6 +25297,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/types"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @TestMetadata("allSupertypes.kt") + public void testAllSupertypes() throws Exception { + runTest("compiler/testData/codegen/box/reflection/mapping/types/allSupertypes.kt"); + } + @TestMetadata("annotationConstructorParameters.kt") public void testAnnotationConstructorParameters() throws Exception { runTest("compiler/testData/codegen/box/reflection/mapping/types/annotationConstructorParameters.kt"); @@ -25312,6 +25317,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reflection/mapping/types/constructors.kt"); } + @TestMetadata("createType.kt") + public void testCreateType() throws Exception { + runTest("compiler/testData/codegen/box/reflection/mapping/types/createType.kt"); + } + @TestMetadata("genericArrayElementType.kt") public void testGenericArrayElementType() throws Exception { runTest("compiler/testData/codegen/box/reflection/mapping/types/genericArrayElementType.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 4ca15a02846..71b4434fe32 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -26072,6 +26072,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/types"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @TestMetadata("allSupertypes.kt") + public void testAllSupertypes() throws Exception { + runTest("compiler/testData/codegen/box/reflection/mapping/types/allSupertypes.kt"); + } + @TestMetadata("annotationConstructorParameters.kt") public void testAnnotationConstructorParameters() throws Exception { runTest("compiler/testData/codegen/box/reflection/mapping/types/annotationConstructorParameters.kt"); @@ -26087,6 +26092,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reflection/mapping/types/constructors.kt"); } + @TestMetadata("createType.kt") + public void testCreateType() throws Exception { + runTest("compiler/testData/codegen/box/reflection/mapping/types/createType.kt"); + } + @TestMetadata("genericArrayElementType.kt") public void testGenericArrayElementType() throws Exception { runTest("compiler/testData/codegen/box/reflection/mapping/types/genericArrayElementType.kt"); diff --git a/core/reflection.jvm/src/kotlin/reflect/full/KClasses.kt b/core/reflection.jvm/src/kotlin/reflect/full/KClasses.kt index 886d837d8cf..d20675d466d 100644 --- a/core/reflection.jvm/src/kotlin/reflect/full/KClasses.kt +++ b/core/reflection.jvm/src/kotlin/reflect/full/KClasses.kt @@ -201,10 +201,7 @@ val KClass<*>.allSupertypes: Collection supertypes.map { supertype -> val substituted = substitutor.substitute((supertype as KTypeImpl).type, Variance.INVARIANT) ?: throw KotlinReflectionInternalError("Type substitution failed: $supertype ($current)") - KTypeImpl(substituted) { - // TODO - TODO("Java type for supertype") - } + KTypeImpl(substituted) } } }, diff --git a/core/reflection.jvm/src/kotlin/reflect/full/KClassifiers.kt b/core/reflection.jvm/src/kotlin/reflect/full/KClassifiers.kt index baad1bcc20e..82759c0b15f 100644 --- a/core/reflection.jvm/src/kotlin/reflect/full/KClassifiers.kt +++ b/core/reflection.jvm/src/kotlin/reflect/full/KClassifiers.kt @@ -19,7 +19,10 @@ package kotlin.reflect.full import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.types.* -import kotlin.reflect.* +import kotlin.reflect.KClassifier +import kotlin.reflect.KType +import kotlin.reflect.KTypeProjection +import kotlin.reflect.KVariance import kotlin.reflect.jvm.internal.KClassifierImpl import kotlin.reflect.jvm.internal.KTypeImpl import kotlin.reflect.jvm.internal.KotlinReflectionInternalError @@ -56,11 +59,7 @@ fun KClassifier.createType( if (annotations.isEmpty()) Annotations.EMPTY else Annotations.EMPTY // TODO: support type annotations - val kotlinType = createKotlinType(typeAnnotations, typeConstructor, arguments, nullable) - - return KTypeImpl(kotlinType) { - TODO("Java type is not yet supported for types created with createType (classifier = $this)") - } + return KTypeImpl(createKotlinType(typeAnnotations, typeConstructor, arguments, nullable)) } private fun createKotlinType( diff --git a/core/reflection.jvm/src/kotlin/reflect/full/KTypes.kt b/core/reflection.jvm/src/kotlin/reflect/full/KTypes.kt index 7413b068f56..a4432be1759 100644 --- a/core/reflection.jvm/src/kotlin/reflect/full/KTypes.kt +++ b/core/reflection.jvm/src/kotlin/reflect/full/KTypes.kt @@ -17,10 +17,8 @@ @file:JvmName("KTypes") package kotlin.reflect.full -import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.types.isFlexible import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf -import kotlin.reflect.* +import kotlin.reflect.KType import kotlin.reflect.jvm.internal.KTypeImpl /** @@ -28,15 +26,7 @@ import kotlin.reflect.jvm.internal.KTypeImpl */ @SinceKotlin("1.1") fun KType.withNullability(nullable: Boolean): KType { - if (isMarkedNullable) { - return if (nullable) this else KTypeImpl(TypeUtils.makeNotNullable((this as KTypeImpl).type)) { javaType } - } - - // If the type is not marked nullable, it's either a non-null type or a platform type. - val kotlinType = (this as KTypeImpl).type - if (kotlinType.isFlexible()) return KTypeImpl(TypeUtils.makeNullableAsSpecified(kotlinType, nullable)) { javaType } - - return if (!nullable) this else KTypeImpl(TypeUtils.makeNullable(kotlinType)) { javaType } + return (this as KTypeImpl).makeNullableAsSpecified(nullable) } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/ReflectJvmMapping.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/ReflectJvmMapping.kt index 2fc177d8d1d..4573725f51c 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/ReflectJvmMapping.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/ReflectJvmMapping.kt @@ -21,6 +21,7 @@ package kotlin.reflect.jvm import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import java.lang.reflect.* import kotlin.reflect.* +import kotlin.reflect.javaType as stdlibJavaType import kotlin.reflect.full.companionObject import kotlin.reflect.full.functions import kotlin.reflect.full.memberProperties @@ -76,7 +77,8 @@ val KFunction.javaConstructor: Constructor? * the JVM class [Unit] when it's the type of a parameter, or to `void` when it's the return type of a function. */ val KType.javaType: Type - get() = (this as KTypeImpl).javaType + @OptIn(ExperimentalStdlibApi::class) + get() = (this as KTypeImpl).javaType ?: stdlibJavaType // Java reflection -> Kotlin reflection 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 855bfb52738..49666340603 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.runtime.structure.primitiveByWrapper import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.types.isFlexible import java.lang.reflect.GenericArrayType import java.lang.reflect.ParameterizedType import java.lang.reflect.Type @@ -37,15 +38,19 @@ import kotlin.reflect.jvm.jvmErasure internal class KTypeImpl( val type: KotlinType, - computeJavaType: () -> Type + computeJavaType: (() -> Type)? = null ) : KTypeBase { - override val javaType: Type by ReflectProperties.lazySoft(computeJavaType) + @Suppress("UNCHECKED_CAST") + private val computeJavaType = + computeJavaType as? ReflectProperties.LazySoftVal ?: computeJavaType?.let(ReflectProperties::lazySoft) + + override val javaType: Type? + get() = computeJavaType?.invoke() override val classifier: KClassifier? by ReflectProperties.lazySoft { convert(type) } private fun convert(type: KotlinType): KClassifier? { - val descriptor = type.constructor.declarationDescriptor - when (descriptor) { + when (val descriptor = type.constructor.declarationDescriptor) { is ClassDescriptor -> { val jClass = descriptor.toJavaClass() ?: return null if (jClass.isArray) { @@ -53,7 +58,7 @@ internal class KTypeImpl( val argument = type.arguments.singleOrNull()?.type ?: return KClassImpl(jClass) val elementClassifier = convert(argument) - ?: throw KotlinReflectionInternalError("Cannot determine classifier for array element type: $this") + ?: throw KotlinReflectionInternalError("Cannot determine classifier for array element type: $this") return KClassImpl(elementClassifier.jvmErasure.java.createArrayType()) } @@ -73,15 +78,14 @@ internal class KTypeImpl( val typeArguments = type.arguments if (typeArguments.isEmpty()) return@arguments emptyList() - val parameterizedTypeArguments by lazy(PUBLICATION) { javaType.parameterizedTypeArguments } + val parameterizedTypeArguments by lazy(PUBLICATION) { javaType!!.parameterizedTypeArguments } typeArguments.mapIndexed { i, typeProjection -> if (typeProjection.isStarProjection) { KTypeProjection.STAR } else { - val type = KTypeImpl(typeProjection.type) { - val javaType = javaType - when (javaType) { + val type = KTypeImpl(typeProjection.type, if (computeJavaType == null) null else fun(): Type { + return when (val javaType = javaType) { is Class<*> -> { // It's either an array or a raw type. // TODO: return upper bound of the corresponding parameter for a raw type? @@ -99,7 +103,7 @@ internal class KTypeImpl( } else -> throw KotlinReflectionInternalError("Non-generic type has been queried for arguments: $this") } - } + }) when (typeProjection.projectionKind) { Variance.INVARIANT -> KTypeProjection.invariant(type) Variance.IN_VARIANCE -> KTypeProjection.contravariant(type) @@ -115,6 +119,13 @@ internal class KTypeImpl( override val annotations: List get() = type.computeAnnotations() + internal fun makeNullableAsSpecified(nullable: Boolean): KTypeImpl { + // If the type is not marked nullable, it's either a non-null type or a platform type. + if (!type.isFlexible() && isMarkedNullable == nullable) return this + + return KTypeImpl(TypeUtils.makeNullableAsSpecified(type, nullable), computeJavaType) + } + override fun equals(other: Any?) = other is KTypeImpl && type == other.type diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeParameterImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeParameterImpl.kt index 1510ec531e6..ac600b3d60e 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeParameterImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeParameterImpl.kt @@ -36,13 +36,7 @@ internal class KTypeParameterImpl( override val name: String get() = descriptor.name.asString() - override val upperBounds: List by ReflectProperties.lazySoft { - descriptor.upperBounds.map { kotlinType -> - KTypeImpl(kotlinType) { - TODO("Java type is not yet supported for type parameters: $descriptor") - } - } - } + override val upperBounds: List by ReflectProperties.lazySoft { descriptor.upperBounds.map(::KTypeImpl) } override val variance: KVariance get() = when (descriptor.variance) { diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectProperties.java b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectProperties.java index 57d097217fa..0326cbc0486 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectProperties.java +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectProperties.java @@ -68,7 +68,7 @@ public class ReflectProperties { // A delegate for a lazy property on a soft reference, whose initializer may be invoked multiple times // including simultaneously from different threads - public static class LazySoftVal extends Val { + public static class LazySoftVal extends Val implements Function0 { private final Function0 initializer; private volatile SoftReference value = null;