[Commonizer] Build CIR tree directly from metadata

This commit is contained in:
Dmitriy Dolovov
2021-02-10 12:27:43 +03:00
parent 3d6893e518
commit eddeef1d51
31 changed files with 1671 additions and 95 deletions
@@ -6,12 +6,14 @@
package org.jetbrains.kotlin.descriptors.commonizer.cir.factory
import gnu.trove.THashMap
import kotlinx.metadata.Flag
import kotlinx.metadata.Flags
import kotlinx.metadata.KmAnnotation
import kotlinx.metadata.KmAnnotationArgument
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirAnnotation
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirClassType
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirConstantValue
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirName
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
import org.jetbrains.kotlin.descriptors.commonizer.cir.impl.CirAnnotationImpl
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirProvided
import org.jetbrains.kotlin.descriptors.commonizer.utils.*
import org.jetbrains.kotlin.descriptors.commonizer.utils.compact
import org.jetbrains.kotlin.name.Name
@@ -50,6 +52,59 @@ object CirAnnotationFactory {
)
}
fun createAnnotations(flags: Flags, typeResolver: CirTypeResolver, annotations: () -> List<KmAnnotation>): List<CirAnnotation> {
return if (!Flag.Common.HAS_ANNOTATIONS(flags))
emptyList()
else
annotations().compactMap { create(it, typeResolver) }
}
fun create(source: KmAnnotation, typeResolver: CirTypeResolver): CirAnnotation {
val classId = CirEntityId.create(source.className)
val clazz: CirProvided.Class = typeResolver.resolveClassifier(classId)
val type = CirTypeFactory.createClassType(
classId = classId,
outerType = null, // annotation class can't be inner class
visibility = clazz.visibility,
arguments = clazz.typeParameters.compactMap { typeParameter ->
CirTypeProjectionImpl(
projectionKind = typeParameter.variance,
type = CirTypeFactory.createTypeParameterType(
index = typeParameter.index,
isMarkedNullable = false
)
)
},
isMarkedNullable = false
)
val allValueArguments: Map<String, KmAnnotationArgument<*>> = source.arguments
if (allValueArguments.isEmpty())
return create(type = type, constantValueArguments = emptyMap(), annotationValueArguments = emptyMap())
val constantValueArguments: MutableMap<CirName, CirConstantValue<*>> = THashMap(allValueArguments.size)
val annotationValueArguments: MutableMap<CirName, CirAnnotation> = THashMap(allValueArguments.size)
allValueArguments.forEach { (name, constantValue) ->
val cirName = CirName.create(name)
if (constantValue is KmAnnotationArgument.AnnotationValue)
annotationValueArguments[cirName] = create(source = constantValue.value, typeResolver)
else
constantValueArguments[cirName] = CirConstantValueFactory.createSafely(
constantValue = constantValue,
constantName = cirName,
owner = source,
)
}
return create(
type = type,
constantValueArguments = constantValueArguments.compact(),
annotationValueArguments = annotationValueArguments.compact()
)
}
fun create(
type: CirClassType,
constantValueArguments: Map<CirName, CirConstantValue<*>>,
@@ -5,11 +5,15 @@
package org.jetbrains.kotlin.descriptors.commonizer.cir.factory
import kotlinx.metadata.Flag
import kotlinx.metadata.KmConstructor
import kotlinx.metadata.klib.annotations
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
import org.jetbrains.kotlin.descriptors.commonizer.cir.impl.CirClassConstructorImpl
import org.jetbrains.kotlin.descriptors.commonizer.metadata.decodeVisibility
import org.jetbrains.kotlin.descriptors.commonizer.utils.compactMap
import org.jetbrains.kotlin.descriptors.commonizer.utils.compactMapNotNull
@@ -33,6 +37,18 @@ object CirClassConstructorFactory {
)
}
fun create(source: KmConstructor, containingClass: CirContainingClass, typeResolver: CirTypeResolver): CirClassConstructor {
return create(
annotations = CirAnnotationFactory.createAnnotations(source.flags, typeResolver, source::annotations),
typeParameters = emptyList(), // TODO: nowhere to read constructor type parameters from
visibility = decodeVisibility(source.flags),
containingClass = containingClass,
valueParameters = source.valueParameters.compactMap { CirValueParameterFactory.create(it, typeResolver) },
hasStableParameterNames = !Flag.Constructor.HAS_NON_STABLE_PARAMETER_NAMES(source.flags),
isPrimary = !Flag.Constructor.IS_SECONDARY(source.flags)
)
}
@Suppress("NOTHING_TO_INLINE")
inline fun create(
annotations: List<CirAnnotation>,
@@ -5,15 +5,16 @@
package org.jetbrains.kotlin.descriptors.commonizer.cir.factory
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirAnnotation
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirClass
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirName
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirTypeParameter
import kotlinx.metadata.Flag
import kotlinx.metadata.KmAnnotation
import kotlinx.metadata.KmClass
import kotlinx.metadata.klib.annotations
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
import org.jetbrains.kotlin.descriptors.commonizer.cir.impl.CirClassImpl
import org.jetbrains.kotlin.descriptors.commonizer.metadata.decodeClassKind
import org.jetbrains.kotlin.descriptors.commonizer.metadata.decodeModality
import org.jetbrains.kotlin.descriptors.commonizer.metadata.decodeVisibility
import org.jetbrains.kotlin.descriptors.commonizer.utils.compactMap
import org.jetbrains.kotlin.descriptors.commonizer.utils.filteredSupertypes
import org.jetbrains.kotlin.resolve.isInlineClass
@@ -36,6 +37,53 @@ object CirClassFactory {
setSupertypes(source.filteredSupertypes.compactMap { CirTypeFactory.create(it) })
}
fun create(name: CirName, source: KmClass, typeResolver: CirTypeResolver): CirClass = create(
annotations = CirAnnotationFactory.createAnnotations(source.flags, typeResolver, source::annotations),
name = name,
typeParameters = source.typeParameters.compactMap { CirTypeParameterFactory.create(it, typeResolver) },
visibility = decodeVisibility(source.flags),
modality = decodeModality(source.flags),
kind = decodeClassKind(source.flags),
companion = source.companionObject?.let(CirName::create),
isCompanion = Flag.Class.IS_COMPANION_OBJECT(source.flags),
isData = Flag.Class.IS_DATA(source.flags),
isInline = Flag.Class.IS_INLINE(source.flags),
isInner = Flag.Class.IS_INNER(source.flags),
isExternal = Flag.Class.IS_EXTERNAL(source.flags)
).apply {
setSupertypes(source.filteredSupertypes.compactMap { CirTypeFactory.create(it, typeResolver) })
}
fun createDefaultEnumEntry(
name: CirName,
annotations: List<KmAnnotation>,
enumClassId: CirEntityId,
enumClass: KmClass,
typeResolver: CirTypeResolver
): CirClass = create(
annotations = annotations.compactMap { CirAnnotationFactory.create(it, typeResolver) },
name = name,
typeParameters = emptyList(),
visibility = DescriptorVisibilities.PUBLIC,
modality = Modality.FINAL,
kind = ClassKind.ENUM_ENTRY,
companion = null,
isCompanion = false,
isData = false,
isInline = false,
isInner = false,
isExternal = false
).apply {
val enumClassType = CirTypeFactory.createClassType(
classId = enumClassId,
outerType = null,
visibility = decodeVisibility(enumClass.flags),
arguments = emptyList(),
isMarkedNullable = false
)
setSupertypes(listOf(enumClassType))
}
@Suppress("NOTHING_TO_INLINE")
inline fun create(
annotations: List<CirAnnotation>,
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.descriptors.commonizer.cir.factory
import kotlinx.metadata.KmAnnotationArgument
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirConstantValue
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirName
@@ -25,6 +26,8 @@ object CirConstantValueFactory {
constantValue: ConstantValue<*>,
location: () -> String
): CirConstantValue<*> = when (constantValue) {
is NullValue -> CirConstantValue.NullValue
is StringValue -> CirConstantValue.StringValue(constantValue.value)
is CharValue -> CirConstantValue.CharValue(constantValue.value)
@@ -46,7 +49,6 @@ object CirConstantValueFactory {
CirEntityId.create(constantValue.enumClassId),
CirName.create(constantValue.enumEntryName)
)
is NullValue -> CirConstantValue.NullValue
is ArrayValue -> CirConstantValue.ArrayValue(
constantValue.value.compactMapIndexed { index, innerConstantValue ->
@@ -54,8 +56,58 @@ object CirConstantValueFactory {
constantValue = innerConstantValue,
location = { "${location()}[$index]" }
)
})
}
)
else -> error("Unsupported const value type: ${constantValue::class.java}, $constantValue at ${location()}")
}
fun createSafely(
constantValue: KmAnnotationArgument<*>?,
constantName: CirName? = null,
owner: Any,
): CirConstantValue<*> = createSafely(
constantValue = constantValue,
location = { "${owner::class.java}, $owner" + constantName?.toString()?.let { "[$it]" } }
)
private fun createSafely(
constantValue: KmAnnotationArgument<*>?,
location: () -> String
): CirConstantValue<*> = when (constantValue) {
null -> CirConstantValue.NullValue
is KmAnnotationArgument.StringValue -> CirConstantValue.StringValue(constantValue.value)
is KmAnnotationArgument.CharValue -> CirConstantValue.CharValue(constantValue.value)
is KmAnnotationArgument.ByteValue -> CirConstantValue.ByteValue(constantValue.value)
is KmAnnotationArgument.ShortValue -> CirConstantValue.ShortValue(constantValue.value)
is KmAnnotationArgument.IntValue -> CirConstantValue.IntValue(constantValue.value)
is KmAnnotationArgument.LongValue -> CirConstantValue.LongValue(constantValue.value)
is KmAnnotationArgument.UByteValue -> CirConstantValue.UByteValue(constantValue.value)
is KmAnnotationArgument.UShortValue -> CirConstantValue.UShortValue(constantValue.value)
is KmAnnotationArgument.UIntValue -> CirConstantValue.UIntValue(constantValue.value)
is KmAnnotationArgument.ULongValue -> CirConstantValue.ULongValue(constantValue.value)
is KmAnnotationArgument.FloatValue -> CirConstantValue.FloatValue(constantValue.value)
is KmAnnotationArgument.DoubleValue -> CirConstantValue.DoubleValue(constantValue.value)
is KmAnnotationArgument.BooleanValue -> CirConstantValue.BooleanValue(constantValue.value)
is KmAnnotationArgument.EnumValue -> CirConstantValue.EnumValue(
CirEntityId.create(constantValue.enumClassName),
CirName.create(constantValue.enumEntryName)
)
is KmAnnotationArgument.ArrayValue -> CirConstantValue.ArrayValue(
constantValue.value.compactMapIndexed { index, innerConstantValue ->
createSafely(
constantValue = innerConstantValue,
location = { "${location()}[$index]" }
)
}
)
else -> error("Unsupported annotation argument type: ${constantValue::class.java}, $constantValue")
}
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.descriptors.commonizer.cir.factory
import kotlinx.metadata.KmType
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirAnnotation
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirExtensionReceiver
@@ -18,6 +19,11 @@ object CirExtensionReceiverFactory {
type = CirTypeFactory.create(source.type)
)
fun create(receiverParameterType: KmType, typeResolver: CirTypeResolver): CirExtensionReceiver = create(
annotations = emptyList(), // TODO nowhere to read receiver annotations from, see KT-42490
type = CirTypeFactory.create(receiverParameterType, typeResolver)
)
@Suppress("NOTHING_TO_INLINE")
inline fun create(
annotations: List<CirAnnotation>,
@@ -5,9 +5,15 @@
package org.jetbrains.kotlin.descriptors.commonizer.cir.factory
import kotlinx.metadata.Flag
import kotlinx.metadata.KmFunction
import kotlinx.metadata.klib.annotations
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
import org.jetbrains.kotlin.descriptors.commonizer.cir.impl.CirFunctionImpl
import org.jetbrains.kotlin.descriptors.commonizer.metadata.decodeCallableKind
import org.jetbrains.kotlin.descriptors.commonizer.metadata.decodeModality
import org.jetbrains.kotlin.descriptors.commonizer.metadata.decodeVisibility
import org.jetbrains.kotlin.descriptors.commonizer.utils.compactMap
object CirFunctionFactory {
@@ -26,6 +32,23 @@ object CirFunctionFactory {
modifiers = CirFunctionModifiersFactory.create(source),
)
fun create(name: CirName, source: KmFunction, containingClass: CirContainingClass?, typeResolver: CirTypeResolver): CirFunction {
return create(
annotations = CirAnnotationFactory.createAnnotations(source.flags, typeResolver, source::annotations),
name = name,
typeParameters = source.typeParameters.compactMap { CirTypeParameterFactory.create(it, typeResolver) },
visibility = decodeVisibility(source.flags),
modality = decodeModality(source.flags),
containingClass = containingClass,
valueParameters = source.valueParameters.compactMap { CirValueParameterFactory.create(it, typeResolver) },
hasStableParameterNames = !Flag.Function.HAS_NON_STABLE_PARAMETER_NAMES(source.flags),
extensionReceiver = source.receiverParameterType?.let { CirExtensionReceiverFactory.create(it, typeResolver) },
returnType = CirTypeFactory.create(source.returnType, typeResolver),
kind = decodeCallableKind(source.flags),
modifiers = CirFunctionModifiersFactory.create(source),
)
}
@Suppress("NOTHING_TO_INLINE")
inline fun create(
annotations: List<CirAnnotation>,
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.descriptors.commonizer.cir.factory
import kotlinx.metadata.Flag
import kotlinx.metadata.KmFunction
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirFunctionModifiers
import org.jetbrains.kotlin.descriptors.commonizer.cir.impl.CirFunctionModifiersImpl
@@ -22,6 +24,15 @@ object CirFunctionModifiersFactory {
isExternal = source.isExternal
)
fun create(source: KmFunction): CirFunctionModifiers = create(
isOperator = Flag.Function.IS_OPERATOR(source.flags),
isInfix = Flag.Function.IS_INFIX(source.flags),
isInline = Flag.Function.IS_INLINE(source.flags),
isTailrec = Flag.Function.IS_TAILREC(source.flags),
isSuspend = Flag.Function.IS_SUSPEND(source.flags),
isExternal = Flag.Function.IS_EXTERNAL(source.flags)
)
fun create(
isOperator: Boolean,
isInfix: Boolean,
@@ -5,12 +5,19 @@
package org.jetbrains.kotlin.descriptors.commonizer.cir.factory
import kotlinx.metadata.Flag
import kotlinx.metadata.KmProperty
import kotlinx.metadata.klib.annotations
import kotlinx.metadata.klib.compileTimeValue
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
import org.jetbrains.kotlin.descriptors.commonizer.cir.impl.CirPropertyImpl
import org.jetbrains.kotlin.descriptors.commonizer.metadata.decodeCallableKind
import org.jetbrains.kotlin.descriptors.commonizer.metadata.decodeModality
import org.jetbrains.kotlin.descriptors.commonizer.metadata.decodeVisibility
import org.jetbrains.kotlin.descriptors.commonizer.utils.compactMap
object CirPropertyFactory {
@@ -45,6 +52,37 @@ object CirPropertyFactory {
)
}
fun create(name: CirName, source: KmProperty, containingClass: CirContainingClass?, typeResolver: CirTypeResolver): CirProperty {
val compileTimeInitializer = if (Flag.Property.HAS_CONSTANT(source.flags)) {
CirConstantValueFactory.createSafely(
constantValue = source.compileTimeValue,
owner = source,
)
} else CirConstantValue.NullValue
return create(
annotations = CirAnnotationFactory.createAnnotations(source.flags, typeResolver, source::annotations),
name = name,
typeParameters = source.typeParameters.compactMap { CirTypeParameterFactory.create(it, typeResolver) },
visibility = decodeVisibility(source.flags),
modality = decodeModality(source.flags),
containingClass = containingClass,
isExternal = Flag.Property.IS_EXTERNAL(source.flags),
extensionReceiver = source.receiverParameterType?.let { CirExtensionReceiverFactory.create(it, typeResolver) },
returnType = CirTypeFactory.create(source.returnType, typeResolver),
kind = decodeCallableKind(source.flags),
isVar = Flag.Property.IS_VAR(source.flags),
isLateInit = Flag.Property.IS_LATEINIT(source.flags),
isConst = Flag.Property.IS_CONST(source.flags),
isDelegate = Flag.Property.IS_DELEGATED(source.flags),
getter = CirPropertyGetterFactory.create(source, typeResolver),
setter = CirPropertySetterFactory.create(source, typeResolver),
backingFieldAnnotations = emptyList(), // TODO unclear where to read backing/delegate field annotations from, see KT-44625
delegateFieldAnnotations = emptyList(), // TODO unclear where to read backing/delegate field annotations from, see KT-44625
compileTimeInitializer = compileTimeInitializer
)
}
@Suppress("NOTHING_TO_INLINE")
inline fun create(
annotations: List<CirAnnotation>,
@@ -5,6 +5,9 @@
package org.jetbrains.kotlin.descriptors.commonizer.cir.factory
import kotlinx.metadata.Flag
import kotlinx.metadata.KmProperty
import kotlinx.metadata.klib.getterAnnotations
import org.jetbrains.kotlin.descriptors.PropertyGetterDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirAnnotation
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirPropertyGetter
@@ -35,6 +38,26 @@ object CirPropertyGetterFactory {
)
}
fun create(source: KmProperty, typeResolver: CirTypeResolver): CirPropertyGetter? {
if (!Flag.Property.HAS_GETTER(source.flags))
return null
val getterFlags = source.getterFlags
val isDefault = !Flag.PropertyAccessor.IS_NOT_DEFAULT(getterFlags)
val annotations = CirAnnotationFactory.createAnnotations(getterFlags, typeResolver, source::getterAnnotations)
if (isDefault && annotations.isEmpty())
return DEFAULT_NO_ANNOTATIONS
return create(
annotations = annotations,
isDefault = isDefault,
isExternal = Flag.PropertyAccessor.IS_EXTERNAL(getterFlags),
isInline = Flag.PropertyAccessor.IS_INLINE(getterFlags)
)
}
fun create(
annotations: List<CirAnnotation>,
isDefault: Boolean,
@@ -5,12 +5,17 @@
package org.jetbrains.kotlin.descriptors.commonizer.cir.factory
import kotlinx.metadata.Flag
import kotlinx.metadata.KmProperty
import kotlinx.metadata.klib.annotations
import kotlinx.metadata.klib.setterAnnotations
import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirAnnotation
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirPropertySetter
import org.jetbrains.kotlin.descriptors.commonizer.cir.impl.CirPropertySetterImpl
import org.jetbrains.kotlin.descriptors.commonizer.metadata.decodeVisibility
import org.jetbrains.kotlin.descriptors.commonizer.utils.Interner
import org.jetbrains.kotlin.descriptors.commonizer.utils.compactMap
@@ -26,6 +31,24 @@ object CirPropertySetterFactory {
isInline = source.isInline
)
fun create(source: KmProperty, typeResolver: CirTypeResolver): CirPropertySetter? {
if (!Flag.Property.HAS_SETTER(source.flags))
return null
val setterFlags = source.setterFlags
return create(
annotations = CirAnnotationFactory.createAnnotations(setterFlags, typeResolver, source::setterAnnotations),
parameterAnnotations = source.setterParameter?.let { setterParameter ->
CirAnnotationFactory.createAnnotations(setterParameter.flags, typeResolver, setterParameter::annotations)
}.orEmpty(),
visibility = decodeVisibility(setterFlags),
isDefault = !Flag.PropertyAccessor.IS_NOT_DEFAULT(setterFlags),
isExternal = Flag.PropertyAccessor.IS_EXTERNAL(setterFlags),
isInline = Flag.PropertyAccessor.IS_INLINE(setterFlags)
)
}
fun create(
annotations: List<CirAnnotation>,
parameterAnnotations: List<CirAnnotation>,
@@ -0,0 +1,181 @@
/*
* Copyright 2010-2021 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.descriptors.commonizer.cir.factory
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirProvided
import org.jetbrains.kotlin.descriptors.commonizer.utils.compactMapIndexed
import org.jetbrains.kotlin.types.Variance
class CirTypeAliasExpansion(
val typeAlias: CirProvided.TypeAlias,
val arguments: List<CirTypeProjection>,
val isMarkedNullable: Boolean,
val typeResolver: CirTypeResolver
) {
companion object {
fun create(
typeAliasId: CirEntityId,
arguments: List<CirTypeProjection>,
isMarkedNullable: Boolean,
typeResolver: CirTypeResolver
): CirTypeAliasExpansion {
val typeAlias: CirProvided.TypeAlias = typeResolver.resolveClassifier(typeAliasId)
checkArgumentsCount(typeAlias, typeAliasId, arguments)
return CirTypeAliasExpansion(
typeAlias = typeAlias,
arguments = arguments,
isMarkedNullable = isMarkedNullable,
typeResolver = typeResolver
)
}
}
}
object CirTypeAliasExpander {
fun expand(expansion: CirTypeAliasExpansion): CirClassOrTypeAliasType {
val underlyingType = expansion.typeAlias.underlyingType
val underlyingProjection = CirProvided.RegularTypeProjection(Variance.INVARIANT, underlyingType)
val expandedProjection = expandTypeProjection(expansion, underlyingProjection, Variance.INVARIANT)
check(expandedProjection is CirTypeProjectionImpl) {
"Type alias expansion: result for $underlyingType is $expandedProjection, should not be a star projection"
}
check(expandedProjection.projectionKind == Variance.INVARIANT) {
"Type alias expansion: result for $underlyingType is $expandedProjection, should be invariant"
}
val expandedType = expandedProjection.type as CirClassOrTypeAliasType
return CirTypeFactory.makeNullableIfNecessary(expandedType, expansion.isMarkedNullable)
}
private fun expandTypeProjection(
expansion: CirTypeAliasExpansion,
projection: CirProvided.TypeProjection,
typeParameterVariance: Variance
): CirTypeProjection {
val type = when (projection) {
is CirProvided.StarTypeProjection -> return CirStarTypeProjection
is CirProvided.RegularTypeProjection -> projection.type
}
val argument = when (type) {
is CirProvided.TypeParameterType -> expansion.arguments[type.index]
is CirProvided.TypeAliasType -> {
val substitutedType = expandTypeAliasType(expansion, type)
CirTypeProjectionImpl(projection.variance, substitutedType)
}
is CirProvided.ClassType -> {
val substitutedType = expandClassType(expansion, type)
CirTypeProjectionImpl(projection.variance, substitutedType)
}
}
return when (argument) {
is CirStarTypeProjection -> CirStarTypeProjection
is CirTypeProjectionImpl -> {
val argumentType = argument.type as CirSimpleType
val resultingVariance = run {
val argumentVariance = argument.projectionKind
val underlyingVariance = projection.variance
val substitutionVariance = when {
underlyingVariance == argumentVariance -> argumentVariance
underlyingVariance == Variance.INVARIANT -> argumentVariance
argumentVariance == Variance.INVARIANT -> underlyingVariance
else -> argumentVariance
}
when {
typeParameterVariance == substitutionVariance -> substitutionVariance
typeParameterVariance == Variance.INVARIANT -> substitutionVariance
substitutionVariance == Variance.INVARIANT -> Variance.INVARIANT
else -> substitutionVariance
}
}
val substitutedType = CirTypeFactory.makeNullableIfNecessary(argumentType, type.isMarkedNullable)
CirTypeProjectionImpl(resultingVariance, substitutedType)
}
}
}
private fun expandTypeAliasType(
expansion: CirTypeAliasExpansion,
type: CirProvided.TypeAliasType
): CirTypeAliasType {
val typeAlias: CirProvided.TypeAlias = expansion.typeResolver.resolveClassifier(type.typeAliasId)
checkArgumentsCount(typeAlias, type.typeAliasId, type.arguments)
val expandedArguments = type.arguments.compactMapIndexed { index, argument ->
val projection = expandTypeProjection(expansion, argument, typeAlias.typeParameters[index].variance)
makeNullableTypeIfNecessary(projection, argument)
}
val nestedExpansion = CirTypeAliasExpansion(typeAlias, expandedArguments, type.isMarkedNullable, expansion.typeResolver)
val nestedExpandedType = expand(nestedExpansion)
return CirTypeFactory.createTypeAliasType(
typeAliasId = type.typeAliasId,
underlyingType = nestedExpandedType,
arguments = expandedArguments,
isMarkedNullable = type.isMarkedNullable
)
}
private fun expandClassType(
expansion: CirTypeAliasExpansion,
type: CirProvided.ClassType
): CirClassType {
val clazz: CirProvided.Class = expansion.typeResolver.resolveClassifier(type.classId)
checkArgumentsCount(clazz, type.classId, type.arguments)
val expandedArguments = type.arguments.compactMapIndexed { index, argument ->
val projection = expandTypeProjection(expansion, argument, clazz.typeParameters[index].variance)
makeNullableTypeIfNecessary(projection, argument)
}
return CirTypeFactory.createClassType(
classId = type.classId,
outerType = type.outerType?.let { expandClassType(expansion, it) },
visibility = clazz.visibility,
arguments = expandedArguments,
isMarkedNullable = type.isMarkedNullable
)
}
@Suppress("NOTHING_TO_INLINE")
private inline fun makeNullableTypeIfNecessary(
projection: CirTypeProjection,
originalArgument: CirProvided.TypeProjection
): CirTypeProjection {
return when (projection) {
is CirStarTypeProjection -> CirStarTypeProjection
is CirTypeProjectionImpl -> {
val originalTypeIsNullable = (originalArgument as? CirProvided.RegularTypeProjection)?.type?.isMarkedNullable == true
if (!originalTypeIsNullable)
return projection
val projectionType = projection.type as CirSimpleType
if (projectionType.isMarkedNullable)
return projection
CirTypeProjectionImpl(
projectionKind = projection.projectionKind,
type = CirTypeFactory.makeNullable(projectionType)
)
}
}
}
}
private fun checkArgumentsCount(classifier: CirProvided.Classifier, classifierId: CirEntityId, arguments: List<*>) =
check(classifier.typeParameters.size == arguments.size) {
"${classifier::class.java.simpleName} $classifierId has different number of type parameters than the number of supplied arguments: ${classifier.typeParameters.size} != ${arguments.size}"
}
@@ -5,10 +5,12 @@
package org.jetbrains.kotlin.descriptors.commonizer.cir.factory
import kotlinx.metadata.KmTypeAlias
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
import org.jetbrains.kotlin.descriptors.commonizer.cir.impl.CirTypeAliasImpl
import org.jetbrains.kotlin.descriptors.commonizer.metadata.decodeVisibility
import org.jetbrains.kotlin.descriptors.commonizer.utils.compactMap
object CirTypeAliasFactory {
@@ -26,6 +28,20 @@ object CirTypeAliasFactory {
)
}
fun create(name: CirName, source: KmTypeAlias, typeResolver: CirTypeResolver): CirTypeAlias {
val underlyingType = CirTypeFactory.create(source.underlyingType, typeResolver) as CirClassOrTypeAliasType
val expandedType = CirTypeFactory.unabbreviate(underlyingType)
return create(
annotations = CirAnnotationFactory.createAnnotations(source.flags, typeResolver, source::annotations),
name = name,
typeParameters = source.typeParameters.compactMap { CirTypeParameterFactory.create(it, typeResolver) },
visibility = decodeVisibility(source.flags),
underlyingType = underlyingType,
expandedType = expandedType
)
}
@Suppress("NOTHING_TO_INLINE")
inline fun create(
annotations: List<CirAnnotation>,
@@ -5,11 +5,16 @@
package org.jetbrains.kotlin.descriptors.commonizer.cir.factory
import gnu.trove.TIntObjectHashMap
import kotlinx.metadata.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
import org.jetbrains.kotlin.descriptors.commonizer.cir.impl.CirClassTypeImpl
import org.jetbrains.kotlin.descriptors.commonizer.cir.impl.CirTypeAliasTypeImpl
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirProvided
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirProvidedClassifiers
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.TypeParameterResolver
import org.jetbrains.kotlin.descriptors.commonizer.core.computeExpandedType
import org.jetbrains.kotlin.descriptors.commonizer.utils.*
import org.jetbrains.kotlin.types.*
@@ -29,6 +34,56 @@ object CirTypeFactory {
private val typeAliasTypeInterner = Interner<CirTypeAliasType>()
private val typeParameterTypeInterner = Interner<CirTypeParameterType>()
fun create(source: KmType, typeResolver: CirTypeResolver): CirType {
@Suppress("NAME_SHADOWING")
val source = source.abbreviatedType ?: source
val isMarkedNullable = Flag.Type.IS_NULLABLE(source.flags)
return when (val classifier = source.classifier) {
is KmClassifier.Class -> {
val classId = CirEntityId.create(classifier.name)
val outerType = source.outerType?.let { outerType ->
val outerClassType = create(outerType, typeResolver)
check(outerClassType is CirClassType) { "Outer type of $classId is not a class: $outerClassType" }
outerClassType
}
val clazz: CirProvided.Class = typeResolver.resolveClassifier(classId)
createClassType(
classId = classId,
outerType = outerType,
visibility = clazz.visibility,
arguments = createArguments(source.arguments, typeResolver),
isMarkedNullable = isMarkedNullable
)
}
is KmClassifier.TypeAlias -> {
val typeAliasId = CirEntityId.create(classifier.name)
val arguments = createArguments(source.arguments, typeResolver)
val underlyingType = CirTypeAliasExpander.expand(
CirTypeAliasExpansion.create(typeAliasId, arguments, isMarkedNullable, typeResolver)
)
createTypeAliasType(
typeAliasId = typeAliasId,
underlyingType = underlyingType,
arguments = arguments,
isMarkedNullable = isMarkedNullable
)
}
is KmClassifier.TypeParameter -> {
createTypeParameterType(
index = typeResolver.resolveTypeParameterIndex(classifier.id),
isMarkedNullable = isMarkedNullable
)
}
}
}
fun create(source: KotlinType): CirType = source.unwrap().run {
when (this) {
is SimpleType -> create(this)
@@ -161,6 +216,13 @@ object CirTypeFactory {
inline fun <T : CirSimpleType> makeNullableIfNecessary(type: T, necessary: Boolean): T =
if (!necessary) type else makeNullable(type)
@Suppress("NOTHING_TO_INLINE")
inline fun decodeVariance(variance: KmVariance): Variance = when (variance) {
KmVariance.INVARIANT -> Variance.INVARIANT
KmVariance.IN -> Variance.IN_VARIANCE
KmVariance.OUT -> Variance.OUT_VARIANCE
}
fun unabbreviate(type: CirClassOrTypeAliasType): CirClassType = when (type) {
is CirClassType -> {
var hasAbbreviationsInArguments = false
@@ -239,6 +301,19 @@ object CirTypeFactory {
)
}
@Suppress("NOTHING_TO_INLINE")
private inline fun createArguments(arguments: List<KmTypeProjection>, typeResolver: CirTypeResolver): List<CirTypeProjection> {
return arguments.compactMap { argument ->
val variance = argument.variance ?: return@compactMap CirStarTypeProjection
val argumentType = argument.type ?: return@compactMap CirStarTypeProjection
CirTypeProjectionImpl(
projectionKind = decodeVariance(variance),
type = create(argumentType, typeResolver)
)
}
}
private inline val TypeParameterDescriptor.typeParameterIndex: Int
get() {
var index = index
@@ -257,3 +332,68 @@ object CirTypeFactory {
return index
}
}
typealias TypeParameterId = Int
typealias TypeParameterIndex = Int
abstract class CirTypeResolver : TypeParameterResolver {
abstract val providedClassifiers: CirProvidedClassifiers
protected abstract val typeParameterIndexOffset: Int
inline fun <reified T : CirProvided.Classifier> resolveClassifier(classifierId: CirEntityId): T {
val classifier = providedClassifiers.classifier(classifierId)
?: error("Unresolved classifier: $classifierId")
check(classifier is T) {
"Resolved classifier $classifierId of type ${classifier::class.java.simpleName}. Expected: ${T::class.java.simpleName}."
}
return classifier
}
abstract fun resolveTypeParameterIndex(id: TypeParameterId): TypeParameterIndex
abstract override fun resolveTypeParameter(id: TypeParameterId): KmTypeParameter
private class TopLevel(override val providedClassifiers: CirProvidedClassifiers) : CirTypeResolver() {
override val typeParameterIndexOffset get() = 0
override fun resolveTypeParameterIndex(id: TypeParameterId) = error("Unresolved type parameter: id=$id")
override fun resolveTypeParameter(id: TypeParameterId) = error("Unresolved type parameter: id=$id")
}
private class Nested(
private val parent: CirTypeResolver,
private val typeParameterMapping: TIntObjectHashMap<TypeParameterInfo>
) : CirTypeResolver() {
override val providedClassifiers get() = parent.providedClassifiers
override val typeParameterIndexOffset = typeParameterMapping.size() + parent.typeParameterIndexOffset
override fun resolveTypeParameterIndex(id: TypeParameterId) =
typeParameterMapping[id]?.index ?: parent.resolveTypeParameterIndex(id)
override fun resolveTypeParameter(id: TypeParameterId) =
typeParameterMapping[id]?.typeParameter ?: parent.resolveTypeParameter(id)
}
private class TypeParameterInfo(val index: TypeParameterIndex, val typeParameter: KmTypeParameter)
fun create(typeParameters: List<KmTypeParameter>): CirTypeResolver =
if (typeParameters.isEmpty())
this
else {
val mapping = TIntObjectHashMap<TypeParameterInfo>(typeParameters.size * 2)
typeParameters.forEachIndexed { localIndex, typeParameter ->
val typeParameterInfo = TypeParameterInfo(
index = localIndex + typeParameterIndexOffset,
typeParameter = typeParameter
)
mapping.put(typeParameter.id, typeParameterInfo)
}
Nested(this, mapping)
}
companion object {
fun create(providedClassifiers: CirProvidedClassifiers): CirTypeResolver = TopLevel(providedClassifiers)
}
}
@@ -5,12 +5,17 @@
package org.jetbrains.kotlin.descriptors.commonizer.cir.factory
import kotlinx.metadata.Flag
import kotlinx.metadata.KmTypeParameter
import kotlinx.metadata.klib.annotations
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirAnnotation
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirName
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirType
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirTypeParameter
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirTypeFactory.decodeVariance
import org.jetbrains.kotlin.descriptors.commonizer.cir.impl.CirTypeParameterImpl
import org.jetbrains.kotlin.descriptors.commonizer.metadata.ALWAYS_HAS_ANNOTATIONS
import org.jetbrains.kotlin.descriptors.commonizer.utils.compactMap
import org.jetbrains.kotlin.descriptors.commonizer.utils.filteredUpperBounds
import org.jetbrains.kotlin.types.Variance
@@ -24,6 +29,14 @@ object CirTypeParameterFactory {
upperBounds = source.filteredUpperBounds.compactMap(CirTypeFactory::create)
)
fun create(source: KmTypeParameter, typeResolver: CirTypeResolver): CirTypeParameter = create(
annotations = CirAnnotationFactory.createAnnotations(ALWAYS_HAS_ANNOTATIONS, typeResolver, source::annotations),
name = CirName.create(source.name),
isReified = Flag.TypeParameter.IS_REIFIED(source.flags),
variance = decodeVariance(source.variance),
upperBounds = source.filteredUpperBounds.compactMap { CirTypeFactory.create(it, typeResolver) }
)
@Suppress("NOTHING_TO_INLINE")
inline fun create(
annotations: List<CirAnnotation>,
@@ -5,6 +5,9 @@
package org.jetbrains.kotlin.descriptors.commonizer.cir.factory
import kotlinx.metadata.Flag
import kotlinx.metadata.KmValueParameter
import kotlinx.metadata.klib.annotations
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirAnnotation
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirName
@@ -27,6 +30,16 @@ object CirValueParameterFactory {
isNoinline = source.isNoinline
)
fun create(source: KmValueParameter, typeResolver: CirTypeResolver): CirValueParameter = create(
annotations = CirAnnotationFactory.createAnnotations(source.flags, typeResolver, source::annotations),
name = CirName.create(source.name),
returnType = CirTypeFactory.create(source.type!!, typeResolver),
varargElementType = source.varargElementType?.let { CirTypeFactory.create(it, typeResolver) },
declaresDefaultValue = Flag.ValueParameter.DECLARES_DEFAULT_VALUE(source.flags),
isCrossinline = Flag.ValueParameter.IS_CROSSINLINE(source.flags),
isNoinline = Flag.ValueParameter.IS_NOINLINE(source.flags)
)
fun create(
annotations: List<CirAnnotation>,
name: CirName,
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.descriptors.commonizer.ResultsConsumer.Status
import org.jetbrains.kotlin.descriptors.commonizer.core.CommonizationVisitor
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.*
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirNode.Companion.dimension
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirTreeMerger.CirTreeMergeResult
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirTreeMergerV2.CirTreeMergeResult
import org.jetbrains.kotlin.descriptors.commonizer.metadata.MetadataBuilder
import org.jetbrains.kotlin.library.SerializedMetadata
import org.jetbrains.kotlin.storage.LockBasedStorageManager
@@ -46,7 +46,7 @@ private fun mergeAndCommonize(storageManager: StorageManager, parameters: Common
CirProvidedClassifiers.by(parameters.dependencyModulesProvider)
)
)
val mergeResult = CirTreeMerger(storageManager, classifiers, parameters).merge()
val mergeResult = CirTreeMergerV2(storageManager, classifiers, parameters).build()
// commonize:
val mergedTree = mergeResult.root
@@ -5,10 +5,12 @@
package org.jetbrains.kotlin.descriptors.commonizer.mergedtree
import gnu.trove.THashSet
import gnu.trove.THashMap
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirName
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirPackageName
import org.jetbrains.kotlin.types.Variance
object CirFictitiousFunctionClassifiers : CirProvidedClassifiers {
private const val MIN_ARITY = 0
@@ -17,16 +19,28 @@ object CirFictitiousFunctionClassifiers : CirProvidedClassifiers {
private val FUNCTION_PREFIXES = arrayOf("Function", "SuspendFunction")
private val PACKAGE_NAME = CirPackageName.create("kotlin")
private val classifiers: Set<CirEntityId> = THashSet<CirEntityId>().apply {
private val classifiers: Map<CirEntityId, CirProvided.Class> = THashMap<CirEntityId, CirProvided.Class>().apply {
(MIN_ARITY..MAX_ARITY).forEach { arity ->
FUNCTION_PREFIXES.forEach { prefix ->
this += buildFictitiousFunctionClass(prefix, arity)
buildFictitiousFunctionClass(prefix, arity, this::set)
}
}
}
override fun hasClassifier(classifierId: CirEntityId): Boolean = classifierId in classifiers
override fun hasClassifier(classifierId: CirEntityId) = classifierId in classifiers
override fun classifier(classifierId: CirEntityId): CirProvided.Class? = classifiers[classifierId]
private fun buildFictitiousFunctionClass(prefix: String, arity: Int): CirEntityId =
CirEntityId.create(PACKAGE_NAME, CirName.create("$prefix$arity"))
private inline fun buildFictitiousFunctionClass(prefix: String, arity: Int, consumer: (CirEntityId, CirProvided.Class) -> Unit) {
val typeParameters = List(arity + 1) { index ->
CirProvided.TypeParameter(
index = index,
variance = if (index == arity) Variance.OUT_VARIANCE else Variance.IN_VARIANCE
)
}
val classId = CirEntityId.create(PACKAGE_NAME, CirName.create("$prefix$arity"))
val clazz = CirProvided.Class(typeParameters, DescriptorVisibilities.PUBLIC)
consumer(classId, clazz)
}
}
@@ -5,22 +5,29 @@
package org.jetbrains.kotlin.descriptors.commonizer.mergedtree
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.commonizer.ModulesProvider
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId
import org.jetbrains.kotlin.types.Variance
/** A set of classes and type aliases provided by libraries (either the libraries to commonize, or their dependency libraries)/ */
interface CirProvidedClassifiers {
fun hasClassifier(classifierId: CirEntityId): Boolean
// TODO: implement later
//fun classifier(classifierId: ClassId): Any?
fun classifier(classifierId: CirEntityId): CirProvided.Classifier?
object EMPTY : CirProvidedClassifiers {
override fun hasClassifier(classifierId: CirEntityId) = false
override fun classifier(classifierId: CirEntityId): CirProvided.Classifier? = null
}
private class CompositeClassifiers(val delegates: List<CirProvidedClassifiers>) : CirProvidedClassifiers {
override fun hasClassifier(classifierId: CirEntityId) = delegates.any { it.hasClassifier(classifierId) }
override fun classifier(classifierId: CirEntityId): CirProvided.Classifier? {
for (delegate in delegates) {
delegate.classifier(classifierId)?.let { return it }
}
return null
}
}
companion object {
@@ -42,6 +49,55 @@ interface CirProvidedClassifiers {
}
fun by(modulesProvider: ModulesProvider?): CirProvidedClassifiers =
if (modulesProvider != null) CirProvidedClassifiersByModules(modulesProvider) else EMPTY
if (modulesProvider != null) CirProvidedClassifiersByModules.load(modulesProvider) else EMPTY
}
}
object CirProvided {
/* Classifiers */
sealed interface Classifier {
val typeParameters: List<TypeParameter>
}
data class Class(
override val typeParameters: List<TypeParameter>,
val visibility: DescriptorVisibility
) : Classifier
data class TypeAlias(
override val typeParameters: List<TypeParameter>,
val underlyingType: Type
) : Classifier
/* Type parameter */
data class TypeParameter(val index: Int, val variance: Variance)
/* Types */
sealed interface Type {
val isMarkedNullable: Boolean
}
data class TypeParameterType(
val index: Int,
override val isMarkedNullable: Boolean
) : Type
data class ClassType(
val classId: CirEntityId,
val outerType: ClassType?,
val arguments: List<TypeProjection>,
override val isMarkedNullable: Boolean
) : Type
data class TypeAliasType(
val typeAliasId: CirEntityId,
val arguments: List<TypeProjection>,
override val isMarkedNullable: Boolean
) : Type
/* Type projections */
sealed interface TypeProjection
object StarTypeProjection : TypeProjection
data class RegularTypeProjection(val variance: Variance, val type: Type) : TypeProjection
}
@@ -5,58 +5,257 @@
package org.jetbrains.kotlin.descriptors.commonizer.mergedtree
import gnu.trove.THashSet
import com.intellij.util.containers.FactoryMap
import gnu.trove.THashMap
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.commonizer.ModulesProvider
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirName
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirPackageName
import org.jetbrains.kotlin.descriptors.commonizer.utils.NON_EXISTING_CLASSIFIER_ID
import org.jetbrains.kotlin.descriptors.commonizer.utils.compactMap
import org.jetbrains.kotlin.descriptors.commonizer.utils.compactMapIndexed
import org.jetbrains.kotlin.descriptors.commonizer.utils.isUnderKotlinNativeSyntheticPackages
import org.jetbrains.kotlin.library.SerializedMetadata
import org.jetbrains.kotlin.library.metadata.parsePackageFragment
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.serialization.deserialization.ProtoEnumFlags
import org.jetbrains.kotlin.serialization.deserialization.descriptorVisibility
import org.jetbrains.kotlin.types.Variance
internal class CirProvidedClassifiersByModules(modulesProvider: ModulesProvider) : CirProvidedClassifiers {
private val classifiers: Set<CirEntityId> = loadClassifiers(modulesProvider)
internal class CirProvidedClassifiersByModules private constructor(
private val hasForwardDeclarations: Boolean,
private val classifiers: Map<CirEntityId, CirProvided.Classifier>,
) : CirProvidedClassifiers {
override fun hasClassifier(classifierId: CirEntityId) =
if (classifierId.packageName.isUnderKotlinNativeSyntheticPackages) {
hasForwardDeclarations
} else {
classifierId in classifiers
}
override fun hasClassifier(classifierId: CirEntityId): Boolean = classifierId in classifiers
}
override fun classifier(classifierId: CirEntityId) =
if (classifierId.packageName.isUnderKotlinNativeSyntheticPackages) {
if (hasForwardDeclarations) FALLBACK_FORWARD_DECLARATION_CLASS else null
} else {
classifiers[classifierId]
}
private fun loadClassifiers(modulesProvider: ModulesProvider): Set<CirEntityId> {
val result = THashSet<CirEntityId>()
companion object {
fun load(modulesProvider: ModulesProvider): CirProvidedClassifiers {
val classifiers = THashMap<CirEntityId, CirProvided.Classifier>()
var hasForwardDeclarations = false
modulesProvider.loadModuleInfos().forEach { moduleInfo ->
val metadata = modulesProvider.loadModuleMetadata(moduleInfo.name)
for (i in metadata.fragmentNames.indices) {
val packageFqName = metadata.fragmentNames[i]
val packageFragments = metadata.fragments[i]
for (j in packageFragments.indices) {
val packageFragment: ProtoBuf.PackageFragment = parsePackageFragment(packageFragments[j])
val classes: List<ProtoBuf.Class> = packageFragment.class_List
val typeAliases: List<ProtoBuf.TypeAlias> = packageFragment.`package`?.typeAliasList.orEmpty()
if (classes.isEmpty() && typeAliases.isEmpty())
break // this and next package fragments do not contain classifiers and can be skipped
val packageName = CirPackageName.create(packageFqName)
val nameResolver = NameResolverImpl(packageFragment.strings, packageFragment.qualifiedNames)
for (clazz in classes) {
if (!nameResolver.isLocalClassName(clazz.fqName)) {
val classId = CirEntityId.create(nameResolver.getQualifiedClassName(clazz.fqName))
check(classId.packageName == packageName)
result += classId
}
modulesProvider.loadModuleInfos().forEach { moduleInfo ->
if (moduleInfo.cInteropAttributes != null) {
// this is a C-interop module
hasForwardDeclarations = true
}
for (typeAlias in typeAliases) {
val typeAliasId = CirEntityId.create(packageName, CirName.create(nameResolver.getString(typeAlias.name)))
result += typeAliasId
val metadata = modulesProvider.loadModuleMetadata(moduleInfo.name)
readModule(metadata, classifiers::set)
}
if (classifiers.isEmpty)
return CirProvidedClassifiers.EMPTY
return CirProvidedClassifiersByModules(hasForwardDeclarations, classifiers)
}
private val FALLBACK_FORWARD_DECLARATION_CLASS = CirProvided.Class(emptyList(), DescriptorVisibilities.PUBLIC)
}
}
private fun readModule(metadata: SerializedMetadata, consumer: (CirEntityId, CirProvided.Classifier) -> Unit) {
for (i in metadata.fragmentNames.indices) {
val packageFqName = metadata.fragmentNames[i]
val packageFragments = metadata.fragments[i]
val classProtosToRead = ClassProtosToRead()
for (j in packageFragments.indices) {
val packageFragmentProto = parsePackageFragment(packageFragments[j])
val classProtos: List<ProtoBuf.Class> = packageFragmentProto.class_List
val typeAliasProtos: List<ProtoBuf.TypeAlias> = packageFragmentProto.`package`?.typeAliasList.orEmpty()
if (classProtos.isEmpty() && typeAliasProtos.isEmpty())
continue
val packageName = CirPackageName.create(packageFqName)
val strings = NameResolverImpl(packageFragmentProto.strings, packageFragmentProto.qualifiedNames)
classProtosToRead.addClasses(classProtos, strings)
if (typeAliasProtos.isNotEmpty()) {
val types = TypeTable(packageFragmentProto.`package`.typeTable)
for (typeAliasProto in typeAliasProtos) {
readTypeAlias(typeAliasProto, packageName, strings, types, consumer)
}
}
}
classProtosToRead.forEachClassInScope(parentClassId = null) { classEntry ->
readClass(classEntry, classProtosToRead, typeParameterIndexOffset = 0, consumer)
}
}
}
private class ClassProtosToRead {
data class ClassEntry(val classId: CirEntityId, val proto: ProtoBuf.Class)
// key = parent class ID (or NON_EXISTING_CLASSIFIER_ID for top-level classes)
// value = class protos under this parent class (MutableList to preserve order of classes)
private val groupedByParentClassId = FactoryMap.create<CirEntityId, MutableList<ClassEntry>> { ArrayList() }
fun addClasses(classProtos: List<ProtoBuf.Class>, strings: NameResolver) {
classProtos.forEach { classProto ->
if (strings.isLocalClassName(classProto.fqName)) return@forEach
val classId = CirEntityId.create(strings.getQualifiedClassName(classProto.fqName))
val parentClassId: CirEntityId = classId.getParentEntityId() ?: NON_EXISTING_CLASSIFIER_ID
groupedByParentClassId.getValue(parentClassId) += ClassEntry(classId, classProto)
}
}
return result
fun forEachClassInScope(parentClassId: CirEntityId?, block: (ClassEntry) -> Unit) {
groupedByParentClassId[parentClassId ?: NON_EXISTING_CLASSIFIER_ID]?.forEach { classEntry -> block(classEntry) }
}
}
private fun readClass(
classEntry: ClassProtosToRead.ClassEntry,
classProtosToRead: ClassProtosToRead,
typeParameterIndexOffset: Int,
consumer: (CirEntityId, CirProvided.Classifier) -> Unit
) {
val (classId, classProto) = classEntry
val typeParameters = readTypeParameters(
typeParameterProtos = classProto.typeParameterList,
typeParameterIndexOffset = typeParameterIndexOffset
)
val visibility = ProtoEnumFlags.descriptorVisibility(Flags.VISIBILITY.get(classProto.flags))
val clazz = CirProvided.Class(typeParameters, visibility)
consumer(classId, clazz)
classProtosToRead.forEachClassInScope(parentClassId = classId) { nestedClassEntry ->
readClass(nestedClassEntry, classProtosToRead, typeParameterIndexOffset = typeParameters.size + typeParameterIndexOffset, consumer)
}
}
private inline fun readTypeAlias(
typeAliasProto: ProtoBuf.TypeAlias,
packageName: CirPackageName,
strings: NameResolver,
types: TypeTable,
consumer: (CirEntityId, CirProvided.Classifier) -> Unit
) {
val typeAliasId = CirEntityId.create(packageName, CirName.create(strings.getString(typeAliasProto.name)))
val typeParameterNameToIndex = HashMap<Int, Int>()
val typeParameters = readTypeParameters(
typeParameterProtos = typeAliasProto.typeParameterList,
typeParameterIndexOffset = 0,
nameToIndexMapper = typeParameterNameToIndex::set
)
val underlyingType = readType(typeAliasProto.underlyingType(types), TypeReadContext(strings, types, typeParameterNameToIndex))
val typeAlias = CirProvided.TypeAlias(typeParameters, underlyingType)
consumer(typeAliasId, typeAlias)
}
private inline fun readTypeParameters(
typeParameterProtos: List<ProtoBuf.TypeParameter>,
typeParameterIndexOffset: Int,
nameToIndexMapper: (name: Int, id: Int) -> Unit = { _, _ -> }
): List<CirProvided.TypeParameter> =
typeParameterProtos.compactMapIndexed { localIndex, typeParameterProto ->
val index = localIndex + typeParameterIndexOffset
val typeParameter = CirProvided.TypeParameter(
index = index,
variance = readVariance(typeParameterProto.variance)
)
nameToIndexMapper(typeParameterProto.name, index)
typeParameter
}
private class TypeReadContext(
val strings: NameResolver,
val types: TypeTable,
private val _typeParameterNameToIndex: Map<Int, Int>
) {
val typeParameterNameToIndex: (Int) -> Int = { name ->
_typeParameterNameToIndex[name] ?: error("No type parameter index for ${strings.getString(name)}")
}
private val _typeParameterIdToIndex = HashMap<Int, Int>()
val typeParameterIdToIndex: (Int) -> Int = { id -> _typeParameterIdToIndex.getOrPut(id) { _typeParameterIdToIndex.size } }
}
private fun readType(typeProto: ProtoBuf.Type, context: TypeReadContext): CirProvided.Type =
with(typeProto.abbreviatedType(context.types) ?: typeProto) {
when {
hasClassName() -> {
val classId = CirEntityId.create(context.strings.getQualifiedClassName(className))
val outerType = typeProto.outerType(context.types)?.let { outerType ->
val outerClassType = readType(outerType, context)
check(outerClassType is CirProvided.ClassType) { "Outer type of $classId is not a class: $outerClassType" }
outerClassType
}
CirProvided.ClassType(
classId = classId,
outerType = outerType,
arguments = readTypeArguments(argumentList, context),
isMarkedNullable = nullable
)
}
hasTypeAliasName() -> CirProvided.TypeAliasType(
typeAliasId = CirEntityId.create(context.strings.getQualifiedClassName(typeAliasName)),
arguments = readTypeArguments(argumentList, context),
isMarkedNullable = nullable
)
hasTypeParameter() -> CirProvided.TypeParameterType(
index = context.typeParameterIdToIndex(typeParameter),
isMarkedNullable = nullable
)
hasTypeParameterName() -> CirProvided.TypeParameterType(
index = context.typeParameterNameToIndex(typeParameterName),
isMarkedNullable = nullable
)
else -> error("No classifier (class, type alias or type parameter) recorded for Type")
}
}
private fun readTypeArguments(argumentProtos: List<ProtoBuf.Type.Argument>, context: TypeReadContext): List<CirProvided.TypeProjection> =
argumentProtos.compactMap { argumentProto ->
val variance = readVariance(argumentProto.projection!!) ?: return@compactMap CirProvided.StarTypeProjection
val typeProto = argumentProto.type(context.types) ?: error("No type argument for non-STAR projection in Type")
CirProvided.RegularTypeProjection(
variance = variance,
type = readType(typeProto, context)
)
}
@Suppress("NOTHING_TO_INLINE")
private inline fun readVariance(varianceProto: ProtoBuf.TypeParameter.Variance): Variance =
when (varianceProto) {
ProtoBuf.TypeParameter.Variance.IN -> Variance.IN_VARIANCE
ProtoBuf.TypeParameter.Variance.OUT -> Variance.OUT_VARIANCE
ProtoBuf.TypeParameter.Variance.INV -> Variance.INVARIANT
}
@Suppress("NOTHING_TO_INLINE")
private inline fun readVariance(varianceProto: ProtoBuf.Type.Argument.Projection): Variance? =
when (varianceProto) {
ProtoBuf.Type.Argument.Projection.IN -> Variance.IN_VARIANCE
ProtoBuf.Type.Argument.Projection.OUT -> Variance.OUT_VARIANCE
ProtoBuf.Type.Argument.Projection.INV -> Variance.INVARIANT
ProtoBuf.Type.Argument.Projection.STAR -> null
}
@@ -0,0 +1,414 @@
/*
* Copyright 2010-2021 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.descriptors.commonizer.mergedtree
import com.intellij.util.containers.FactoryMap
import kotlinx.metadata.*
import kotlinx.metadata.klib.KlibModuleMetadata
import kotlinx.metadata.klib.fqName
import kotlinx.metadata.klib.klibEnumEntries
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerParameters
import org.jetbrains.kotlin.descriptors.commonizer.LeafCommonizerTarget
import org.jetbrains.kotlin.descriptors.commonizer.ModulesProvider.ModuleInfo
import org.jetbrains.kotlin.descriptors.commonizer.TargetProvider
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirName
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirPackageName
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.*
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ClassesToProcess.ClassEntry
import org.jetbrains.kotlin.descriptors.commonizer.metadata.utils.SerializedMetadataLibraryProvider
import org.jetbrains.kotlin.descriptors.commonizer.prettyName
import org.jetbrains.kotlin.descriptors.commonizer.utils.*
import org.jetbrains.kotlin.storage.StorageManager
/**
* N.B. Limitations on C/Obj-C interop.
*
* [Case 1]: An interop library with two fragments for two targets. The first fragment has a forward declaration of classifier A.
* The second one has a definition of class A. Both fragments have a top-level callable (ex: function)
* with the same signature that refers to type "A" as its return type.
*
* What will happen: Forward declarations will be ignored during building CIR merged tree. So the node for class A
* will contain CirClass "A" for the second target only. This node will not succeed in commonization, and no common class
* declaration will be produced. As a result the top-level callable will not be commonized, as it refers to the type "A"
* that is not formally commonized.
*
* This is not strictly correct: The classifier "A" exists in both targets though in different form. So if the user
* would write shared source code that uses "A" and the callable, then this code would successfully compile against both targets.
*
* The reason why commonization of such classifiers is not supported yet is that this is quite a rare case that requires
* a complex implementation with potential performance penalty.
*
* [Case 2]: A library with two fragments for two targets. The first fragment is interop. The second one is not.
* Similarly to case 1, the 1st fragment has a forward declaration of a classifier, and the 2nd has a real classifier.
*
* At the moment, this is an exotic case. It could happen if someone tries to commonize an MPP library for Native and non-Native
* targets (which is not supported yet), or a Native library where one fragment is produced via C-interop tool and the other one
* is compiled from Kotlin/Native source code (not sure this should be supported at all).
*/
class CirTreeMergerV2(
private val storageManager: StorageManager,
private val classifiers: CirKnownClassifiers,
private val parameters: CommonizerParameters
) {
class CirTreeMergeResult(
val root: CirRootNode,
val missingModuleInfos: Map<LeafCommonizerTarget, Collection<ModuleInfo>>
)
private class CirTreeMergingContext(
val targetIndex: Int,
val typeResolver: CirTypeResolver
) {
fun create(classEntry: ClassEntry): CirTreeMergingContext = when (classEntry) {
is ClassEntry.RegularClassEntry -> create(classEntry.clazz.typeParameters)
is ClassEntry.EnumEntry -> this
}
fun create(typeParameters: List<KmTypeParameter>): CirTreeMergingContext {
val newTypeResolver = typeResolver.create(typeParameters)
return if (newTypeResolver !== typeResolver)
CirTreeMergingContext(targetIndex, newTypeResolver)
else
this
}
}
private val leafTargetsSize = parameters.targetProviders.size
fun build(): CirTreeMergeResult {
val result = processRoot()
System.gc()
return result
}
private fun processRoot(): CirTreeMergeResult {
val rootNode: CirRootNode = buildRootNode(storageManager, leafTargetsSize)
// remember any exported forward declarations from common fragments of dependee modules
parameters.dependencyModulesProvider?.loadModuleInfos()?.forEach(::processCInteropModuleAttributes)
val commonModuleNames = parameters.getCommonModuleNames()
val missingModuleInfosByTargets = mutableMapOf<LeafCommonizerTarget, Collection<ModuleInfo>>()
parameters.targetProviders.forEachIndexed { targetIndex, targetProvider ->
val allModuleInfos = targetProvider.modulesProvider.loadModuleInfos()
val (commonModuleInfos, missingModuleInfos) = allModuleInfos.partition { it.name in commonModuleNames }
processTarget(targetIndex, rootNode, targetProvider, commonModuleInfos)
missingModuleInfosByTargets[targetProvider.target] = missingModuleInfos
parameters.progressLogger?.invoke("Loaded declarations for ${targetProvider.target.prettyName}")
System.gc()
}
return CirTreeMergeResult(
root = rootNode,
missingModuleInfos = missingModuleInfosByTargets
)
}
private fun processTarget(
targetIndex: Int,
rootNode: CirRootNode,
targetProvider: TargetProvider,
commonModuleInfos: Collection<ModuleInfo>
) {
rootNode.targetDeclarations[targetIndex] = CirRootFactory.create(targetProvider.target)
if (commonModuleInfos.isEmpty())
return
val context = CirTreeMergingContext(
targetIndex = targetIndex,
// all classifiers "visible" for the target:
typeResolver = CirTypeResolver.create(
providedClassifiers = CirProvidedClassifiers.of(
classifiers.commonDependencies,
CirProvidedClassifiers.by(targetProvider.dependencyModulesProvider),
CirProvidedClassifiers.by(targetProvider.modulesProvider)
)
)
)
commonModuleInfos.forEach { moduleInfo ->
val metadata = targetProvider.modulesProvider.loadModuleMetadata(moduleInfo.name)
val module = KlibModuleMetadata.read(SerializedMetadataLibraryProvider(metadata))
processModule(context, rootNode, moduleInfo, module)
}
}
private fun processModule(
context: CirTreeMergingContext,
rootNode: CirRootNode,
moduleInfo: ModuleInfo,
module: KlibModuleMetadata
) {
processCInteropModuleAttributes(moduleInfo)
val moduleName: CirName = CirName.create(module.name)
val moduleNode: CirModuleNode = rootNode.modules.getOrPut(moduleName) {
buildModuleNode(storageManager, leafTargetsSize)
}
moduleNode.targetDeclarations[context.targetIndex] = CirModuleFactory.create(moduleName)
val groupedFragments: Map<CirPackageName, Collection<KmModuleFragment>> = module.fragments.foldToMap { fragment ->
fragment.fqName?.let(CirPackageName::create) ?: error("A fragment without FQ name in module $moduleName: $fragment")
}
groupedFragments.forEach { (packageName, fragments) ->
processFragments(context, moduleNode, fragments, packageName)
}
}
private fun processFragments(
context: CirTreeMergingContext,
moduleNode: CirModuleNode,
fragments: Collection<KmModuleFragment>,
packageName: CirPackageName
) {
val packageNode: CirPackageNode = moduleNode.packages.getOrPut(packageName) {
buildPackageNode(storageManager, leafTargetsSize)
}
packageNode.targetDeclarations[context.targetIndex] = CirPackageFactory.create(packageName)
val classesToProcess = ClassesToProcess()
fragments.forEach { fragment ->
classesToProcess.addClassesFromFragment(fragment)
fragment.pkg?.let { pkg ->
pkg.properties.forEach { property ->
val propertyContext = context.create(property.typeParameters)
processProperty(propertyContext, packageNode, property)
}
pkg.functions.forEach { function ->
val functionContext = context.create(function.typeParameters)
processFunction(functionContext, packageNode, function)
}
pkg.typeAliases.forEach { typeAlias ->
val typeAliasContext = context.create(typeAlias.typeParameters)
processTypeAlias(typeAliasContext, packageNode, typeAlias)
}
}
}
classesToProcess.forEachClassInScope(parentClassId = null) { classEntry ->
val classContext = context.create(classEntry)
processClass(classContext, packageNode, classEntry, classesToProcess)
}
}
private fun processProperty(
context: CirTreeMergingContext,
ownerNode: CirNodeWithMembers<*, *>,
property: KmProperty
) {
if (property.isFakeOverride())
return
val maybeClassOwnerNode: CirClassNode? = ownerNode as? CirClassNode
val approximationKey = PropertyApproximationKey(property, context.typeResolver)
val propertyNode: CirPropertyNode = ownerNode.properties.getOrPut(approximationKey) {
buildPropertyNode(storageManager, leafTargetsSize, classifiers, maybeClassOwnerNode?.commonDeclaration)
}
propertyNode.targetDeclarations[context.targetIndex] = CirPropertyFactory.create(
name = approximationKey.name,
source = property,
containingClass = maybeClassOwnerNode?.targetDeclarations?.get(context.targetIndex),
typeResolver = context.typeResolver
)
}
private fun processFunction(
context: CirTreeMergingContext,
ownerNode: CirNodeWithMembers<*, *>,
function: KmFunction
) {
if (function.isFakeOverride()
|| function.isKniBridgeFunction()
|| function.isTopLevelDeprecatedFunction(isTopLevel = ownerNode !is CirClassNode)
) {
return
}
val maybeClassOwnerNode: CirClassNode? = ownerNode as? CirClassNode
val approximationKey = FunctionApproximationKey(function, context.typeResolver)
val functionNode: CirFunctionNode = ownerNode.functions.getOrPut(approximationKey) {
buildFunctionNode(storageManager, leafTargetsSize, classifiers, maybeClassOwnerNode?.commonDeclaration)
}
functionNode.targetDeclarations[context.targetIndex] = CirFunctionFactory.create(
name = approximationKey.name,
source = function,
containingClass = maybeClassOwnerNode?.targetDeclarations?.get(context.targetIndex),
typeResolver = context.typeResolver
)
}
private fun processClass(
context: CirTreeMergingContext,
ownerNode: CirNodeWithMembers<*, *>,
classEntry: ClassEntry,
classesToProcess: ClassesToProcess
) {
val classId = classEntry.classId
val className = classId.relativeNameSegments.last()
val maybeClassOwnerNode: CirClassNode? = ownerNode as? CirClassNode
val classNode: CirClassNode = ownerNode.classes.getOrPut(className) {
buildClassNode(storageManager, leafTargetsSize, classifiers, maybeClassOwnerNode?.commonDeclaration, classId)
}
val clazz: KmClass?
val isEnumEntry: Boolean
classNode.targetDeclarations[context.targetIndex] = when (classEntry) {
is ClassEntry.RegularClassEntry -> {
clazz = classEntry.clazz
isEnumEntry = Flag.Class.IS_ENUM_ENTRY(clazz.flags)
CirClassFactory.create(className, clazz, context.typeResolver)
}
is ClassEntry.EnumEntry -> {
clazz = null
isEnumEntry = true
CirClassFactory.createDefaultEnumEntry(
name = className,
annotations = classEntry.annotations,
enumClassId = classEntry.enumClassId,
enumClass = classEntry.enumClass,
typeResolver = context.typeResolver
)
}
}
if (!isEnumEntry) {
clazz?.constructors?.forEach { constructor ->
// TODO: nowhere to read constructor type parameters from
//val constructorContext = context.create(constructor.typeParameters)
processClassConstructor(context, classNode, constructor)
}
}
clazz?.properties?.forEach { property ->
val propertyContext = context.create(property.typeParameters)
processProperty(propertyContext, classNode, property)
}
clazz?.functions?.forEach { function ->
val functionContext = context.create(function.typeParameters)
processFunction(functionContext, classNode, function)
}
classesToProcess.forEachClassInScope(parentClassId = classId) { nestedClassEntry ->
val nestedClassContext = context.create(nestedClassEntry)
processClass(nestedClassContext, classNode, nestedClassEntry, classesToProcess)
}
}
private fun processClassConstructor(
context: CirTreeMergingContext,
classNode: CirClassNode,
constructor: KmConstructor
) {
val approximationKey = ConstructorApproximationKey(constructor, context.typeResolver)
val constructorNode: CirClassConstructorNode = classNode.constructors.getOrPut(approximationKey) {
buildClassConstructorNode(storageManager, leafTargetsSize, classifiers, classNode.commonDeclaration)
}
constructorNode.targetDeclarations[context.targetIndex] = CirClassConstructorFactory.create(
source = constructor,
containingClass = classNode.targetDeclarations[context.targetIndex]!!,
typeResolver = context.typeResolver
)
}
private fun processTypeAlias(
context: CirTreeMergingContext,
packageNode: CirPackageNode,
typeAlias: KmTypeAlias
) {
val typeAliasName = CirName.create(typeAlias.name)
val typeAliasId = CirEntityId.create(packageNode.packageName, typeAliasName)
val typeAliasNode: CirTypeAliasNode = packageNode.typeAliases.getOrPut(typeAliasName) {
buildTypeAliasNode(storageManager, leafTargetsSize, classifiers, typeAliasId)
}
typeAliasNode.targetDeclarations[context.targetIndex] = CirTypeAliasFactory.create(
name = typeAliasName,
source = typeAlias,
typeResolver = context.typeResolver
)
}
private fun processCInteropModuleAttributes(moduleInfo: ModuleInfo) {
val cInteropAttributes = moduleInfo.cInteropAttributes ?: return
val exportForwardDeclarations = cInteropAttributes.exportForwardDeclarations.takeIf { it.isNotEmpty() } ?: return
exportForwardDeclarations.forEach { classFqName ->
// Class has synthetic package FQ name (cnames/objcnames). Need to transfer it to the main package.
val packageName = CirPackageName.create(classFqName.substringBeforeLast('.', missingDelimiterValue = ""))
val className = CirName.create(classFqName.substringAfterLast('.'))
classifiers.forwardDeclarations.addExportedForwardDeclaration(CirEntityId.create(packageName, className))
}
}
}
private class ClassesToProcess {
sealed class ClassEntry {
abstract val classId: CirEntityId
data class RegularClassEntry(
override val classId: CirEntityId,
val clazz: KmClass
) : ClassEntry()
data class EnumEntry(
override val classId: CirEntityId,
val annotations: List<KmAnnotation>,
val enumClassId: CirEntityId,
val enumClass: KmClass
) : ClassEntry()
}
// key = parent class ID (or NON_EXISTING_CLASSIFIER_ID for top-level classes)
// value = classes under this parent class (MutableList to preserve order of classes)
private val groupedByParentClassId = FactoryMap.create<CirEntityId, MutableList<ClassEntry>> { ArrayList() }
fun addClassesFromFragment(fragment: KmModuleFragment) {
val klibEnumEntries = LinkedHashMap<CirEntityId, ClassEntry.EnumEntry>() // linked hash map to preserve order
val regularClassIds = HashSet<CirEntityId>()
fragment.classes.forEach { clazz ->
val classId: CirEntityId = CirEntityId.create(clazz.name)
val parentClassId: CirEntityId = classId.getParentEntityId() ?: NON_EXISTING_CLASSIFIER_ID
if (Flag.Class.IS_ENUM_CLASS(clazz.flags)) {
clazz.klibEnumEntries.forEach { entry ->
val enumEntryId = classId.createNestedEntityId(CirName.create(entry.name))
klibEnumEntries[enumEntryId] = ClassEntry.EnumEntry(enumEntryId, entry.annotations, classId, clazz)
}
}
groupedByParentClassId.getValue(parentClassId) += ClassEntry.RegularClassEntry(classId, clazz)
regularClassIds += classId
}
// add enum entries that are not stored in module as KmClass records
klibEnumEntries.forEach { (enumEntryId, enumEntry) ->
if (enumEntryId !in regularClassIds) {
groupedByParentClassId.getValue(enumEntry.enumClassId) += enumEntry
}
}
}
fun forEachClassInScope(parentClassId: CirEntityId?, block: (ClassEntry) -> Unit) {
groupedByParentClassId[parentClassId ?: NON_EXISTING_CLASSIFIER_ID]?.forEach { classEntry -> block(classEntry) }
}
}
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.descriptors.commonizer.mergedtree
import kotlinx.metadata.*
import kotlinx.metadata.klib.annotations
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirName
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirTypeSignature
@@ -21,6 +23,11 @@ data class PropertyApproximationKey(
CirName.create(property.name),
property.extensionReceiverParameter?.type?.signature
)
constructor(property: KmProperty, typeParameterResolver: TypeParameterResolver) : this(
CirName.create(property.name),
property.receiverParameterType?.computeSignature(typeParameterResolver)
)
}
/** Used for approximation of [SimpleFunctionDescriptor]s before running concrete [Commonizer]s */
@@ -37,6 +44,13 @@ data class FunctionApproximationKey(
function.extensionReceiverParameter?.type?.signature
)
constructor(function: KmFunction, typeParameterResolver: TypeParameterResolver) : this(
CirName.create(function.name),
function.valueParameters.computeSignatures(typeParameterResolver),
additionalValueParameterNamesHash(function.annotations, function.valueParameters),
function.receiverParameterType?.computeSignature(typeParameterResolver)
)
override fun equals(other: Any?): Boolean {
if (other !is FunctionApproximationKey)
return false
@@ -63,6 +77,11 @@ data class ConstructorApproximationKey(
additionalValueParameterNamesHash(constructor)
)
constructor(constructor: KmConstructor, typeParameterResolver: TypeParameterResolver) : this(
constructor.valueParameters.computeSignatures(typeParameterResolver),
additionalValueParameterNamesHash(constructor.annotations, constructor.valueParameters)
)
override fun equals(other: Any?): Boolean {
if (other !is ConstructorApproximationKey)
return false
@@ -75,9 +94,24 @@ data class ConstructorApproximationKey(
.appendHashCode(additionalValueParametersNamesHash)
}
interface TypeParameterResolver {
fun resolveTypeParameter(id: Int): KmTypeParameter?
companion object {
val EMPTY = object : TypeParameterResolver {
override fun resolveTypeParameter(id: Int): KmTypeParameter? = null
}
}
}
@JvmName("toTypeSignaturesDescriptors")
@Suppress("NOTHING_TO_INLINE")
private inline fun List<ValueParameterDescriptor>.toTypeSignatures(): Array<CirTypeSignature> =
Array(size) { index -> this[index].type.signature }
if (isEmpty()) emptyArray() else Array(size) { index -> this[index].type.signature }
@Suppress("NOTHING_TO_INLINE")
private inline fun List<KmValueParameter>.computeSignatures(typeParameterResolver: TypeParameterResolver): Array<CirTypeSignature> =
if (isEmpty()) emptyArray() else Array(size) { index -> this[index].type?.computeSignature(typeParameterResolver).orEmpty() }
private fun additionalValueParameterNamesHash(callable: FunctionDescriptor): Int {
// TODO: add more precise checks when more languages than C & ObjC are supported
@@ -86,3 +120,11 @@ private fun additionalValueParameterNamesHash(callable: FunctionDescriptor): Int
return callable.valueParameters.fold(0) { acc, next -> acc.appendHashCode(next.name.asString()) }
}
private fun additionalValueParameterNamesHash(annotations: List<KmAnnotation>, valueParameters: List<KmValueParameter>): Int {
// TODO: add more precise checks when more languages than C & ObjC are supported
if (annotations.none { it.isObjCInteropCallableAnnotation })
return 0 // do not calculate hash for non-ObjC callables
return valueParameters.fold(0) { acc, next -> acc.appendHashCode(next.name) }
}
@@ -133,6 +133,7 @@ internal fun CirClassConstructor.buildClassConstructor(
flags = classConstructorFlags()
).also { constructor ->
annotations.mapTo(constructor.annotations) { it.buildAnnotation() }
// TODO: nowhere to write constructor type parameters
valueParameters.mapTo(constructor.valueParameters) { it.buildValueParameter(context) }
}
@@ -156,11 +157,11 @@ internal fun CirProperty.buildProperty(
getterFlags = getter?.propertyAccessorFlags(this, this) ?: NO_FLAGS,
setterFlags = setter?.let { setter -> setter.propertyAccessorFlags(setter, this) } ?: NO_FLAGS
).also { property ->
// TODO unclear where to write backing/delegate field annotations, see KT-44625
annotations.mapTo(property.annotations) { it.buildAnnotation() }
getter?.annotations?.mapTo(property.getterAnnotations) { it.buildAnnotation() }
setter?.annotations?.mapTo(property.setterAnnotations) { it.buildAnnotation() }
property.compileTimeValue = compileTimeInitializer?.takeIf { it !is CirConstantValue.NullValue }?.buildAnnotationArgument()
// TODO unclear where to write backing/delegate field annotations, see KT-44625
property.compileTimeValue = compileTimeInitializer.takeIf { it !is CirConstantValue.NullValue }?.buildAnnotationArgument()
typeParameters.buildTypeParameters(context, output = property.typeParameters)
extensionReceiver?.let { receiver ->
// TODO nowhere to write receiver annotations, see KT-42490
@@ -8,13 +8,11 @@ package org.jetbrains.kotlin.descriptors.commonizer.metadata
import kotlinx.metadata.Flag
import kotlinx.metadata.Flags
import kotlinx.metadata.flagsOf
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
internal const val NO_FLAGS: Flags = 0
internal val ALWAYS_HAS_ANNOTATIONS: Flags = flagsOf(Flag.Common.HAS_ANNOTATIONS)
internal fun CirFunction.functionFlags(isExpect: Boolean): Flags =
flagsOfNotNull(
@@ -100,6 +98,48 @@ internal fun CirTypeAlias.typeAliasFlags(): Flags =
visibilityFlag
)
@Suppress("NOTHING_TO_INLINE")
internal inline fun decodeVisibility(flags: Flags): DescriptorVisibility =
when {
Flag.Common.IS_PUBLIC(flags) -> DescriptorVisibilities.PUBLIC
Flag.Common.IS_PROTECTED(flags) -> DescriptorVisibilities.PROTECTED
Flag.Common.IS_INTERNAL(flags) -> DescriptorVisibilities.INTERNAL
Flag.Common.IS_PRIVATE(flags) -> DescriptorVisibilities.PRIVATE
else -> error("Can't decode visibility from flags: $flags")
}
@Suppress("NOTHING_TO_INLINE")
internal inline fun decodeModality(flags: Flags): Modality =
when {
Flag.Common.IS_FINAL(flags) -> Modality.FINAL
Flag.Common.IS_ABSTRACT(flags) -> Modality.ABSTRACT
Flag.Common.IS_OPEN(flags) -> Modality.OPEN
Flag.Common.IS_SEALED(flags) -> Modality.SEALED
else -> error("Can't decode modality from flags: $flags")
}
@Suppress("NOTHING_TO_INLINE")
internal inline fun decodeCallableKind(flags: Flags): CallableMemberDescriptor.Kind =
when {
Flag.Property.IS_DECLARATION(flags) /*|| Flag.Function.IS_DECLARATION(flags)*/ -> CallableMemberDescriptor.Kind.DECLARATION
Flag.Property.IS_FAKE_OVERRIDE(flags) /*|| Flag.Function.IS_FAKE_OVERRIDE(flags)*/ -> CallableMemberDescriptor.Kind.FAKE_OVERRIDE
Flag.Property.IS_DELEGATION(flags) /*|| Flag.Function.IS_DELEGATION(flags)*/ -> CallableMemberDescriptor.Kind.DELEGATION
Flag.Property.IS_SYNTHESIZED(flags) /*|| Flag.Function.IS_SYNTHESIZED(flags)*/ -> CallableMemberDescriptor.Kind.SYNTHESIZED
else -> error("Can't decode callable kind from flags: $flags")
}
@Suppress("NOTHING_TO_INLINE")
internal inline fun decodeClassKind(flags: Flags): ClassKind =
when {
Flag.Class.IS_CLASS(flags) -> ClassKind.CLASS
Flag.Class.IS_INTERFACE(flags) -> ClassKind.INTERFACE
Flag.Class.IS_ENUM_CLASS(flags) -> ClassKind.ENUM_CLASS
Flag.Class.IS_ENUM_ENTRY(flags) -> ClassKind.ENUM_ENTRY
Flag.Class.IS_ANNOTATION_CLASS(flags) -> ClassKind.ANNOTATION_CLASS
Flag.Class.IS_OBJECT(flags) || Flag.Class.IS_COMPANION_OBJECT(flags) -> ClassKind.OBJECT
else -> error("Can't decode class kind from flags: $flags")
}
private inline val CirHasAnnotations.hasAnnotationsFlag: Flag?
get() = if (annotations.isNotEmpty()) Flag.Common.HAS_ANNOTATIONS else null
@@ -5,6 +5,10 @@
package org.jetbrains.kotlin.descriptors.commonizer.utils
import kotlinx.metadata.Flag
import kotlinx.metadata.KmFunction
import kotlinx.metadata.KmProperty
import kotlinx.metadata.klib.annotations
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
@@ -13,5 +17,21 @@ internal const val KNI_BRIDGE_FUNCTION_PREFIX = "kniBridge"
internal fun SimpleFunctionDescriptor.isKniBridgeFunction() =
name.asString().startsWith(KNI_BRIDGE_FUNCTION_PREFIX)
@Suppress("NOTHING_TO_INLINE")
internal inline fun KmFunction.isKniBridgeFunction() =
name.startsWith(KNI_BRIDGE_FUNCTION_PREFIX)
internal fun SimpleFunctionDescriptor.isDeprecatedTopLevelFunction() =
containingDeclaration is PackageFragmentDescriptor && annotations.hasAnnotation(DEPRECATED_ANNOTATION_FQN)
@Suppress("NOTHING_TO_INLINE")
internal inline fun KmFunction.isTopLevelDeprecatedFunction(isTopLevel: Boolean) =
isTopLevel && annotations.any { it.className == DEPRECATED_ANNOTATION_FULL_NAME }
@Suppress("NOTHING_TO_INLINE")
internal inline fun KmProperty.isFakeOverride() =
Flag.Property.IS_FAKE_OVERRIDE(flags)
@Suppress("NOTHING_TO_INLINE")
internal inline fun KmFunction.isFakeOverride() =
Flag.Function.IS_FAKE_OVERRIDE(flags)
@@ -95,6 +95,15 @@ internal inline fun <K : Any, V> compactMapOf(key1: K, value1: V, key2: K, value
internal inline fun <reified T> Iterable<T?>.firstNonNull() = firstIsInstance<T>()
internal inline fun <reified T, reified K : Any> Collection<T>.foldToMap(keySelector: (T) -> K): Map<K, List<T>> {
val result = fold(THashMap<K, MutableList<T>>()) { accumulator, element ->
accumulator.getOrPut(keySelector(element)) { ArrayList() } += element
accumulator
}
return result.compactMapValues { (_, elements) -> elements.compact() }
}
internal fun Any?.isNull(): Boolean = this == null
@Suppress("NOTHING_TO_INLINE")
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.descriptors.commonizer.utils
import kotlinx.metadata.ClassName
import kotlinx.metadata.KmAnnotation
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
@@ -17,16 +18,20 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.konan.impl.ForwardDeclarationsFqNames
internal val DEPRECATED_ANNOTATION_FQN: FqName = FqName(Deprecated::class.java.name)
internal val DEPRECATED_ANNOTATION_CLASS_ID: CirEntityId = CirEntityId.create("kotlin/Deprecated")
internal const val DEPRECATED_ANNOTATION_FULL_NAME: ClassName = "kotlin/Deprecated"
internal val DEPRECATED_ANNOTATION_CLASS_ID: CirEntityId = CirEntityId.create(DEPRECATED_ANNOTATION_FULL_NAME)
internal val ANY_CLASS_ID: CirEntityId = CirEntityId.create("kotlin/Any")
private val NOTHING_CLASS_ID: CirEntityId = CirEntityId.create("kotlin/Nothing")
internal const val ANY_CLASS_FULL_NAME: ClassName = "kotlin/Any"
internal val ANY_CLASS_ID: CirEntityId = CirEntityId.create(ANY_CLASS_FULL_NAME)
internal val SPECIAL_CLASS_WITHOUT_SUPERTYPES_CLASS_IDS: List<CirEntityId> = listOf(
ANY_CLASS_ID,
NOTHING_CLASS_ID
CirEntityId.create("kotlin/Nothing")
)
// illegal Kotlin classifier name, for special purposes only
internal val NON_EXISTING_CLASSIFIER_ID = CirEntityId.create("$0")
internal val SPECIAL_CLASS_WITHOUT_SUPERTYPES_CLASS_NAMES: List<ClassName> =
SPECIAL_CLASS_WITHOUT_SUPERTYPES_CLASS_IDS.map(CirEntityId::toString)
@@ -49,6 +54,10 @@ private val OBJC_INTEROP_CALLABLE_ANNOTATIONS: List<CirName> = listOf(
CirName.create("ObjCFactory")
)
private val OBJC_INTEROP_CALLABLE_ANNOTATION_FULL_NAMES: List<ClassName> = OBJC_INTEROP_CALLABLE_ANNOTATIONS.map { name ->
CirEntityId.create(CINTEROP_PACKAGE, name).toString()
}
internal val DEFAULT_CONSTRUCTOR_NAME: CirName = CirName.create("<init>")
internal val DEFAULT_SETTER_VALUE_NAME: CirName = CirName.create("value")
@@ -70,3 +79,6 @@ internal val AnnotationDescriptor.isObjCInteropCallableAnnotation: Boolean
return CirName.create(classifier.name) in OBJC_INTEROP_CALLABLE_ANNOTATIONS
&& (classifier.containingDeclaration as? PackageFragmentDescriptor)?.fqName?.let(CirPackageName::create) == CINTEROP_PACKAGE
}
internal val KmAnnotation.isObjCInteropCallableAnnotation: Boolean
get() = className in OBJC_INTEROP_CALLABLE_ANNOTATION_FULL_NAMES
@@ -5,12 +5,15 @@
package org.jetbrains.kotlin.descriptors.commonizer.utils
import gnu.trove.TIntHashSet
import kotlinx.metadata.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirName
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirPackageName
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirTypeSignature
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.TypeParameterResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.isNullableAny
@@ -44,9 +47,21 @@ internal val ClassifierDescriptorWithTypeParameters.classifierId: CirEntityId
internal inline val TypeParameterDescriptor.filteredUpperBounds: List<KotlinType>
get() = upperBounds.takeUnless { it.singleOrNull()?.isNullableAny() == true } ?: emptyList()
internal inline val KmTypeParameter.filteredUpperBounds: List<KmType>
get() = upperBounds.takeUnless { it.singleOrNull()?.isNullableAny == true } ?: emptyList()
internal inline val ClassDescriptor.filteredSupertypes: Collection<KotlinType>
get() = typeConstructor.supertypes.takeUnless { it.size == 1 && KotlinBuiltIns.isAny(it.first()) } ?: emptyList()
internal inline val KmClass.filteredSupertypes: List<KmType>
get() = supertypes.takeUnless { it.singleOrNull()?.isAny == true } ?: emptyList()
private inline val KmType.isNullableAny: Boolean
get() = (classifier as? KmClassifier.Class)?.name == ANY_CLASS_FULL_NAME && Flag.Type.IS_NULLABLE(flags)
private inline val KmType.isAny: Boolean
get() = (classifier as? KmClassifier.Class)?.name == ANY_CLASS_FULL_NAME && !Flag.Type.IS_NULLABLE(flags)
internal val KotlinType.signature: CirTypeSignature
get() {
// use of interner saves up to 95% of duplicates
@@ -100,5 +115,84 @@ private fun StringBuilder.buildTypeSignature(type: KotlinType, exploredTypeParam
}
}
internal fun KmType.computeSignature(typeParameterResolver: TypeParameterResolver): CirTypeSignature {
// use of interner saves up to 95% of duplicates
return typeSignatureInterner.intern(
buildString {
buildTypeSignature(
type = this@computeSignature,
typeParameterResolver = typeParameterResolver,
exploredTypeParameters = TIntHashSet()
)
}
)
}
private fun StringBuilder.buildTypeSignature(
type: KmType,
typeParameterResolver: TypeParameterResolver,
exploredTypeParameters: TIntHashSet
) {
when (val classifier = type.classifier) {
is KmClassifier.TypeParameter -> {
// N.B this is type parameter type
val typeParameter = typeParameterResolver.resolveTypeParameter(classifier.id)
?: error("Unresolved type parameter #${classifier.id} in type ${type.classifier}")
append(typeParameter.name)
if (exploredTypeParameters.add(classifier.id)) { // print upper bounds once the first time when type parameter type is met
append(':').append('[')
typeParameter.filteredUpperBounds.forEachIndexed { index, upperBoundType ->
if (index > 0)
append(',')
buildTypeSignature(upperBoundType, typeParameterResolver, exploredTypeParameters)
}
append(']')
}
if (Flag.Type.IS_NULLABLE(type.flags))
append('?')
}
else -> {
val abbreviation = type.abbreviatedType ?: type
val classifierId = when (val abbreviationClassifier = abbreviation.classifier) {
is KmClassifier.Class -> abbreviationClassifier.name
is KmClassifier.TypeAlias -> abbreviationClassifier.name
else -> error("Unexpected classifier type for non-type-parameter type: ${type.classifier}")
}
append(classifierId)
val arguments = abbreviation.arguments
if (arguments.isNotEmpty()) {
append('<')
arguments.forEachIndexed { index, argument ->
if (index > 0)
append(',')
val variance = argument.variance
val argumentType = argument.type
if (variance == null || argumentType == null)
append('*')
else {
when (variance) {
KmVariance.INVARIANT -> Unit
KmVariance.IN -> append("in ")
KmVariance.OUT -> append("out ")
}
buildTypeSignature(argumentType, typeParameterResolver, exploredTypeParameters)
}
}
append('>')
}
if (Flag.Type.IS_NULLABLE(abbreviation.flags))
append('?')
}
}
}
// dedicated to hold unique entries of "signature"
private val typeSignatureInterner = Interner<CirTypeSignature>()
@@ -43,8 +43,7 @@ typealias Y = V // TA at the RHS with the different nullability of own RHS
// Supertypes:
expect class FILE : kotlinx.cinterop.CStructVar
typealias uuid_t = kotlinx.cinterop.CPointer<kotlinx.cinterop.UByteVarOf<kotlinx.cinterop.UByte>>
// ^^^ TODO: ideally, it should be CArrayPointer<UByteVar>
typealias uuid_t = kotlinx.cinterop.CArrayPointer<kotlinx.cinterop.UByteVar>
typealias __darwin_uuid_t = kotlinx.cinterop.CArrayPointer<kotlinx.cinterop.UByteVar>
expect val uuid: uuid_t
@@ -34,7 +34,8 @@ class TypeCommonizerTest : AbstractCommonizerTest<CirType, CirType>() {
commonizedNodes = CirCommonizedClassifierNodes.default(),
forwardDeclarations = CirForwardDeclarations.default(),
commonDependencies = object : CirProvidedClassifiers {
override fun hasClassifier(classifierId: CirEntityId): Boolean = classifierId.packageName.isUnderStandardKotlinPackages
override fun hasClassifier(classifierId: CirEntityId) = classifierId.packageName.isUnderStandardKotlinPackages
override fun classifier(classifierId: CirEntityId) = error("This method should not be called")
}
)
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.descriptors.commonizer.utils
import kotlinx.metadata.klib.KlibModuleMetadata
import kotlinx.metadata.klib.annotations
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
import org.jetbrains.kotlin.descriptors.commonizer.identityString
import org.jetbrains.kotlin.descriptors.commonizer.metadata.utils.MetadataDeclarationsComparator
@@ -52,30 +53,46 @@ fun assertModulesAreEqual(reference: SerializedMetadata, generated: SerializedMe
private val FILTER_OUT_ACCEPTABLE_MISMATCHES: (Mismatch) -> Boolean = { mismatch ->
var isAcceptableMismatch = false // don't filter it out by default
if (mismatch is Mismatch.MissingEntity) {
if (mismatch.kind == EntityKind.TypeKind.ABBREVIATED) {
val usefulPath = mismatch.path
.dropWhile { it !is PathElement.Package }
.drop(1)
when (mismatch) {
is Mismatch.MissingEntity -> when (mismatch.kind) {
EntityKind.TypeKind.ABBREVIATED -> {
val usefulPath = mismatch.path
.dropWhile { it !is PathElement.Package }
.drop(1)
if (mismatch.missingInA) {
if (usefulPath.size == 2
&& usefulPath[0] is PathElement.TypeAlias
&& (usefulPath[1] as? PathElement.Type)?.kind == EntityKind.TypeKind.EXPANDED
) {
// extra abbreviated type appeared in commonized declaration, it's OK
isAcceptableMismatch = true
if (mismatch.missingInA) {
if (usefulPath.size == 2
&& usefulPath[0] is PathElement.TypeAlias
&& (usefulPath[1] as? PathElement.Type)?.kind == EntityKind.TypeKind.EXPANDED
) {
// extra abbreviated type appeared in commonized declaration, it's OK
isAcceptableMismatch = true
}
} else /*if (mismatch.missingInB)*/ {
if (usefulPath.size > 2
&& usefulPath.any { (it as? PathElement.Type)?.kind == EntityKind.TypeKind.RETURN }
&& usefulPath[usefulPath.size - 2] is PathElement.TypeArgument
&& (usefulPath[usefulPath.size - 1] as? PathElement.Type)?.kind == EntityKind.TypeKind.TYPE_ARGUMENT
) {
// extra abbreviated type gone in type argument of commonized declaration, it's OK
isAcceptableMismatch = true
}
}
} else /*if (mismatch.missingInB)*/ {
if (usefulPath.size > 2
&& usefulPath.any { (it as? PathElement.Type)?.kind == EntityKind.TypeKind.RETURN }
&& usefulPath[usefulPath.size - 2] is PathElement.TypeArgument
&& (usefulPath[usefulPath.size - 1] as? PathElement.Type)?.kind == EntityKind.TypeKind.TYPE_ARGUMENT
}
else -> Unit
}
is Mismatch.DifferentValues -> when (mismatch.kind) {
EntityKind.FlagKind.REGULAR, EntityKind.FlagKind.GETTER, EntityKind.FlagKind.SETTER -> {
if (mismatch.name == "HAS_ANNOTATIONS"
&& mismatch.valueA == true
&& mismatch.valueB == false
&& (mismatch.path.last() as? PathElement.Property)?.propertyA?.annotations.isNullOrEmpty()
) {
// extra abbreviated type gone in type argument of commonized declaration, it's OK
// backing or delegate field annotations were not serialized (KT-44625) but the corresponding flag was raised, it's OK
isAcceptableMismatch = true
}
}
else -> Unit
}
}