From 86d4d320c4d077c73025a0343834a493162e01e0 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Tue, 22 Sep 2020 18:20:57 +0300 Subject: [PATCH] Introduce AbstractTypeMapper based on type markers --- .../backend/jvm/codegen/IrTypeMapper.kt | 2 +- .../kotlin/types/AbstractTypeMapper.kt | 126 ++++++++++++++++++ .../kotlin/types/expandedTypeUtils.kt | 56 ++++++++ .../types/TypeSystemCommonBackendContext.kt | 25 ++++ .../kotlin/load/kotlin/inlineClassMapping.kt | 50 ------- 5 files changed, 208 insertions(+), 51 deletions(-) create mode 100644 core/compiler.backend.common.jvm/src/org/jetbrains/kotlin/types/AbstractTypeMapper.kt create mode 100644 core/compiler.common.jvm/src/org/jetbrains/kotlin/types/expandedTypeUtils.kt diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt index e38d4cca4d1..0dcbcb265fe 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt @@ -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() { diff --git a/core/compiler.backend.common.jvm/src/org/jetbrains/kotlin/types/AbstractTypeMapper.kt b/core/compiler.backend.common.jvm/src/org/jetbrains/kotlin/types/AbstractTypeMapper.kt new file mode 100644 index 00000000000..dbb1e612280 --- /dev/null +++ b/core/compiler.backend.common.jvm/src/org/jetbrains/kotlin/types/AbstractTypeMapper.kt @@ -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.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? = 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 + } +} diff --git a/core/compiler.common.jvm/src/org/jetbrains/kotlin/types/expandedTypeUtils.kt b/core/compiler.common.jvm/src/org/jetbrains/kotlin/types/expandedTypeUtils.kt new file mode 100644 index 00000000000..c2641ad326c --- /dev/null +++ b/core/compiler.common.jvm/src/org/jetbrains/kotlin/types/expandedTypeUtils.kt @@ -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 +): 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 + } +} diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt index d1d934b569d..08ede6e58cd 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt @@ -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): 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 +} diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/inlineClassMapping.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/inlineClassMapping.kt index 1f8509d299b..1586934a6b9 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/inlineClassMapping.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/inlineClassMapping.kt @@ -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 -): 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