JVM IR: do not use KotlinTypeMapper in IrTypeMapper.mapType

This commit is contained in:
Alexander Udalov
2019-05-14 18:36:15 +02:00
parent 1e16c0a447
commit a15575d546
8 changed files with 368 additions and 39 deletions
@@ -1433,7 +1433,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
private fun hasNothingInNonContravariantPosition(kotlinType: KotlinType): Boolean = private fun hasNothingInNonContravariantPosition(kotlinType: KotlinType): Boolean =
SimpleClassicTypeSystemContext.hasNothingInNonContravariantPosition(kotlinType) SimpleClassicTypeSystemContext.hasNothingInNonContravariantPosition(kotlinType)
private fun TypeSystemContext.hasNothingInNonContravariantPosition(type: KotlinTypeMarker): Boolean { fun TypeSystemContext.hasNothingInNonContravariantPosition(type: KotlinTypeMarker): Boolean {
val typeConstructor = type.typeConstructor() val typeConstructor = type.typeConstructor()
for (i in 0 until type.argumentsCount()) { for (i in 0 until type.argumentsCount()) {
@@ -6,40 +6,65 @@
package org.jetbrains.kotlin.backend.jvm.codegen package org.jetbrains.kotlin.backend.jvm.codegen
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext 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.AsmUtil
import org.jetbrains.kotlin.codegen.ClassBuilderMode
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
import org.jetbrains.kotlin.codegen.OwnerKind 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.signature.JvmSignatureWriter
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.toKotlinType 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.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.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.Type
import org.jetbrains.org.objectweb.asm.commons.Method
class IrTypeMapper(private val context: JvmBackendContext) { class IrTypeMapper(private val context: JvmBackendContext) {
val kotlinTypeMapper: KotlinTypeMapper = context.state.typeMapper 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) = fun mapFieldSignature(irField: IrField) =
kotlinTypeMapper.mapFieldSignature(irField.type.toKotlinType(), irField.descriptor) 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) 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) 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) = fun mapToCallableMethod(f: IrFunction, superCall: Boolean, kind: OwnerKind? = null, resolvedCall: ResolvedCall<*>? = null) =
kotlinTypeMapper.mapToCallableMethod(f.descriptor, superCall, kind, resolvedCall) kotlinTypeMapper.mapToCallableMethod(f.descriptor, superCall, kind, resolvedCall)
@@ -47,13 +72,188 @@ class IrTypeMapper(private val context: JvmBackendContext) {
fun writeFormalTypeParameters(irParameters: List<IrTypeParameter>, sw: JvmSignatureWriter) = fun writeFormalTypeParameters(irParameters: List<IrTypeParameter>, sw: JvmSignatureWriter) =
kotlinTypeMapper.writeFormalTypeParameters(irParameters.map { it.descriptor }, sw) kotlinTypeMapper.writeFormalTypeParameters(irParameters.map { it.descriptor }, sw)
fun boxType(irType: IrType) = fun boxType(irType: IrType): Type =
AsmUtil.boxType(mapType(irType), irType.toKotlinType(), kotlinTypeMapper) AsmUtil.boxType(mapType(irType), irType.toKotlinType(), kotlinTypeMapper)
fun mapType( fun mapType(
type: IrType, type: IrType,
mode: TypeMappingMode = TypeMappingMode.DEFAULT, mode: TypeMappingMode = TypeMappingMode.DEFAULT,
sw: JvmSignatureWriter? = null sw: JvmSignatureWriter? = null
): Type = ): Type {
kotlinTypeMapper.mapType(type.toKotlinType(), sw, mode) 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<PossiblyInnerIrType>,
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<IrTypeArgument>,
parameters: List<IrTypeParameterSymbol>,
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
} }
@@ -5,14 +5,20 @@
package org.jetbrains.kotlin.backend.jvm.codegen 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.codegen.signature.JvmSignatureWriter
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.types.IrType 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.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.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
fun IrTypeMapper.mapType(irVariable: IrVariable): 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 = fun IrTypeMapper.mapTypeParameter(irType: IrType, sw: JvmSignatureWriter): Type =
mapType(irType, TypeMappingMode.GENERIC_ARGUMENT, sw) 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<IrTypeArgument>,
private val outerType: PossiblyInnerIrType?
) {
fun segments(): List<PossiblyInnerIrType> = 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()
}
@@ -5,7 +5,10 @@
package org.jetbrains.kotlin.backend.jvm.intrinsics 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 import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
/** /**
@@ -19,10 +22,14 @@ object UnsafeCoerce : IntrinsicMethod() {
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? { override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? {
val from = expression.getTypeArgument(0)!! val from = expression.getTypeArgument(0)!!
val to = expression.getTypeArgument(1)!! 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 arg = expression.getValueArgument(0)!!
val result = arg.accept(codegen, data) 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() override fun materialize() = result.coerce(from).materialize()
} }
} }
@@ -84,8 +84,8 @@ private class FunctionNVarargInvokeLowering(var context: JvmBackendContext) : Cl
symbol = IrValueParameterSymbolImpl(varargParameterDescriptor), symbol = IrValueParameterSymbolImpl(varargParameterDescriptor),
name = Name.identifier("args"), name = Name.identifier("args"),
index = 0, index = 0,
type = context.irBuiltIns.arrayClass.typeWith(), type = context.irBuiltIns.arrayClass.typeWith(context.irBuiltIns.anyNType),
varargElementType = context.irBuiltIns.anyClass.typeWith(), varargElementType = context.irBuiltIns.anyNType,
isCrossinline = false, isCrossinline = false,
isNoinline = false isNoinline = false
).apply { ).apply {
@@ -7,8 +7,11 @@ package org.jetbrains.kotlin.ir.symbols
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.* 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.name.FqName
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
@@ -31,7 +34,7 @@ object FqNameEqualityChecker : IrClassifierEqualityChecker {
override fun getHashCode(symbol: IrClassifierSymbol): Int { override fun getHashCode(symbol: IrClassifierSymbol): Int {
if (symbol.isBound) { if (symbol.isBound) {
val owner = symbol.owner val owner = symbol.owner
if (owner is IrClass && !isLocalClass(owner)) { if (owner is IrClass && !owner.isLocalClass()) {
return owner.fqName.hashCode() return owner.fqName.hashCode()
} }
return owner.hashCode() return owner.hashCode()
@@ -54,20 +57,9 @@ object FqNameEqualityChecker : IrClassifierEqualityChecker {
return parentFqName?.child(name) 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 { private fun checkViaDeclarations(c1: IrSymbolOwner, c2: IrSymbolOwner): Boolean {
if (c1 is IrClass && c2 is IrClass) { 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 === c2 // Local declarations should be identical
return c1.fqName == c2.fqName return c1.fqName == c2.fqName
@@ -6,22 +6,30 @@
package org.jetbrains.kotlin.ir.types package org.jetbrains.kotlin.ir.types
import org.jetbrains.kotlin.builtins.KotlinBuiltIns 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.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns 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.FqNameEqualityChecker
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.impl.* 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.Variance
import org.jetbrains.kotlin.types.checker.convertVariance import org.jetbrains.kotlin.types.checker.convertVariance
import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.ir.types.isPrimitiveType as irTypePredicates_isPrimitiveType import org.jetbrains.kotlin.ir.types.isPrimitiveType as irTypePredicates_isPrimitiveType
interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesContext { interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesContext, TypeSystemCommonBackendContext {
val irBuiltIns: IrBuiltIns val irBuiltIns: IrBuiltIns
@@ -247,6 +255,67 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
override fun createErrorTypeWithCustomConstructor(debugName: String, constructor: TypeConstructorMarker): KotlinTypeMarker = override fun createErrorTypeWithCustomConstructor(debugName: String, constructor: TypeConstructorMarker): KotlinTypeMarker =
TODO("IrTypeSystemContext doesn't support constraint system resolution") 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<IrTypeParameter> { fun extractTypeParameters(klass: IrDeclarationParent): List<IrTypeParameter> {
@@ -304,6 +304,17 @@ val IrDeclarationWithName.fqNameWhenAvailable: FqName?
val IrDeclaration.parentAsClass get() = parent as IrClass 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? { tailrec fun IrElement.getPackageFragment(): IrPackageFragment? {
if (this is IrPackageFragment) return this if (this is IrPackageFragment) return this
val vParent = (this as? IrDeclaration)?.parent val vParent = (this as? IrDeclaration)?.parent