Introduce AbstractTypeMapper based on type markers
This commit is contained in:
+1
-1
@@ -26,11 +26,11 @@ import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
||||
import org.jetbrains.kotlin.load.kotlin.computeExpandedTypeForInlineClass
|
||||
import org.jetbrains.kotlin.load.kotlin.mapBuiltInType
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.computeExpandedTypeForInlineClass
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
|
||||
class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapperBase() {
|
||||
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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 org.jetbrains.kotlin.types
|
||||
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.signature.AsmTypeFactory
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmDescriptorTypeWriter
|
||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
||||
import org.jetbrains.kotlin.load.kotlin.mapBuiltInType
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.types.model.*
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
|
||||
interface TypeMappingContext {
|
||||
val typeContext: TypeSystemCommonBackendContextForTypeMapping
|
||||
|
||||
fun getClassInternalName(typeConstructor: TypeConstructorMarker): String
|
||||
fun JvmDescriptorTypeWriter<Type>.writeGenericType(type: SimpleTypeMarker, asmType: Type, mode: TypeMappingMode)
|
||||
}
|
||||
|
||||
object AbstractTypeMapper {
|
||||
fun mapClass(context: TypeMappingContext, typeConstructor: TypeConstructorMarker): Type {
|
||||
return with(context.typeContext) {
|
||||
when {
|
||||
typeConstructor.isClassTypeConstructor() -> {
|
||||
mapType(context, typeConstructor.defaultType(), TypeMappingMode.CLASS_DECLARATION)
|
||||
}
|
||||
typeConstructor.isTypeParameter() -> {
|
||||
mapType(context, typeConstructor.defaultType())
|
||||
}
|
||||
else -> error("Unknown type constructor: $typeConstructor")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
fun TypeSystemCommonBackendContextForTypeMapping.mapType(
|
||||
context: TypeMappingContext,
|
||||
type: SimpleTypeMarker,
|
||||
mode: TypeMappingMode = TypeMappingMode.DEFAULT,
|
||||
sw: JvmDescriptorTypeWriter<Type>? = null
|
||||
): Type {
|
||||
if (type.isSuspendFunction()) {
|
||||
val argumentsCount = type.argumentsCount()
|
||||
val argumentsList = type.asArgumentList()
|
||||
val arguments = buildList {
|
||||
for (i in 0 until (argumentsCount - 1)) {
|
||||
this += argumentsList[i].adjustedType()
|
||||
}
|
||||
this += continuationTypeConstructor().typeWithArguments(argumentsList[argumentsCount - 1].adjustedType())
|
||||
this += nullableAnyType()
|
||||
}
|
||||
val runtimeFunctionType = functionNTypeConstructor(arguments.size - 1).typeWithArguments(arguments)
|
||||
return mapType(context, runtimeFunctionType, mode, sw)
|
||||
}
|
||||
|
||||
mapBuiltInType(type, AsmTypeFactory, mode)?.let { builtInType ->
|
||||
return boxTypeIfNeeded(builtInType, mode.needPrimitiveBoxing).also { asmType ->
|
||||
with(context) { sw?.writeGenericType(type, asmType, mode) }
|
||||
}
|
||||
}
|
||||
|
||||
val typeConstructor = type.typeConstructor()
|
||||
|
||||
when {
|
||||
type.isArrayOrNullableArray() -> {
|
||||
val typeArgument = type.asArgumentList()[0]
|
||||
val (variance, memberType) = when {
|
||||
typeArgument.isStarProjection() -> Variance.OUT_VARIANCE to nullableAnyType()
|
||||
else -> typeArgument.getVariance().toVariance() to typeArgument.getType()
|
||||
}
|
||||
require(memberType is SimpleTypeMarker)
|
||||
|
||||
val arrayElementType: Type
|
||||
sw?.writeArrayType()
|
||||
if (variance == Variance.IN_VARIANCE) {
|
||||
arrayElementType = AsmTypes.OBJECT_TYPE
|
||||
sw?.writeClass(arrayElementType)
|
||||
} else {
|
||||
arrayElementType = mapType(context, memberType, mode.toGenericArgumentMode(variance, ofArray = true), sw)
|
||||
}
|
||||
sw?.writeArrayEnd()
|
||||
return AsmUtil.getArrayType(arrayElementType)
|
||||
}
|
||||
|
||||
typeConstructor.isClassTypeConstructor() -> {
|
||||
if (typeConstructor.isInlineClass() && !mode.needInlineClassWrapping) {
|
||||
val expandedType = computeExpandedTypeForInlineClass(type)
|
||||
require(expandedType is SimpleTypeMarker?)
|
||||
if (expandedType != null) {
|
||||
return mapType(context, expandedType, mode.wrapInlineClassesMode(), sw)
|
||||
}
|
||||
}
|
||||
|
||||
val asmType = if (mode.isForAnnotationParameter && type.isKClass())
|
||||
AsmTypes.JAVA_CLASS_TYPE
|
||||
else
|
||||
Type.getObjectType(context.getClassInternalName(typeConstructor))
|
||||
|
||||
with(context) { sw?.writeGenericType(type, asmType, mode) }
|
||||
return asmType
|
||||
}
|
||||
|
||||
typeConstructor.isTypeParameter() -> {
|
||||
val typeParameter = typeConstructor as TypeParameterMarker
|
||||
return mapType(context, typeParameter.representativeUpperBound(), mode, null).also { asmType ->
|
||||
sw?.writeTypeVariable(typeParameter.getName(), asmType)
|
||||
}
|
||||
}
|
||||
|
||||
else -> throw UnsupportedOperationException("Unknown type $type")
|
||||
}
|
||||
}
|
||||
|
||||
private fun boxTypeIfNeeded(possiblyPrimitiveType: Type, needBoxedType: Boolean): Type =
|
||||
if (needBoxedType) AsmUtil.boxType(possiblyPrimitiveType) else possiblyPrimitiveType
|
||||
|
||||
private fun TypeVariance.toVariance(): Variance = when (this) {
|
||||
TypeVariance.IN -> Variance.IN_VARIANCE
|
||||
TypeVariance.OUT -> Variance.OUT_VARIANCE
|
||||
TypeVariance.INV -> Variance.INVARIANT
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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 org.jetbrains.kotlin.types
|
||||
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||
|
||||
fun TypeSystemCommonBackendContext.computeExpandedTypeForInlineClass(inlineClassType: KotlinTypeMarker): KotlinTypeMarker? =
|
||||
computeExpandedTypeInner(inlineClassType, hashSetOf())
|
||||
|
||||
private fun TypeSystemCommonBackendContext.computeExpandedTypeInner(
|
||||
kotlinType: KotlinTypeMarker, visitedClassifiers: HashSet<TypeConstructorMarker>
|
||||
): KotlinTypeMarker? {
|
||||
val classifier = kotlinType.typeConstructor()
|
||||
if (!visitedClassifiers.add(classifier)) return null
|
||||
|
||||
val typeParameter = classifier.getTypeParameterClassifier()
|
||||
|
||||
return when {
|
||||
typeParameter != null ->
|
||||
computeExpandedTypeInner(typeParameter.getRepresentativeUpperBound(), visitedClassifiers)
|
||||
?.let { expandedUpperBound ->
|
||||
if (expandedUpperBound.isNullableType() || !kotlinType.isMarkedNullable())
|
||||
expandedUpperBound
|
||||
else
|
||||
expandedUpperBound.makeNullable()
|
||||
}
|
||||
|
||||
classifier.isInlineClass() -> {
|
||||
// kotlinType is the boxed inline class type
|
||||
|
||||
val underlyingType = kotlinType.getSubstitutedUnderlyingType() ?: return null
|
||||
val expandedUnderlyingType = computeExpandedTypeInner(underlyingType, visitedClassifiers) ?: return null
|
||||
when {
|
||||
!kotlinType.isNullableType() -> expandedUnderlyingType
|
||||
|
||||
// Here inline class type is nullable. Apply nullability to the expandedUnderlyingType.
|
||||
|
||||
// Nullable types become inline class boxes
|
||||
expandedUnderlyingType.isNullableType() -> kotlinType
|
||||
|
||||
// Primitives become inline class boxes
|
||||
expandedUnderlyingType is SimpleTypeMarker && expandedUnderlyingType.isPrimitiveType() -> kotlinType
|
||||
|
||||
// Non-null reference types become nullable reference types
|
||||
else -> expandedUnderlyingType.makeNullable()
|
||||
}
|
||||
}
|
||||
|
||||
else -> kotlinType
|
||||
}
|
||||
}
|
||||
@@ -50,3 +50,28 @@ interface TypeSystemCommonBackendContext : TypeSystemContext {
|
||||
|
||||
fun KotlinTypeMarker.isInterfaceOrAnnotationClass(): Boolean
|
||||
}
|
||||
|
||||
interface TypeSystemCommonBackendContextForTypeMapping : TypeSystemCommonBackendContext {
|
||||
fun TypeConstructorMarker.isTypeParameter(): Boolean
|
||||
fun TypeConstructorMarker.defaultType(): SimpleTypeMarker
|
||||
|
||||
fun SimpleTypeMarker.isSuspendFunction(): Boolean
|
||||
fun SimpleTypeMarker.isKClass(): Boolean
|
||||
|
||||
fun KotlinTypeMarker.isRawType(): Boolean
|
||||
|
||||
fun TypeConstructorMarker.typeWithArguments(arguments: List<KotlinTypeMarker>): SimpleTypeMarker
|
||||
fun TypeConstructorMarker.typeWithArguments(vararg arguments: KotlinTypeMarker): SimpleTypeMarker {
|
||||
return typeWithArguments(arguments.toList())
|
||||
}
|
||||
|
||||
fun TypeArgumentMarker.adjustedType(): KotlinTypeMarker {
|
||||
if (this.isStarProjection()) return nullableAnyType()
|
||||
return getType()
|
||||
}
|
||||
|
||||
fun TypeParameterMarker.representativeUpperBound(): SimpleTypeMarker
|
||||
|
||||
fun continuationTypeConstructor(): TypeConstructorMarker
|
||||
fun functionNTypeConstructor(n: Int): TypeConstructorMarker
|
||||
}
|
||||
|
||||
@@ -10,11 +10,7 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.resolve.substitutedUnderlyingType
|
||||
import org.jetbrains.kotlin.resolve.unsubstitutedUnderlyingType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
|
||||
|
||||
internal fun computeUnderlyingType(inlineClassType: KotlinType): KotlinType? {
|
||||
@@ -27,52 +23,6 @@ internal fun computeUnderlyingType(inlineClassType: KotlinType): KotlinType? {
|
||||
inlineClassType.substitutedUnderlyingType()
|
||||
}
|
||||
|
||||
fun TypeSystemCommonBackendContext.computeExpandedTypeForInlineClass(inlineClassType: KotlinTypeMarker): KotlinTypeMarker? =
|
||||
computeExpandedTypeInner(inlineClassType, hashSetOf())
|
||||
|
||||
private fun TypeSystemCommonBackendContext.computeExpandedTypeInner(
|
||||
kotlinType: KotlinTypeMarker, visitedClassifiers: HashSet<TypeConstructorMarker>
|
||||
): KotlinTypeMarker? {
|
||||
val classifier = kotlinType.typeConstructor()
|
||||
if (!visitedClassifiers.add(classifier)) return null
|
||||
|
||||
val typeParameter = classifier.getTypeParameterClassifier()
|
||||
|
||||
return when {
|
||||
typeParameter != null ->
|
||||
computeExpandedTypeInner(typeParameter.getRepresentativeUpperBound(), visitedClassifiers)
|
||||
?.let { expandedUpperBound ->
|
||||
if (expandedUpperBound.isNullableType() || !kotlinType.isMarkedNullable())
|
||||
expandedUpperBound
|
||||
else
|
||||
expandedUpperBound.makeNullable()
|
||||
}
|
||||
|
||||
classifier.isInlineClass() -> {
|
||||
// kotlinType is the boxed inline class type
|
||||
|
||||
val underlyingType = kotlinType.getSubstitutedUnderlyingType() ?: return null
|
||||
val expandedUnderlyingType = computeExpandedTypeInner(underlyingType, visitedClassifiers) ?: return null
|
||||
when {
|
||||
!kotlinType.isNullableType() -> expandedUnderlyingType
|
||||
|
||||
// Here inline class type is nullable. Apply nullability to the expandedUnderlyingType.
|
||||
|
||||
// Nullable types become inline class boxes
|
||||
expandedUnderlyingType.isNullableType() -> kotlinType
|
||||
|
||||
// Primitives become inline class boxes
|
||||
expandedUnderlyingType is SimpleTypeMarker && expandedUnderlyingType.isPrimitiveType() -> kotlinType
|
||||
|
||||
// Non-null reference types become nullable reference types
|
||||
else -> expandedUnderlyingType.makeNullable()
|
||||
}
|
||||
}
|
||||
|
||||
else -> kotlinType
|
||||
}
|
||||
}
|
||||
|
||||
internal fun shouldUseUnderlyingType(inlineClassType: KotlinType): Boolean {
|
||||
val underlyingType = inlineClassType.unsubstitutedUnderlyingType() ?: return false
|
||||
|
||||
|
||||
Reference in New Issue
Block a user