Support mapping for inline classes based on type variables

This commit is contained in:
Mikhail Zarechenskiy
2018-02-05 18:43:38 +03:00
parent 0fd80ce980
commit 4eb64fb4b9
8 changed files with 159 additions and 14 deletions
@@ -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
}