Support mapping for inline classes based on type variables
This commit is contained in:
@@ -477,7 +477,7 @@ public class KotlinTypeMapper {
|
||||
|
||||
@NotNull
|
||||
public static Type mapUnderlyingTypeOfInlineClassType(@NotNull KotlinType kotlinType) {
|
||||
KotlinType underlyingType = InlineClassesUtilsKt.underlyingTypeOfInlineClassType(kotlinType);
|
||||
KotlinType underlyingType = InlineClassesUtilsKt.unsubstitutedUnderlyingType(kotlinType);
|
||||
if (underlyingType == null) {
|
||||
throw new IllegalStateException("There should be underlying type for inline class type: " + kotlinType);
|
||||
}
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
|
||||
inline class Foo<T>(val x: List<T>)
|
||||
|
||||
object Test {
|
||||
fun nonNullTypeArgument(f: Foo<Int>) {}
|
||||
fun nullableTypeArgument(f: Foo<String?>) {}
|
||||
|
||||
fun nullableValue(f: Foo<Long>?) {}
|
||||
}
|
||||
|
||||
// method: Test::nonNullTypeArgument
|
||||
// jvm signature: (Ljava/util/List;)V
|
||||
// generic signature: (Ljava/util/List<Ljava/lang/Integer;>;)V
|
||||
|
||||
// method: Test::nullableTypeArgument
|
||||
// jvm signature: (Ljava/util/List;)V
|
||||
// generic signature: (Ljava/util/List<Ljava/lang/String;>;)V
|
||||
|
||||
// method: Test::nullableValue
|
||||
// jvm signature: (Ljava/util/List;)V
|
||||
// generic signature: (Ljava/util/List<Ljava/lang/Long;>;)V
|
||||
|
||||
// method: Foo$Erased::box
|
||||
// jvm signature: (Ljava/util/List;)LFoo;
|
||||
// generic signature: null
|
||||
|
||||
// method: Foo::unbox
|
||||
// jvm signature: ()Ljava/util/List;
|
||||
// generic signature: ()Ljava/util/List<TT;>;
|
||||
Vendored
+43
@@ -0,0 +1,43 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
|
||||
inline class Default<T>(val x: T)
|
||||
|
||||
class Inv<T>
|
||||
|
||||
object Test {
|
||||
fun withNotNullPrimitive(a: Default<Int>) {}
|
||||
fun withAdditionalGenericParameter(x: Inv<String>, y: Default<String>) {}
|
||||
|
||||
fun asNullable(a: Default<Int>?) {}
|
||||
|
||||
fun asNullableTypeArgument(a: Default<Int?>) {}
|
||||
fun asNullableAndNullableTypeArgument(a: Default<Int?>?) {}
|
||||
}
|
||||
|
||||
// method: Test::withNotNullPrimitive
|
||||
// jvm signature: (Ljava/lang/Object;)V
|
||||
// generic signature: null
|
||||
|
||||
// method: Test::withAdditionalGenericParameter
|
||||
// jvm signature: (LInv;Ljava/lang/Object;)V
|
||||
// generic signature: (LInv<Ljava/lang/String;>;Ljava/lang/Object;)V
|
||||
|
||||
// method: Test::asNullable
|
||||
// jvm signature: (LDefault;)V
|
||||
// generic signature: (LDefault<Ljava/lang/Integer;>;)V
|
||||
|
||||
// method: Test::asNullableTypeArgument
|
||||
// jvm signature: (Ljava/lang/Object;)V
|
||||
// generic signature: null
|
||||
|
||||
// method: Test::asNullableAndNullableTypeArgument
|
||||
// jvm signature: (LDefault;)V
|
||||
// generic signature: (LDefault<Ljava/lang/Integer;>;)V
|
||||
|
||||
// method: Default$Erased:box
|
||||
// jvm signature: (Ljava/lang/Object;)LDefault;
|
||||
// generic signature: null
|
||||
|
||||
// method: Default:unbox
|
||||
// jvm signature: ()Ljava/lang/Object
|
||||
// generic signature: null
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
|
||||
inline class NonNull<T : Any>(val x: T)
|
||||
inline class NullableValue<T : Any>(val x: T?)
|
||||
|
||||
object Test {
|
||||
fun withNotNullPrimitive(a: NonNull<Int>) {}
|
||||
fun asNullable(a: NonNull<Int>?) {}
|
||||
|
||||
fun withNotNullForNullableValue(a: NullableValue<Int>) {}
|
||||
fun asNullableForNullableValue(a: NullableValue<Int>?) {}
|
||||
}
|
||||
|
||||
// method: Test::withNotNullPrimitive
|
||||
// jvm signature: (Ljava/lang/Object;)V
|
||||
// generic signature: null
|
||||
|
||||
// method: Test::asNullable
|
||||
// jvm signature: (Ljava/lang/Object;)V
|
||||
// generic signature: null
|
||||
|
||||
// method: Test::withNotNullForNullableValue
|
||||
// jvm signature: (Ljava/lang/Object;)V
|
||||
// generic signature: null
|
||||
|
||||
// method: Test::asNullableForNullableValue
|
||||
// jvm signature: (LNullableValue;)V
|
||||
// generic signature: (LNullableValue<Ljava/lang/Integer;>;)V
|
||||
@@ -1944,6 +1944,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassCallsDefaultValue.kt")
|
||||
public void testInlineClassCallsDefaultValue() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassCallsDefaultValue.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("unboxInlineClassAfterSafeCall.kt")
|
||||
public void testUnboxInlineClassAfterSafeCall() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassAfterSafeCall.kt");
|
||||
|
||||
+18
@@ -564,6 +564,24 @@ public class WriteSignatureTestGenerated extends AbstractWriteSignatureTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("genericInlineClassBasedOnGenericType.kt")
|
||||
public void testGenericInlineClassBasedOnGenericType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/inlineClasses/genericInlineClassBasedOnGenericType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("genericInlineClassWithDefaultTypeParameter.kt")
|
||||
public void testGenericInlineClassWithDefaultTypeParameter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/inlineClasses/genericInlineClassWithDefaultTypeParameter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("genericInlineClassWithNotNullTypeParameter.kt")
|
||||
public void testGenericInlineClassWithNotNullTypeParameter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/inlineClasses/genericInlineClassWithNotNullTypeParameter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nullableInlineClassType.kt")
|
||||
public void testNullableInlineClassType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/inlineClasses/nullableInlineClassType.kt");
|
||||
|
||||
@@ -19,7 +19,8 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.kotlin.resolve.underlyingRepresentation
|
||||
import org.jetbrains.kotlin.resolve.substitutedUnderlyingType
|
||||
import org.jetbrains.kotlin.resolve.unsubstitutedUnderlyingType
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
|
||||
import org.jetbrains.kotlin.utils.DO_NOTHING_3
|
||||
@@ -130,15 +131,9 @@ fun <T : Any> mapType(
|
||||
|
||||
descriptor is ClassDescriptor -> {
|
||||
if (descriptor.isInline && !mode.needInlineClassWrapping) {
|
||||
val underlyingType = descriptor.underlyingRepresentation()?.type
|
||||
if (underlyingType != null) {
|
||||
if (!kotlinType.isMarkedNullable) {
|
||||
return mapType(underlyingType, factory, mode, typeMappingConfiguration, descriptorTypeWriter, writeGenericType)
|
||||
}
|
||||
|
||||
if (!underlyingType.isMarkedNullable && !KotlinBuiltIns.isPrimitiveType(underlyingType)) {
|
||||
return mapType(underlyingType, factory, mode, typeMappingConfiguration, descriptorTypeWriter, writeGenericType)
|
||||
}
|
||||
val typeForMapping = computeUnderlyingType(kotlinType)
|
||||
if (typeForMapping != null) {
|
||||
return mapType(typeForMapping, factory, mode, typeMappingConfiguration, descriptorTypeWriter, writeGenericType)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,6 +209,23 @@ private fun <T : Any> mapBuiltInType(type: KotlinType, typeFactory: JvmTypeFacto
|
||||
return null
|
||||
}
|
||||
|
||||
private fun computeUnderlyingType(inlineClassType: KotlinType): KotlinType? {
|
||||
if (!shouldUseUnderlyingType(inlineClassType)) return null
|
||||
|
||||
val descriptor = inlineClassType.unsubstitutedUnderlyingType()?.constructor?.declarationDescriptor ?: return null
|
||||
return if (descriptor is TypeParameterDescriptor)
|
||||
getRepresentativeUpperBound(descriptor)
|
||||
else
|
||||
inlineClassType.substitutedUnderlyingType()
|
||||
}
|
||||
|
||||
private fun shouldUseUnderlyingType(inlineClassType: KotlinType): Boolean {
|
||||
val underlyingType = inlineClassType.unsubstitutedUnderlyingType() ?: return false
|
||||
|
||||
return !inlineClassType.isMarkedNullable ||
|
||||
!TypeUtils.isNullableType(underlyingType) && !KotlinBuiltIns.isPrimitiveType(underlyingType)
|
||||
}
|
||||
|
||||
fun computeInternalName(
|
||||
klass: ClassDescriptor,
|
||||
typeMappingConfiguration: TypeMappingConfiguration<*> = TypeMappingConfigurationImpl
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.resolve
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
@@ -18,8 +19,15 @@ fun ClassDescriptor.underlyingRepresentation(): ValueParameterDescriptor? {
|
||||
|
||||
fun DeclarationDescriptor.isInlineClass() = this is ClassDescriptor && this.isInline
|
||||
|
||||
fun KotlinType.underlyingTypeOfInlineClassType(): KotlinType? {
|
||||
return constructor.declarationDescriptor.safeAs<ClassDescriptor>()?.underlyingRepresentation()?.type
|
||||
fun KotlinType.unsubstitutedUnderlyingParameter(): ValueParameterDescriptor? {
|
||||
return constructor.declarationDescriptor.safeAs<ClassDescriptor>()?.underlyingRepresentation()
|
||||
}
|
||||
|
||||
fun KotlinType.isInlineClassType(): Boolean = constructor.declarationDescriptor?.isInlineClass() ?: false
|
||||
fun KotlinType.unsubstitutedUnderlyingType(): KotlinType? = unsubstitutedUnderlyingParameter()?.type
|
||||
|
||||
fun KotlinType.isInlineClassType(): Boolean = constructor.declarationDescriptor?.isInlineClass() ?: false
|
||||
|
||||
fun KotlinType.substitutedUnderlyingType(): KotlinType? {
|
||||
val parameter = unsubstitutedUnderlyingParameter() ?: return null
|
||||
return memberScope.getContributedVariables(parameter.name, NoLookupLocation.FOR_ALREADY_TRACKED).singleOrNull()?.type
|
||||
}
|
||||
Reference in New Issue
Block a user