From a15575d5467ec7a5372553d2414f494b04c8e6b5 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 14 May 2019 18:36:15 +0200 Subject: [PATCH] JVM IR: do not use KotlinTypeMapper in IrTypeMapper.mapType --- .../kotlin/codegen/state/KotlinTypeMapper.kt | 2 +- .../backend/jvm/codegen/IrTypeMapper.kt | 226 +++++++++++++++++- .../backend/jvm/codegen/IrTypeMapping.kt | 58 ++++- .../backend/jvm/intrinsics/UnsafeCoerce.kt | 13 +- .../lower/FunctionNVarargInvokeLowering.kt | 4 +- .../ir/symbols/IrClassifierEqualityChecker.kt | 22 +- .../kotlin/ir/types/IrTypeSystemContext.kt | 71 +++++- .../org/jetbrains/kotlin/ir/util/IrUtils.kt | 11 + 8 files changed, 368 insertions(+), 39 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt index b6f2bc524f3..54b5e35aab0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt @@ -1433,7 +1433,7 @@ class KotlinTypeMapper @JvmOverloads constructor( private fun hasNothingInNonContravariantPosition(kotlinType: KotlinType): Boolean = SimpleClassicTypeSystemContext.hasNothingInNonContravariantPosition(kotlinType) - private fun TypeSystemContext.hasNothingInNonContravariantPosition(type: KotlinTypeMarker): Boolean { + fun TypeSystemContext.hasNothingInNonContravariantPosition(type: KotlinTypeMarker): Boolean { val typeConstructor = type.typeConstructor() for (i in 0 until type.argumentsCount()) { 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 777fd91b00b..3d8fb59e9d6 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 @@ -6,40 +6,65 @@ package org.jetbrains.kotlin.backend.jvm.codegen import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor +import org.jetbrains.kotlin.builtins.isSuspendFunctionType +import org.jetbrains.kotlin.builtins.transformSuspendFunctionToRuntimeFunctionType import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.kotlin.codegen.ClassBuilderMode +import org.jetbrains.kotlin.codegen.JvmCodegenUtil import org.jetbrains.kotlin.codegen.OwnerKind +import org.jetbrains.kotlin.codegen.signature.AsmTypeFactory import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.toKotlinType +import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol +import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.types.impl.originalKotlinType +import org.jetbrains.kotlin.ir.util.defaultType +import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable 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.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.kotlin.types.Variance import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.Method class IrTypeMapper(private val context: JvmBackendContext) { val kotlinTypeMapper: KotlinTypeMapper = context.state.typeMapper + private val typeSystem = IrTypeCheckerContext(context.irBuiltIns) - val classBuilderMode get() = kotlinTypeMapper.classBuilderMode + val classBuilderMode: ClassBuilderMode + get() = kotlinTypeMapper.classBuilderMode - fun classInternalName(irClass: IrClass) = kotlinTypeMapper.classInternalName(irClass.descriptor) + fun classInternalName(irClass: IrClass): String = + context.getLocalClassInfo(irClass)?.internalName + ?: JvmCodegenUtil.sanitizeNameIfNeeded(computeInternalName(irClass), context.state.languageVersionSettings) - fun mapAsmMethod(irFunction: IrFunction) = kotlinTypeMapper.mapAsmMethod(irFunction.descriptor) + fun mapAsmMethod(irFunction: IrFunction): Method = + kotlinTypeMapper.mapAsmMethod(irFunction.descriptor) fun mapFieldSignature(irField: IrField) = kotlinTypeMapper.mapFieldSignature(irField.type.toKotlinType(), irField.descriptor) - fun mapFunctionName(irReturnTarget: IrReturnTarget, ownerKind: OwnerKind) = + fun mapFunctionName(irReturnTarget: IrReturnTarget, ownerKind: OwnerKind): String = kotlinTypeMapper.mapFunctionName(irReturnTarget.descriptor, ownerKind) - fun mapImplementationOwner(irDeclaration: IrDeclaration) = kotlinTypeMapper.mapImplementationOwner(irDeclaration.descriptor) + fun mapImplementationOwner(irDeclaration: IrDeclaration): Type = + kotlinTypeMapper.mapImplementationOwner(irDeclaration.descriptor) - fun mapReturnType(irReturnTarget: IrReturnTarget) = kotlinTypeMapper.mapReturnType(irReturnTarget.descriptor) + fun mapReturnType(irReturnTarget: IrReturnTarget): Type = + kotlinTypeMapper.mapReturnType(irReturnTarget.descriptor) - fun mapSignatureSkipGeneric(f: IrFunction, kind: OwnerKind = OwnerKind.IMPLEMENTATION) = + fun mapSignatureSkipGeneric(f: IrFunction, kind: OwnerKind = OwnerKind.IMPLEMENTATION): JvmMethodSignature = kotlinTypeMapper.mapSignatureSkipGeneric(f.descriptor, kind) - fun mapSignatureWithGeneric(f: IrFunction, kind: OwnerKind) = kotlinTypeMapper.mapSignatureWithGeneric(f.descriptor, kind) + fun mapSignatureWithGeneric(f: IrFunction, kind: OwnerKind): JvmMethodGenericSignature = + kotlinTypeMapper.mapSignatureWithGeneric(f.descriptor, kind) fun mapToCallableMethod(f: IrFunction, superCall: Boolean, kind: OwnerKind? = null, resolvedCall: ResolvedCall<*>? = null) = kotlinTypeMapper.mapToCallableMethod(f.descriptor, superCall, kind, resolvedCall) @@ -47,13 +72,188 @@ class IrTypeMapper(private val context: JvmBackendContext) { fun writeFormalTypeParameters(irParameters: List, sw: JvmSignatureWriter) = kotlinTypeMapper.writeFormalTypeParameters(irParameters.map { it.descriptor }, sw) - fun boxType(irType: IrType) = + fun boxType(irType: IrType): Type = AsmUtil.boxType(mapType(irType), irType.toKotlinType(), kotlinTypeMapper) fun mapType( type: IrType, mode: TypeMappingMode = TypeMappingMode.DEFAULT, sw: JvmSignatureWriter? = null - ): Type = - kotlinTypeMapper.mapType(type.toKotlinType(), sw, mode) + ): Type { + if (type !is IrSimpleType) { + val kotlinType = type.originalKotlinType + error("Unexpected type: $type (original Kotlin type=$kotlinType of ${kotlinType?.let { it::class }})") + } + + // TODO: rewrite this part to produce the correct Type without the fake descriptor + if (type.toKotlinType().isSuspendFunctionType) { + return kotlinTypeMapper.mapType( + transformSuspendFunctionToRuntimeFunctionType(type.toKotlinType(), isReleaseCoroutines = true), sw, mode + ) + } + + with(typeSystem) { + mapBuiltInType(type, AsmTypeFactory, mode) + }?.let { builtInType -> + return boxTypeIfNeeded(builtInType, mode.needPrimitiveBoxing).also { asmType -> + sw?.writeGenericType(type, asmType, mode) + } + } + + val classifier = type.classifierOrNull?.owner + + when { + type.isArray() || type.isNullableArray() -> { + val typeArgument = type.arguments.single() + val (variance, memberType) = when (typeArgument) { + is IrTypeProjection -> Pair(typeArgument.variance, typeArgument.type) + is IrStarProjection -> Pair(Variance.OUT_VARIANCE, context.irBuiltIns.anyNType) + else -> error("Unsupported type argument: $typeArgument") + } + + val arrayElementType: Type + sw?.writeArrayType() + if (variance == Variance.IN_VARIANCE) { + arrayElementType = AsmTypes.OBJECT_TYPE + sw?.writeClass(arrayElementType) + } else { + arrayElementType = mapType(memberType, mode.toGenericArgumentMode(variance), sw) + } + sw?.writeArrayEnd() + + return AsmUtil.getArrayType(arrayElementType) + } + + classifier is IrClass -> { + if (classifier.isInline && !mode.needInlineClassWrapping) { + val expandedType = typeSystem.computeExpandedTypeForInlineClass(type) as IrType? + if (expandedType != null) { + return mapType(expandedType, mode.wrapInlineClassesMode(), sw) + } + } + + val asmType = + if (mode.isForAnnotationParameter && type.isKClass()) AsmTypes.JAVA_CLASS_TYPE + else Type.getObjectType(classInternalName(classifier)) + + sw?.writeGenericType(type, asmType, mode) + + return asmType + } + + classifier is IrTypeParameter -> { + return mapType(classifier.representativeUpperBound, mode, null).also { asmType -> + sw?.writeTypeVariable(classifier.name, asmType) + } + } + + else -> throw UnsupportedOperationException("Unknown type $type") + } + } + + private fun computeInternalName(klass: IrClass): String { + val className = SpecialNames.safeIdentifier(klass.name).identifier + return when (val parent = klass.parent) { + is IrPackageFragment -> { + val fqName = parent.fqName + val prefix = if (fqName.isRoot) "" else fqName.asString().replace('.', '/') + "/" + prefix + className + } + is IrClass -> { + computeInternalName(parent) + "$" + className + } + else -> error( + "Local class should have its name computed in InventNamesForLocalClasses: ${klass.fqNameWhenAvailable}\n" + + "Ensure that any lowering that transforms elements with local class info (classes, function references, " + + "IrTypeOperatorCall for SAM conversions) invokes `copyAttributes` on the transformed element." + ) + } + } + + // Copied from KotlinTypeMapper.writeGenericType. + private fun JvmSignatureWriter.writeGenericType(type: IrSimpleType, asmType: Type, mode: TypeMappingMode) { + if (skipGenericSignature() || hasNothingInNonContravariantPosition(type) || type.arguments.isEmpty()) { + writeAsmType(asmType) + return + } + + val possiblyInnerType = type.buildPossiblyInnerType() ?: error("possiblyInnerType with arguments should not be null") + + val innerTypesAsList = possiblyInnerType.segments() + + val indexOfParameterizedType = innerTypesAsList.indexOfFirst { innerPart -> innerPart.arguments.isNotEmpty() } + if (indexOfParameterizedType < 0 || innerTypesAsList.size == 1) { + writeClassBegin(asmType) + writeGenericArguments(this, possiblyInnerType, mode) + } else { + val outerType = innerTypesAsList[indexOfParameterizedType] + + writeOuterClassBegin(asmType, mapType(outerType.classifier.defaultType).internalName) + writeGenericArguments(this, outerType, mode) + + writeInnerParts( + innerTypesAsList, + this, + mode, + indexOfParameterizedType + 1 + ) // inner parts separated by `.` + } + + writeClassEnd() + } + + private fun hasNothingInNonContravariantPosition(irType: IrType): Boolean = with(KotlinTypeMapper) { + typeSystem.hasNothingInNonContravariantPosition(irType) + } + + private fun writeInnerParts( + innerTypesAsList: List, + sw: JvmSignatureWriter, + mode: TypeMappingMode, + index: Int + ) { + for (innerPart in innerTypesAsList.subList(index, innerTypesAsList.size)) { + sw.writeInnerClass(getJvmShortName(innerPart.classifier)) + writeGenericArguments(sw, innerPart, mode) + } + } + + // Copied from KotlinTypeMapper.writeGenericArguments. + private fun writeGenericArguments( + sw: JvmSignatureWriter, + type: PossiblyInnerIrType, + mode: TypeMappingMode + ) { + val classifier = type.classifier + val parameters = classifier.typeParameters.map(IrTypeParameter::symbol) + val arguments = type.arguments + + // TODO: get rid of descriptor here + val classDescriptor = classifier.descriptor + if (classDescriptor is FunctionClassDescriptor) { + if (classDescriptor.hasBigArity || + classDescriptor.functionKind == FunctionClassDescriptor.Kind.KFunction || + classDescriptor.functionKind == FunctionClassDescriptor.Kind.KSuspendFunction + ) { + writeGenericArguments(sw, listOf(arguments.last()), listOf(parameters.last()), mode) + return + } + } + + writeGenericArguments(sw, arguments, parameters, mode) + } + + private fun writeGenericArguments( + sw: JvmSignatureWriter, + arguments: List, + parameters: List, + mode: TypeMappingMode + ) = with(KotlinTypeMapper) { + typeSystem.writeGenericArguments(sw, arguments, parameters, mode) { type, sw, mode -> + mapType(type as IrType, mode, sw) + } + } + + private fun boxTypeIfNeeded(possiblyPrimitiveType: Type, needBoxedType: Boolean): Type = + if (needBoxedType) AsmUtil.boxType(possiblyPrimitiveType) else possiblyPrimitiveType } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapping.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapping.kt index 4c2d7e4a79e..46196fab764 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapping.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapping.kt @@ -5,14 +5,20 @@ package org.jetbrains.kotlin.backend.jvm.codegen +import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrField -import org.jetbrains.kotlin.ir.declarations.IrValueParameter -import org.jetbrains.kotlin.ir.declarations.IrVariable +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.IrTypeArgument +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.isLocalClass +import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.load.kotlin.TypeMappingMode +import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.org.objectweb.asm.Type fun IrTypeMapper.mapType(irVariable: IrVariable): Type = @@ -35,3 +41,47 @@ fun IrTypeMapper.mapTypeAsDeclaration(irType: IrType): Type = fun IrTypeMapper.mapTypeParameter(irType: IrType, sw: JvmSignatureWriter): Type = mapType(irType, TypeMappingMode.GENERIC_ARGUMENT, sw) + +internal fun getJvmShortName(klass: IrClass): String = + klass.fqNameWhenAvailable?.toUnsafe()?.let { JavaToKotlinClassMap.mapKotlinToJava(it)?.shortClassName?.asString() } + ?: SpecialNames.safeIdentifier(klass.name).identifier + +internal class PossiblyInnerIrType( + val classifier: IrClass, + val arguments: List, + private val outerType: PossiblyInnerIrType? +) { + fun segments(): List = outerType?.segments().orEmpty() + this +} + +internal fun IrSimpleType.buildPossiblyInnerType(): PossiblyInnerIrType? = + buildPossiblyInnerType(classOrNull?.owner, 0) + +private fun IrSimpleType.buildPossiblyInnerType(classifier: IrClass?, index: Int): PossiblyInnerIrType? { + if (classifier == null) return null + + val toIndex = classifier.typeParameters.size + index + if (!classifier.isInner) { + assert(toIndex == arguments.size || classifier.isLocalClass()) { + "${arguments.size - toIndex} trailing arguments were found in $this type" + } + + return PossiblyInnerIrType(classifier, arguments.subList(index, arguments.size), null) + } + + val argumentsSubList = arguments.subList(index, toIndex) + return PossiblyInnerIrType( + classifier, argumentsSubList, + buildPossiblyInnerType(classifier.parentAsClass, toIndex) + ) +} + +internal val IrTypeParameter.representativeUpperBound: IrType + get() { + assert(superTypes.isNotEmpty()) { "Upper bounds should not be empty: $this" } + + return superTypes.firstOrNull { + val irClass = it.classOrNull?.owner ?: return@firstOrNull false + irClass.kind != ClassKind.INTERFACE && irClass.kind != ClassKind.ANNOTATION_CLASS + } ?: superTypes.first() + } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/UnsafeCoerce.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/UnsafeCoerce.kt index 1fd57c71e73..356cfc1c22e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/UnsafeCoerce.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/UnsafeCoerce.kt @@ -5,7 +5,10 @@ package org.jetbrains.kotlin.backend.jvm.intrinsics -import org.jetbrains.kotlin.backend.jvm.codegen.* +import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo +import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen +import org.jetbrains.kotlin.backend.jvm.codegen.PromisedValue +import org.jetbrains.kotlin.backend.jvm.codegen.coerce import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression /** @@ -19,10 +22,14 @@ object UnsafeCoerce : IntrinsicMethod() { override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? { val from = expression.getTypeArgument(0)!! val to = expression.getTypeArgument(1)!! - require(with(codegen) { typeMapper.mapType(from) == typeMapper.mapType(to) }) + val fromType = codegen.typeMapper.mapType(from) + val toType = codegen.typeMapper.mapType(to) + require(fromType == toType) { + "Inline class types should have the same representation: $fromType != $toType" + } val arg = expression.getValueArgument(0)!! val result = arg.accept(codegen, data) - return object : PromisedValue(codegen, codegen.typeMapper.mapType(to), to) { + return object : PromisedValue(codegen, toType, to) { override fun materialize() = result.coerce(from).materialize() } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargInvokeLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargInvokeLowering.kt index efd8e65175a..26291e5fc10 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargInvokeLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargInvokeLowering.kt @@ -84,8 +84,8 @@ private class FunctionNVarargInvokeLowering(var context: JvmBackendContext) : Cl symbol = IrValueParameterSymbolImpl(varargParameterDescriptor), name = Name.identifier("args"), index = 0, - type = context.irBuiltIns.arrayClass.typeWith(), - varargElementType = context.irBuiltIns.anyClass.typeWith(), + type = context.irBuiltIns.arrayClass.typeWith(context.irBuiltIns.anyNType), + varargElementType = context.irBuiltIns.anyNType, isCrossinline = false, isNoinline = false ).apply { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/IrClassifierEqualityChecker.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/IrClassifierEqualityChecker.kt index 3b81bf9b900..b326e676c05 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/IrClassifierEqualityChecker.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/IrClassifierEqualityChecker.kt @@ -7,8 +7,11 @@ package org.jetbrains.kotlin.ir.symbols import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptor -import org.jetbrains.kotlin.descriptors.Visibilities -import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName +import org.jetbrains.kotlin.ir.declarations.IrPackageFragment +import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner +import org.jetbrains.kotlin.ir.util.isLocalClass import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe @@ -31,7 +34,7 @@ object FqNameEqualityChecker : IrClassifierEqualityChecker { override fun getHashCode(symbol: IrClassifierSymbol): Int { if (symbol.isBound) { val owner = symbol.owner - if (owner is IrClass && !isLocalClass(owner)) { + if (owner is IrClass && !owner.isLocalClass()) { return owner.fqName.hashCode() } return owner.hashCode() @@ -54,20 +57,9 @@ object FqNameEqualityChecker : IrClassifierEqualityChecker { return parentFqName?.child(name) } - private fun isLocalClass(declaration: IrClass): Boolean { - var current: IrDeclarationParent? = declaration - while (current != null && current !is IrPackageFragment) { - if (current is IrDeclarationWithVisibility && current.visibility == Visibilities.LOCAL) - return true - current = (current as? IrDeclaration)?.parent - } - - return false - } - private fun checkViaDeclarations(c1: IrSymbolOwner, c2: IrSymbolOwner): Boolean { if (c1 is IrClass && c2 is IrClass) { - if (isLocalClass(c1) || isLocalClass(c2)) + if (c1.isLocalClass() || c2.isLocalClass()) return c1 === c2 // Local declarations should be identical return c1.fqName == c2.fqName diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt index 92a529f46e0..8608936f2dc 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt @@ -6,22 +6,30 @@ package org.jetbrains.kotlin.ir.types import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.PrimitiveType +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns +import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.symbols.FqNameEqualityChecker import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.impl.* +import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.FqNameUnsafe +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.checker.convertVariance import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.ir.types.isPrimitiveType as irTypePredicates_isPrimitiveType -interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesContext { +interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesContext, TypeSystemCommonBackendContext { val irBuiltIns: IrBuiltIns @@ -247,6 +255,67 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon override fun createErrorTypeWithCustomConstructor(debugName: String, constructor: TypeConstructorMarker): KotlinTypeMarker = TODO("IrTypeSystemContext doesn't support constraint system resolution") + + override fun TypeConstructorMarker.isFinalClassOrEnumEntryOrAnnotationClassConstructor(): Boolean { + val symbol = this as IrClassifierSymbol + return symbol is IrClassSymbol && symbol.owner.let { + it.modality == Modality.FINAL && !it.isEnumClass + } + } + + override fun KotlinTypeMarker.hasAnnotation(fqName: FqName): Boolean = + // TODO: don't fall back to KotlinType to check annotations. Currently testIdentityEquals fails on JVM without it + (this as IrAnnotationContainer).hasAnnotation(fqName) || + (this as IrType).toKotlinType().annotations.hasAnnotation(fqName) + + override fun KotlinTypeMarker.getAnnotationFirstArgumentValue(fqName: FqName): Any? = + (this as? IrType)?.annotations?.firstOrNull { annotation -> + annotation.symbol.owner.parentAsClass.descriptor.fqNameSafe == fqName + }?.run { + if (valueArgumentsCount > 0) (getValueArgument(0) as? IrConst<*>)?.value else null + } + + override fun TypeConstructorMarker.getTypeParameterClassifier(): TypeParameterMarker? = + this as? IrTypeParameterSymbol + + override fun TypeConstructorMarker.isInlineClass(): Boolean = + (this as? IrClassSymbol)?.owner?.isInline == true + + override fun TypeParameterMarker.getRepresentativeUpperBound(): KotlinTypeMarker = + (this as IrTypeParameterSymbol).owner.superTypes.firstOrNull { + val irClass = it.classOrNull?.owner ?: return@firstOrNull false + irClass.kind != ClassKind.INTERFACE && irClass.kind != ClassKind.ANNOTATION_CLASS + } ?: owner.superTypes.first() + + override fun KotlinTypeMarker.getSubstitutedUnderlyingType(): KotlinTypeMarker? { + // Code in inlineClassesUtils.kt loads the property with the same name and takes its type. This should have the same effect. + val irClass = (this as? IrType)?.classOrNull?.owner ?: return null + return irClass.primaryConstructor?.valueParameters?.singleOrNull()?.type + } + + override fun TypeConstructorMarker.getPrimitiveType(): PrimitiveType? { + // TODO: get rid of descriptor + return KotlinBuiltIns.getPrimitiveType((this as IrClassifierSymbol).descriptor as ClassDescriptor) + } + + override fun TypeConstructorMarker.getPrimitiveArrayType(): PrimitiveType? { + // TODO: get rid of descriptor + return KotlinBuiltIns.getPrimitiveArrayType((this as IrClassifierSymbol).descriptor as ClassDescriptor) + } + + override fun TypeConstructorMarker.isUnderKotlinPackage(): Boolean { + var declaration: IrDeclaration = (this as? IrClassifierSymbol)?.owner as? IrClass ?: return false + while (true) { + val parent = declaration.parent + if (parent is IrPackageFragment) { + return parent.fqName.startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME) + } + declaration = parent as? IrDeclaration ?: return false + } + } + + override fun TypeConstructorMarker.getClassFqNameUnsafe(): FqNameUnsafe? = + (this as IrClassSymbol).owner.fqNameWhenAvailable?.toUnsafe() } fun extractTypeParameters(klass: IrDeclarationParent): List { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index c26040b02ed..3f471ae65c8 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -304,6 +304,17 @@ val IrDeclarationWithName.fqNameWhenAvailable: FqName? val IrDeclaration.parentAsClass get() = parent as IrClass +fun IrClass.isLocalClass(): Boolean { + var current: IrDeclarationParent? = this + while (current != null && current !is IrPackageFragment) { + if (current is IrDeclarationWithVisibility && current.visibility == Visibilities.LOCAL) + return true + current = (current as? IrDeclaration)?.parent + } + + return false +} + tailrec fun IrElement.getPackageFragment(): IrPackageFragment? { if (this is IrPackageFragment) return this val vParent = (this as? IrDeclaration)?.parent