[Commonizer] Metadata comparator: Proper comparison of type lists

There are two types of type lists that can be met in Kotlin metadata
and that should be treated in a different way:

1. The order-sensitive type list. Examples: Context receivers.
2. The order-insensitive type list. Examples: Class supertypes,
   type parameter upper bounds.

With (1) swapping elements in list causes source and/or ABI
incompatibility, while with (2) it does not. If it happens that we
compare two type lists in Kotlin metadata of (2) kind, we should group
them using the key computed with the help of
`dumpToString(dumpExtras = false)` instead of just the index as we do
in case of (1).

^KT-62753
This commit is contained in:
Dmitriy Dolovov
2024-02-20 16:58:28 +01:00
committed by Space Team
parent 40af02ca4f
commit 8365915b3f
@@ -161,7 +161,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con
TypeParameter(entityA, entityB, index)
}
entityA is KmType && entityB is KmType -> {
val optionalIndex = entityKey?.toInt()
val optionalIndex = entityKey?.toIntOrNull()
val typeKind = entityKind as TypeKind
Type(entityA, entityB, typeKind, optionalIndex)
}
@@ -528,11 +528,27 @@ class MetadataDeclarationsComparator private constructor(private val config: Con
)
}
private fun compareTypeLists(
private fun compareOrderInsensitiveTypeLists(
containerContext: Context,
typeListA: List<KmType>,
typeListB: List<KmType>,
typeKind: TypeKind
) {
compareUniqueEntityLists(
containerContext = containerContext,
entityListA = typeListA,
entityListB = typeListB,
entityKind = typeKind,
groupingKeySelector = { _, type -> type.dumpToString(dumpExtras = false) },
entitiesComparator = ::compareTypes
)
}
private fun compareOrderSensitiveTypeLists(
containerContext: Context,
typeListA: List<KmType>,
typeListB: List<KmType>,
@Suppress("SameParameterValue") typeKind: TypeKind
) {
compareUniqueEntityLists(
containerContext = containerContext,
@@ -587,8 +603,8 @@ class MetadataDeclarationsComparator private constructor(private val config: Con
compareTypeParameterLists(classContext, classA.typeParameters, classB.typeParameters)
compareTypeLists(classContext, classA.supertypes, classB.supertypes, TypeKind.SUPERTYPE)
compareTypeLists(classContext, classA.contextReceiverTypes, classB.contextReceiverTypes, TypeKind.CONTEXT_RECEIVER)
compareOrderInsensitiveTypeLists(classContext, classA.supertypes, classB.supertypes, TypeKind.SUPERTYPE)
compareOrderSensitiveTypeLists(classContext, classA.contextReceiverTypes, classB.contextReceiverTypes, TypeKind.CONTEXT_RECEIVER)
compareNullableEntities(
containerContext = classContext,
@@ -678,7 +694,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con
entityKind = TypeKind.RECEIVER,
entitiesComparator = ::compareTypes
)
compareTypeLists(
compareOrderSensitiveTypeLists(
containerContext = propertyContext,
typeListA = propertyA.contextReceiverTypes,
typeListB = propertyB.contextReceiverTypes,
@@ -722,7 +738,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con
entityKind = TypeKind.RECEIVER,
entitiesComparator = ::compareTypes
)
compareTypeLists(
compareOrderSensitiveTypeLists(
containerContext = functionContext,
typeListA = functionA.contextReceiverTypes,
typeListB = functionB.contextReceiverTypes,
@@ -887,7 +903,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con
compareValues(typeParameterContext, typeParameterA.name, typeParameterB.name, EntityKind.TypeParameterName)
compareValues(typeParameterContext, typeParameterA.variance, typeParameterB.variance, EntityKind.TypeParameterVariance)
compareTypeLists(typeParameterContext, typeParameterA.upperBounds, typeParameterB.upperBounds, TypeKind.UPPER_BOUND)
compareOrderInsensitiveTypeLists(typeParameterContext, typeParameterA.upperBounds, typeParameterB.upperBounds, TypeKind.UPPER_BOUND)
}
@OptIn(ExperimentalContracts::class)