From 8365915b3fce560e8ebec18e44e8f1a688a5d2e1 Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Tue, 20 Feb 2024 16:58:28 +0100 Subject: [PATCH] [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 --- .../utils/MetadataDeclarationsComparator.kt | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/metadata/utils/MetadataDeclarationsComparator.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/metadata/utils/MetadataDeclarationsComparator.kt index 44f9ae84ef2..f26e59b436c 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/metadata/utils/MetadataDeclarationsComparator.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/metadata/utils/MetadataDeclarationsComparator.kt @@ -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, typeListB: List, 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, + typeListB: List, + @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)