diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineIntrinsicsSupport.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineIntrinsicsSupport.kt index 6e18e25da5a..a5536de45bc 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineIntrinsicsSupport.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineIntrinsicsSupport.kt @@ -19,7 +19,7 @@ import org.jetbrains.org.objectweb.asm.Type.INT_TYPE import org.jetbrains.org.objectweb.asm.Type.VOID_TYPE import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter -class PsiInlineIntrinsicsSupport(private val state: GenerationState) : ReifiedTypeInliner.IntrinsicsSupport { +class PsiInlineIntrinsicsSupport(override val state: GenerationState) : ReifiedTypeInliner.IntrinsicsSupport { override fun putClassInstance(v: InstructionAdapter, type: KotlinType) { DescriptorAsmUtil.putJavaLangClassInstance(v, state.typeMapper.mapType(type), type, state.typeMapper) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt index dcd9b1394f2..1d8f64fca5c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.codegen.generateAsCast import org.jetbrains.kotlin.codegen.generateIsCheck import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods import org.jetbrains.kotlin.codegen.optimization.common.intConstant +import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor @@ -63,6 +64,8 @@ class ReifiedTypeInliner( } interface IntrinsicsSupport { + val state: GenerationState + fun putClassInstance(v: InstructionAdapter, type: KT) fun generateTypeParameterContainer(v: InstructionAdapter, typeParameter: TypeParameterMarker) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt index d39e5a50da2..3caf794f446 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt @@ -89,6 +89,15 @@ fun TypeSystemCommonBackendContext.generateTypeOf( } v.invokestatic(REFLECTION, methodName, signature, false) + + if (type.isFlexible() && intrinsicsSupport.state.stableTypeOf) { + // If this is a flexible type, we've just generated its lower bound and have it on the stack. + // Let's generate the upper bound now and call the method that takes lower and upper bound and constructs a flexible KType. + @Suppress("UNCHECKED_CAST") + generateTypeOf(v, type.upperBoundIfFlexible() as KT, intrinsicsSupport) + + v.invokestatic(REFLECTION, "platformType", Type.getMethodDescriptor(K_TYPE, K_TYPE, K_TYPE), false) + } } private fun TypeSystemCommonBackendContext.generateNonReifiedTypeParameter( diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt index a82df7c794f..994118ff34c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt @@ -260,6 +260,10 @@ class GenerationState private constructor( val useKotlinNothingValueException = languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4 && !configuration.getBoolean(JVMConfigurationKeys.NO_KOTLIN_NOTHING_VALUE_EXCEPTION) + + // In 1.6, `typeOf` became stable and started to rely on a few internal stdlib functions which were missing before 1.6. + val stableTypeOf = languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_6 + val samWrapperClasses: SamWrapperClasses = SamWrapperClasses(this) val globalInlineContext: GlobalInlineContext = GlobalInlineContext(diagnostics) val mappingsClassesForWhenByEnum: MappingsClassesForWhenByEnum = MappingsClassesForWhenByEnum(this) diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index cf9c69970ee..9c6c125a367 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -37404,9 +37404,15 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT } @Test - @TestMetadata("flexibleType.kt") - public void testFlexibleType() throws Exception { - runTest("compiler/testData/codegen/box/reflection/typeOf/flexibleType.kt"); + @TestMetadata("flexibleTypes_after.kt") + public void testFlexibleTypes_after() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/flexibleTypes_after.kt"); + } + + @Test + @TestMetadata("flexibleTypes_before.kt") + public void testFlexibleTypes_before() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/flexibleTypes_before.kt"); } @Test @@ -37458,6 +37464,18 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/classes.kt"); } + @Test + @TestMetadata("flexibleTypes_after.kt") + public void testFlexibleTypes_after() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/flexibleTypes_after.kt"); + } + + @Test + @TestMetadata("flexibleTypes_before.kt") + public void testFlexibleTypes_before() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/flexibleTypes_before.kt"); + } + @Test @TestMetadata("inlineClasses.kt") public void testInlineClasses() throws Exception { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineIntrinsicsSupport.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineIntrinsicsSupport.kt index 64933e54658..34cab0b49b3 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineIntrinsicsSupport.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineIntrinsicsSupport.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.jvm.intrinsics.SignatureString import org.jetbrains.kotlin.backend.jvm.lower.FunctionReferenceLowering import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner +import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.toIrBasedKotlinType import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol @@ -29,6 +30,9 @@ class IrInlineIntrinsicsSupport( private val context: JvmBackendContext, private val typeMapper: IrTypeMapper ) : ReifiedTypeInliner.IntrinsicsSupport { + override val state: GenerationState + get() = context.state + override fun putClassInstance(v: InstructionAdapter, type: IrType) { ExpressionCodegen.generateClassInstance(v, type, typeMapper) } diff --git a/compiler/testData/codegen/box/reflection/typeOf/flexibleType.kt b/compiler/testData/codegen/box/reflection/typeOf/flexibleType.kt deleted file mode 100644 index ed6c3d01c6a..00000000000 --- a/compiler/testData/codegen/box/reflection/typeOf/flexibleType.kt +++ /dev/null @@ -1,26 +0,0 @@ -// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi -// TARGET_BACKEND: JVM -// WITH_REFLECT -// FILE: box.kt - -package test - -import kotlin.reflect.* - -fun box(): String { - val v = returnTypeOf { J.get() }.toString() - if (v != "J") return "Fail: $v" - - return "OK" -} - -inline fun returnTypeOf(block: () -> T) = - typeOf() - -// FILE: J.java - -public class J { - public static J get() { - return null; - } -} diff --git a/compiler/testData/codegen/box/reflection/typeOf/flexibleTypes_after.kt b/compiler/testData/codegen/box/reflection/typeOf/flexibleTypes_after.kt new file mode 100644 index 00000000000..87605b96b96 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/flexibleTypes_after.kt @@ -0,0 +1,48 @@ +// !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 + +fun box(): String { + val v1 = returnTypeOf { J.nullabilityFlexible() }.toString() + if (v1 != "kotlin.String!") return "Fail 1: $v1" + + val v2 = returnTypeOf { J.mutabilityFlexible() }.toString() + // TODO: should be (Mutable)List after KT-35877. + if (v2 != "kotlin.collections.List") return "Fail 2: $v2" + + val v3 = returnTypeOf { J.bothFlexible() }.toString() + // TODO: should be (Mutable)List after KT-35877. + if (v3 != "kotlin.collections.List!") return "Fail 3: $v3" + + return "OK" +} + +inline fun returnTypeOf(block: () -> T) = + typeOf() + +// FILE: J.java + +import org.jetbrains.annotations.NotNull; +import java.util.List; + +public class J { + public static String nullabilityFlexible() { + return null; + } + + @NotNull + public static List mutabilityFlexible() { + return null; + } + + public static List bothFlexible() { + return null; + } +} diff --git a/compiler/testData/codegen/box/reflection/typeOf/flexibleTypes_before.kt b/compiler/testData/codegen/box/reflection/typeOf/flexibleTypes_before.kt new file mode 100644 index 00000000000..72ae0a2f5cc --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/flexibleTypes_before.kt @@ -0,0 +1,46 @@ +// !API_VERSION: 1.5 +// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi +// TARGET_BACKEND: JVM +// WITH_REFLECT +// FILE: box.kt + +package test + +import kotlin.reflect.KType +import kotlin.reflect.typeOf + +fun box(): String { + val v1 = returnTypeOf { J.nullabilityFlexible() }.toString() + if (v1 != "kotlin.String") return "Fail 1: $v1" + + val v2 = returnTypeOf { J.mutabilityFlexible() }.toString() + if (v2 != "kotlin.collections.List") return "Fail 2: $v2" + + val v3 = returnTypeOf { J.bothFlexible() }.toString() + if (v3 != "kotlin.collections.List") return "Fail 3: $v3" + + return "OK" +} + +inline fun returnTypeOf(block: () -> T) = + typeOf() + +// FILE: J.java + +import org.jetbrains.annotations.NotNull; +import java.util.List; + +public class J { + public static String nullabilityFlexible() { + return null; + } + + @NotNull + public static List mutabilityFlexible() { + return null; + } + + public static List bothFlexible() { + return null; + } +} diff --git a/compiler/testData/codegen/box/reflection/typeOf/noReflect/flexibleTypes_after.kt b/compiler/testData/codegen/box/reflection/typeOf/noReflect/flexibleTypes_after.kt new file mode 100644 index 00000000000..01813d9b504 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/noReflect/flexibleTypes_after.kt @@ -0,0 +1,53 @@ +// !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 { + // 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", returnTypeOf { J.mutabilityFlexible() }) + check("java.util.List", returnTypeOf { J.bothFlexible() }) + + // However, 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" + + return "OK" +} + +inline fun returnTypeOf(block: () -> T) = + typeOf() + +// FILE: J.java + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.List; + +public class J { + public static String nullabilityFlexible() { return null; } + + @NotNull + public static List mutabilityFlexible() { return null; } + + public static List bothFlexible() { return null; } + + @Nullable + public static String nullable() { return null; } + + @NotNull + public static String notNull() { return null; } +} diff --git a/compiler/testData/codegen/box/reflection/typeOf/noReflect/flexibleTypes_before.kt b/compiler/testData/codegen/box/reflection/typeOf/noReflect/flexibleTypes_before.kt new file mode 100644 index 00000000000..cb77d600c61 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/noReflect/flexibleTypes_before.kt @@ -0,0 +1,52 @@ +// !API_VERSION: 1.5 +// !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("java.lang.String", returnTypeOf { J.nullabilityFlexible() }) + check("java.util.List", returnTypeOf { J.mutabilityFlexible() }) + check("java.util.List", returnTypeOf { J.bothFlexible() }) + + // Before 1.6, typeOf of a flexible type was represented as non-nullable type in stdlib implementation (without reflect). + 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 be equal to non-nullable type" + + return "OK" +} + +inline fun returnTypeOf(block: () -> T) = + typeOf() + +// FILE: J.java + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.List; + +public class J { + public static String nullabilityFlexible() { return null; } + + @NotNull + public static List mutabilityFlexible() { return null; } + + public static List bothFlexible() { return null; } + + @Nullable + public static String nullable() { return null; } + + @NotNull + public static String notNull() { return null; } +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 9c99a9466e2..aaaf25303ba 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -37362,9 +37362,15 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } @Test - @TestMetadata("flexibleType.kt") - public void testFlexibleType() throws Exception { - runTest("compiler/testData/codegen/box/reflection/typeOf/flexibleType.kt"); + @TestMetadata("flexibleTypes_after.kt") + public void testFlexibleTypes_after() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/flexibleTypes_after.kt"); + } + + @Test + @TestMetadata("flexibleTypes_before.kt") + public void testFlexibleTypes_before() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/flexibleTypes_before.kt"); } @Test @@ -37416,6 +37422,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/classes.kt"); } + @Test + @TestMetadata("flexibleTypes_after.kt") + public void testFlexibleTypes_after() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/flexibleTypes_after.kt"); + } + + @Test + @TestMetadata("flexibleTypes_before.kt") + public void testFlexibleTypes_before() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/flexibleTypes_before.kt"); + } + @Test @TestMetadata("inlineClasses.kt") public void testInlineClasses() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 9ee02b37207..262d3e7e399 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -37404,9 +37404,15 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes } @Test - @TestMetadata("flexibleType.kt") - public void testFlexibleType() throws Exception { - runTest("compiler/testData/codegen/box/reflection/typeOf/flexibleType.kt"); + @TestMetadata("flexibleTypes_after.kt") + public void testFlexibleTypes_after() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/flexibleTypes_after.kt"); + } + + @Test + @TestMetadata("flexibleTypes_before.kt") + public void testFlexibleTypes_before() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/flexibleTypes_before.kt"); } @Test @@ -37458,6 +37464,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/classes.kt"); } + @Test + @TestMetadata("flexibleTypes_after.kt") + public void testFlexibleTypes_after() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/flexibleTypes_after.kt"); + } + + @Test + @TestMetadata("flexibleTypes_before.kt") + public void testFlexibleTypes_before() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/flexibleTypes_before.kt"); + } + @Test @TestMetadata("inlineClasses.kt") public void testInlineClasses() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 6a1a60f98dd..2c319c6a599 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -29737,9 +29737,14 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reflection/typeOf/classes.kt"); } - @TestMetadata("flexibleType.kt") - public void testFlexibleType() throws Exception { - runTest("compiler/testData/codegen/box/reflection/typeOf/flexibleType.kt"); + @TestMetadata("flexibleTypes_after.kt") + public void testFlexibleTypes_after() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/flexibleTypes_after.kt"); + } + + @TestMetadata("flexibleTypes_before.kt") + public void testFlexibleTypes_before() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/flexibleTypes_before.kt"); } @TestMetadata("inlineClasses.kt") @@ -29792,6 +29797,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/classes.kt"); } + @TestMetadata("flexibleTypes_after.kt") + public void testFlexibleTypes_after() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/flexibleTypes_after.kt"); + } + + @TestMetadata("flexibleTypes_before.kt") + public void testFlexibleTypes_before() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/flexibleTypes_before.kt"); + } + @TestMetadata("inlineClasses.kt") public void testInlineClasses() throws Exception { runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/inlineClasses.kt"); diff --git a/compiler/util/src/org/jetbrains/kotlin/config/ApiVersion.kt b/compiler/util/src/org/jetbrains/kotlin/config/ApiVersion.kt index d561b503d7b..4e1b4b39794 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/ApiVersion.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/ApiVersion.kt @@ -58,6 +58,9 @@ class ApiVersion private constructor( @JvmField val KOTLIN_1_5 = createByLanguageVersion(LanguageVersion.KOTLIN_1_5) + @JvmField + val KOTLIN_1_6 = createByLanguageVersion(LanguageVersion.KOTLIN_1_6) + @JvmField val LATEST: ApiVersion = createByLanguageVersion(LanguageVersion.values().last()) diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java index c0c492749de..bff10b75f92 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java @@ -146,6 +146,11 @@ public class ReflectionFactoryImpl extends ReflectionFactory { // Do nothing. KTypeParameterImpl implementation will load upper bounds from the metadata. } + // @Override // JPS + public KType platformType(KType lowerBound, KType upperBound) { + return TypeOfImplKt.createPlatformKType(lowerBound, upperBound); + } + // Misc public static void clearCaches() { diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/typeOfImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/typeOfImpl.kt new file mode 100644 index 00000000000..ed7cfc30482 --- /dev/null +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/typeOfImpl.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package kotlin.reflect.jvm.internal + +import org.jetbrains.kotlin.types.KotlinTypeFactory +import org.jetbrains.kotlin.types.SimpleType +import kotlin.reflect.KType + +internal fun createPlatformKType(lowerBound: KType, upperBound: KType): KType { + // lowerBound/upperBound are guaranteed to be KTypeImpl over SimpleType, as long as this function is only used from the bytecode + // generated by the compiler for `typeOf`. + return KTypeImpl( + KotlinTypeFactory.flexibleType( + (lowerBound as KTypeImpl).type as SimpleType, + (upperBound as KTypeImpl).type as SimpleType, + ) + ) +} diff --git a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Reflection.java b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Reflection.java index af4492ed19d..58da1f37ff7 100644 --- a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Reflection.java +++ b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Reflection.java @@ -183,4 +183,11 @@ public class Reflection { public static void setUpperBounds(KTypeParameter typeParameter, KType... bounds) { factory.setUpperBounds(typeParameter, ArraysKt.toList(bounds)); } + + // Features of stable typeOf + + @SinceKotlin(version = "1.6") + public static KType platformType(KType lowerBound, KType upperBound) { + return factory.platformType(lowerBound, upperBound); + } } diff --git a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/ReflectionFactory.java b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/ReflectionFactory.java index 33bd42d3d48..4d5e83404fd 100644 --- a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/ReflectionFactory.java +++ b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/ReflectionFactory.java @@ -93,4 +93,9 @@ public class ReflectionFactory { public void setUpperBounds(KTypeParameter typeParameter, List bounds) { ((TypeParameterReference) typeParameter).setUpperBounds(bounds); } + + @SinceKotlin(version = "1.6") + public KType platformType(KType lowerBound, KType upperBound) { + return new TypeReference(lowerBound.getClassifier(), lowerBound.getArguments(), lowerBound.isMarkedNullable(), upperBound); + } } diff --git a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/TypeReference.kt b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/TypeReference.kt index ecc1dea74be..9e261fdf1b6 100644 --- a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/TypeReference.kt +++ b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/TypeReference.kt @@ -3,22 +3,32 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NEWER_VERSION_IN_SINCE_KOTLIN") + package kotlin.jvm.internal import kotlin.reflect.* @SinceKotlin("1.4") -public class TypeReference( +public class TypeReference /* @SinceKotlin("1.6") constructor */( override val classifier: KClassifier, override val arguments: List, - override val isMarkedNullable: Boolean + override val isMarkedNullable: Boolean, + private val platformTypeUpperBound: KType?, ) : KType { + constructor( + classifier: KClassifier, + arguments: List, + isMarkedNullable: Boolean, + ) : this(classifier, arguments, isMarkedNullable, null) + override val annotations: List get() = emptyList() override fun equals(other: Any?): Boolean = other is TypeReference && - classifier == other.classifier && arguments == other.arguments && isMarkedNullable == other.isMarkedNullable + classifier == other.classifier && arguments == other.arguments && isMarkedNullable == other.isMarkedNullable && + platformTypeUpperBound == other.platformTypeUpperBound override fun hashCode(): Int = (classifier.hashCode() * 31 + arguments.hashCode()) * 31 + isMarkedNullable.hashCode() diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt index 0ccd542d815..6dba8e931a4 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt @@ -3995,6 +3995,7 @@ public class kotlin/jvm/internal/Reflection { public static fun nullableTypeOf (Ljava/lang/Class;Lkotlin/reflect/KTypeProjection;Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType; public static fun nullableTypeOf (Ljava/lang/Class;[Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType; public static fun nullableTypeOf (Lkotlin/reflect/KClassifier;)Lkotlin/reflect/KType; + public static fun platformType (Lkotlin/reflect/KType;Lkotlin/reflect/KType;)Lkotlin/reflect/KType; public static fun property0 (Lkotlin/jvm/internal/PropertyReference0;)Lkotlin/reflect/KProperty0; public static fun property1 (Lkotlin/jvm/internal/PropertyReference1;)Lkotlin/reflect/KProperty1; public static fun property2 (Lkotlin/jvm/internal/PropertyReference2;)Lkotlin/reflect/KProperty2; @@ -4021,6 +4022,7 @@ public class kotlin/jvm/internal/ReflectionFactory { public fun mutableProperty0 (Lkotlin/jvm/internal/MutablePropertyReference0;)Lkotlin/reflect/KMutableProperty0; public fun mutableProperty1 (Lkotlin/jvm/internal/MutablePropertyReference1;)Lkotlin/reflect/KMutableProperty1; public fun mutableProperty2 (Lkotlin/jvm/internal/MutablePropertyReference2;)Lkotlin/reflect/KMutableProperty2; + public fun platformType (Lkotlin/reflect/KType;Lkotlin/reflect/KType;)Lkotlin/reflect/KType; public fun property0 (Lkotlin/jvm/internal/PropertyReference0;)Lkotlin/reflect/KProperty0; public fun property1 (Lkotlin/jvm/internal/PropertyReference1;)Lkotlin/reflect/KProperty1; public fun property2 (Lkotlin/jvm/internal/PropertyReference2;)Lkotlin/reflect/KProperty2; @@ -4120,6 +4122,7 @@ public final class kotlin/jvm/internal/TypeParameterReference$Companion { public final class kotlin/jvm/internal/TypeReference : kotlin/reflect/KType { public fun (Lkotlin/reflect/KClassifier;Ljava/util/List;Z)V + public fun (Lkotlin/reflect/KClassifier;Ljava/util/List;ZLkotlin/reflect/KType;)V public fun equals (Ljava/lang/Object;)Z public fun getAnnotations ()Ljava/util/List; public fun getArguments ()Ljava/util/List;