Support mutable collection types in typeOf

flexibleTypes_1_6.kt is fixed for JVM IR in a subsequent commit.

 #KT-35877 Fixed
This commit is contained in:
Alexander Udalov
2021-05-21 20:39:29 +02:00
parent 6e975b3498
commit 0cb905a4b1
19 changed files with 327 additions and 15 deletions
@@ -5,12 +5,14 @@
package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.model.TypeParameterMarker
@@ -56,5 +58,10 @@ class PsiInlineIntrinsicsSupport(override val state: GenerationState) : ReifiedT
)
}
override fun isMutableCollectionType(type: KotlinType): Boolean {
val classifier = type.constructor.declarationDescriptor
return classifier is ClassDescriptor && JavaToKotlinClassMap.isMutable(classifier.fqNameUnsafe)
}
override fun toKotlinType(type: KotlinType): KotlinType = type
}
@@ -70,6 +70,8 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
fun generateTypeParameterContainer(v: InstructionAdapter, typeParameter: TypeParameterMarker)
fun isMutableCollectionType(type: KT): Boolean
fun toKotlinType(type: KT): KotlinType
}
@@ -90,13 +90,19 @@ fun <KT : KotlinTypeMarker> 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)
if (intrinsicsSupport.state.stableTypeOf) {
if (intrinsicsSupport.isMutableCollectionType(type)) {
v.invokestatic(REFLECTION, "mutableCollectionType", Type.getMethodDescriptor(K_TYPE, K_TYPE), false)
}
v.invokestatic(REFLECTION, "platformType", Type.getMethodDescriptor(K_TYPE, K_TYPE, K_TYPE), false)
if (type.isFlexible()) {
// 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)
}
}
}
@@ -37433,6 +37433,18 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
}
@Test
@TestMetadata("mutableCollections_after.kt")
public void testMutableCollections_after() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/mutableCollections_after.kt");
}
@Test
@TestMetadata("mutableCollections_before.kt")
public void testMutableCollections_before() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/mutableCollections_before.kt");
}
@Test
@TestMetadata("typeOfCapturedStar.kt")
public void testTypeOfCapturedStar() throws Exception {
@@ -37482,6 +37494,18 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/inlineClasses.kt");
}
@Test
@TestMetadata("mutableCollections_after.kt")
public void testMutableCollections_after() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/mutableCollections_after.kt");
}
@Test
@TestMetadata("mutableCollections_before.kt")
public void testMutableCollections_before() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/mutableCollections_before.kt");
}
@Test
@TestMetadata("typeReferenceEqualsHashCode.kt")
public void testTypeReferenceEqualsHashCode() throws Exception {
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.ir.allParametersCount
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.intrinsics.SignatureString
import org.jetbrains.kotlin.backend.jvm.lower.FunctionReferenceLowering
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
import org.jetbrains.kotlin.codegen.state.GenerationState
@@ -16,7 +17,9 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.toIrBasedKotlinType
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
import org.jetbrains.kotlin.types.KotlinType
@@ -98,5 +101,10 @@ class IrInlineIntrinsicsSupport(
)
}
override fun isMutableCollectionType(type: IrType): Boolean {
val classifier = type.classOrNull
return classifier != null && JavaToKotlinClassMap.isMutable(classifier.owner.fqNameWhenAvailable?.toUnsafe())
}
override fun toKotlinType(type: IrType): KotlinType = type.toIrBasedKotlinType()
}
@@ -1,6 +1,8 @@
// !API_VERSION: LATEST
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_REFLECT
// FILE: box.kt
@@ -14,12 +16,10 @@ fun box(): String {
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<kotlin.String!>") return "Fail 2: $v2"
if (v2 != "kotlin.collections.(Mutable)List<kotlin.String!>") return "Fail 2: $v2"
val v3 = returnTypeOf { J.bothFlexible() }.toString()
// TODO: should be (Mutable)List after KT-35877.
if (v3 != "kotlin.collections.List<kotlin.String!>!") return "Fail 3: $v3"
if (v3 != "kotlin.collections.(Mutable)List<kotlin.String!>!") return "Fail 3: $v3"
return "OK"
}
@@ -0,0 +1,36 @@
// !API_VERSION: LATEST
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JVM
// WITH_REFLECT
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.collections.Iterable<kotlin.Number>", typeOf<Iterable<Number>>())
check("kotlin.collections.Iterator<kotlin.CharSequence>", typeOf<Iterator<CharSequence>>())
check("kotlin.collections.Collection<kotlin.Char>", typeOf<Collection<Char>>())
check("kotlin.collections.List<kotlin.String>", typeOf<List<String>>())
check("kotlin.collections.Set<kotlin.Double?>", typeOf<Set<Double?>>())
check("kotlin.collections.ListIterator<kotlin.Any>", typeOf<ListIterator<Any>>())
check("kotlin.collections.Map<kotlin.Int, kotlin.Unit>", typeOf<Map<Int, Unit>>())
check("kotlin.collections.Map.Entry<kotlin.Byte?, kotlin.collections.Set<*>>", typeOf<Map.Entry<Byte?, Set<*>>>())
check("kotlin.collections.MutableIterable<kotlin.Number>", typeOf<MutableIterable<Number>>())
check("kotlin.collections.MutableIterator<kotlin.CharSequence>", typeOf<MutableIterator<CharSequence>>())
check("kotlin.collections.MutableCollection<kotlin.Char>", typeOf<MutableCollection<Char>>())
check("kotlin.collections.MutableList<kotlin.String>", typeOf<MutableList<String>>())
check("kotlin.collections.MutableSet<kotlin.Double?>", typeOf<MutableSet<Double?>>())
check("kotlin.collections.MutableListIterator<kotlin.Any>", typeOf<MutableListIterator<Any>>())
check("kotlin.collections.MutableMap<kotlin.Int, kotlin.Unit>", typeOf<MutableMap<Int, Unit>>())
check("kotlin.collections.MutableMap.MutableEntry<kotlin.Byte?, kotlin.collections.Set<*>>", typeOf<MutableMap.MutableEntry<Byte?, Set<*>>>())
return "OK"
}
@@ -0,0 +1,36 @@
// !API_VERSION: 1.5
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JVM
// WITH_REFLECT
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.collections.Iterable<kotlin.Number>", typeOf<Iterable<Number>>())
check("kotlin.collections.Iterator<kotlin.CharSequence>", typeOf<Iterator<CharSequence>>())
check("kotlin.collections.Collection<kotlin.Char>", typeOf<Collection<Char>>())
check("kotlin.collections.List<kotlin.String>", typeOf<List<String>>())
check("kotlin.collections.Set<kotlin.Double?>", typeOf<Set<Double?>>())
check("kotlin.collections.ListIterator<kotlin.Any>", typeOf<ListIterator<Any>>())
check("kotlin.collections.Map<kotlin.Int, kotlin.Unit>", typeOf<Map<Int, Unit>>())
check("kotlin.collections.Map.Entry<kotlin.Byte?, kotlin.collections.Set<*>>", typeOf<Map.Entry<Byte?, Set<*>>>())
check("kotlin.collections.Iterable<kotlin.Number>", typeOf<MutableIterable<Number>>())
check("kotlin.collections.Iterator<kotlin.CharSequence>", typeOf<MutableIterator<CharSequence>>())
check("kotlin.collections.Collection<kotlin.Char>", typeOf<MutableCollection<Char>>())
check("kotlin.collections.List<kotlin.String>", typeOf<MutableList<String>>())
check("kotlin.collections.Set<kotlin.Double?>", typeOf<MutableSet<Double?>>())
check("kotlin.collections.ListIterator<kotlin.Any>", typeOf<MutableListIterator<Any>>())
check("kotlin.collections.Map<kotlin.Int, kotlin.Unit>", typeOf<MutableMap<Int, Unit>>())
check("kotlin.collections.Map.Entry<kotlin.Byte?, kotlin.collections.Set<*>>", typeOf<MutableMap.MutableEntry<Byte?, Set<*>>>())
return "OK"
}
@@ -0,0 +1,38 @@
// !API_VERSION: LATEST
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JVM
// WITH_RUNTIME
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.Iterable<java.lang.Number>", typeOf<Iterable<Number>>())
check("java.util.Iterator<java.lang.CharSequence>", typeOf<Iterator<CharSequence>>())
// TODO: java.util.Collection<java.lang.Character>
check("java.util.Collection<char>", typeOf<Collection<Char>>())
check("java.util.List<java.lang.String>", typeOf<List<String>>())
check("java.util.Set<java.lang.Double?>", typeOf<Set<Double?>>())
check("java.util.ListIterator<java.lang.Object>", typeOf<ListIterator<Any>>())
// TODO: java.util.Map<java.lang.Integer, kotlin.Unit>
check("java.util.Map<int, kotlin.Unit>", typeOf<Map<Int, Unit>>())
check("java.util.Map\$Entry<java.lang.Byte?, java.util.Set<*>>", typeOf<Map.Entry<Byte?, Set<*>>>())
check("java.lang.Iterable<java.lang.Number>", typeOf<MutableIterable<Number>>())
check("java.util.Iterator<java.lang.CharSequence>", typeOf<MutableIterator<CharSequence>>())
check("java.util.Collection<char>", typeOf<MutableCollection<Char>>())
check("java.util.List<java.lang.String>", typeOf<MutableList<String>>())
check("java.util.Set<java.lang.Double?>", typeOf<MutableSet<Double?>>())
check("java.util.ListIterator<java.lang.Object>", typeOf<MutableListIterator<Any>>())
check("java.util.Map<int, kotlin.Unit>", typeOf<MutableMap<Int, Unit>>())
check("java.util.Map\$Entry<java.lang.Byte?, java.util.Set<*>>", typeOf<MutableMap.MutableEntry<Byte?, Set<*>>>())
return "OK"
}
@@ -0,0 +1,38 @@
// !API_VERSION: 1.5
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JVM
// WITH_RUNTIME
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.Iterable<java.lang.Number>", typeOf<Iterable<Number>>())
check("java.util.Iterator<java.lang.CharSequence>", typeOf<Iterator<CharSequence>>())
// TODO: java.util.Collection<java.lang.Character>
check("java.util.Collection<char>", typeOf<Collection<Char>>())
check("java.util.List<java.lang.String>", typeOf<List<String>>())
check("java.util.Set<java.lang.Double?>", typeOf<Set<Double?>>())
check("java.util.ListIterator<java.lang.Object>", typeOf<ListIterator<Any>>())
// TODO: java.util.Map<java.lang.Integer, kotlin.Unit>
check("java.util.Map<int, kotlin.Unit>", typeOf<Map<Int, Unit>>())
check("java.util.Map\$Entry<java.lang.Byte?, java.util.Set<*>>", typeOf<Map.Entry<Byte?, Set<*>>>())
check("java.lang.Iterable<java.lang.Number>", typeOf<MutableIterable<Number>>())
check("java.util.Iterator<java.lang.CharSequence>", typeOf<MutableIterator<CharSequence>>())
check("java.util.Collection<char>", typeOf<MutableCollection<Char>>())
check("java.util.List<java.lang.String>", typeOf<MutableList<String>>())
check("java.util.Set<java.lang.Double?>", typeOf<MutableSet<Double?>>())
check("java.util.ListIterator<java.lang.Object>", typeOf<MutableListIterator<Any>>())
check("java.util.Map<int, kotlin.Unit>", typeOf<MutableMap<Int, Unit>>())
check("java.util.Map\$Entry<java.lang.Byte?, java.util.Set<*>>", typeOf<MutableMap.MutableEntry<Byte?, Set<*>>>())
return "OK"
}
@@ -37391,6 +37391,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
}
@Test
@TestMetadata("mutableCollections_after.kt")
public void testMutableCollections_after() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/mutableCollections_after.kt");
}
@Test
@TestMetadata("mutableCollections_before.kt")
public void testMutableCollections_before() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/mutableCollections_before.kt");
}
@Test
@TestMetadata("typeOfCapturedStar.kt")
public void testTypeOfCapturedStar() throws Exception {
@@ -37440,6 +37452,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/inlineClasses.kt");
}
@Test
@TestMetadata("mutableCollections_after.kt")
public void testMutableCollections_after() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/mutableCollections_after.kt");
}
@Test
@TestMetadata("mutableCollections_before.kt")
public void testMutableCollections_before() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/mutableCollections_before.kt");
}
@Test
@TestMetadata("typeReferenceEqualsHashCode.kt")
public void testTypeReferenceEqualsHashCode() throws Exception {
@@ -37433,6 +37433,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
}
@Test
@TestMetadata("mutableCollections_after.kt")
public void testMutableCollections_after() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/mutableCollections_after.kt");
}
@Test
@TestMetadata("mutableCollections_before.kt")
public void testMutableCollections_before() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/mutableCollections_before.kt");
}
@Test
@TestMetadata("typeOfCapturedStar.kt")
public void testTypeOfCapturedStar() throws Exception {
@@ -37482,6 +37494,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/inlineClasses.kt");
}
@Test
@TestMetadata("mutableCollections_after.kt")
public void testMutableCollections_after() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/mutableCollections_after.kt");
}
@Test
@TestMetadata("mutableCollections_before.kt")
public void testMutableCollections_before() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/mutableCollections_before.kt");
}
@Test
@TestMetadata("typeReferenceEqualsHashCode.kt")
public void testTypeReferenceEqualsHashCode() throws Exception {
@@ -29762,6 +29762,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
}
@TestMetadata("mutableCollections_after.kt")
public void testMutableCollections_after() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/mutableCollections_after.kt");
}
@TestMetadata("mutableCollections_before.kt")
public void testMutableCollections_before() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/mutableCollections_before.kt");
}
@TestMetadata("typeOfCapturedStar.kt")
public void testTypeOfCapturedStar() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/typeOfCapturedStar.kt");
@@ -29812,6 +29822,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/inlineClasses.kt");
}
@TestMetadata("mutableCollections_after.kt")
public void testMutableCollections_after() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/mutableCollections_after.kt");
}
@TestMetadata("mutableCollections_before.kt")
public void testMutableCollections_before() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/mutableCollections_before.kt");
}
@TestMetadata("typeReferenceEqualsHashCode.kt")
public void testTypeReferenceEqualsHashCode() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCode.kt");