diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/cir/CirType.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/cir/CirType.kt index 5bab59192eb..7a5ee28ed84 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/cir/CirType.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/cir/CirType.kt @@ -84,6 +84,8 @@ sealed class CirClassOrTypeAliasType : CirSimpleType() { if (arguments.isNotEmpty()) arguments.joinTo(builder, prefix = "<", postfix = ">") super.appendDescriptionTo(builder) } + + abstract fun withArguments(arguments: List): CirClassOrTypeAliasType } abstract class CirClassType : CirClassOrTypeAliasType(), CirHasVisibility { @@ -98,6 +100,16 @@ abstract class CirClassType : CirClassOrTypeAliasType(), CirHasVisibility { super.appendDescriptionTo(builder, shortNameOnly = outerType != null) } + override fun withArguments(arguments: List): CirClassOrTypeAliasType { + return createInterned( + classId = classifierId, + outerType = outerType, + visibility = visibility, + arguments = arguments, + isMarkedNullable = isMarkedNullable + ) + } + companion object { fun createInterned( classId: CirEntityId, @@ -134,6 +146,15 @@ abstract class CirTypeAliasType : CirClassOrTypeAliasType() { underlyingType.appendDescriptionTo(builder) } + override fun withArguments(arguments: List): CirClassOrTypeAliasType { + return createInterned( + typeAliasId = classifierId, + underlyingType = underlyingType, + arguments = arguments, + isMarkedNullable = isMarkedNullable + ) + } + companion object { fun createInterned( typeAliasId: CirEntityId, diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/TypeAliasCommonizer.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/TypeAliasCommonizer.kt index 98fee727946..9e96026272d 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/TypeAliasCommonizer.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/TypeAliasCommonizer.kt @@ -7,91 +7,29 @@ package org.jetbrains.kotlin.commonizer.core import org.jetbrains.kotlin.commonizer.cir.* import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers -import org.jetbrains.kotlin.descriptors.ClassKind -import org.jetbrains.kotlin.descriptors.Modality -/** - * Primary (optimistic) branch: - * - Make sure that all TAs expand to the same type, so the resulting TA can be short-circuited and lifted up into "common" fragment. - * - * Secondary (less optimistic) branch: - * - Make sure that all TAs are identical, so the resulting TA can be lifted up into "common" fragment. - */ -class TypeAliasCommonizer(classifiers: CirKnownClassifiers) : AbstractStandardCommonizer() { - private val primary = TypeAliasShortCircuitingCommonizer(classifiers) - private val secondary = TypeAliasLiftingUpCommonizer(classifiers) - - override fun commonizationResult(): CirTypeAlias = primary.resultOrNull ?: secondary.result - - override fun initialize(first: CirTypeAlias) = Unit - - override fun doCommonizeWith(next: CirTypeAlias): Boolean { - val primaryResult = primary.commonizeWith(next) - val secondaryResult = secondary.commonizeWith(next) - - // Note: don't call commonizeWith() functions in return statement to avoid short-circuiting! - return primaryResult || secondaryResult - } -} - -private class TypeAliasShortCircuitingCommonizer( +class TypeAliasCommonizer( private val classifiers: CirKnownClassifiers -) : AbstractStandardCommonizer() { - private lateinit var name: CirName - private val typeParameters = TypeParameterListCommonizer(classifiers) - private var underlyingType: CirClassOrTypeAliasType? = null // null means not computed yet - private val expandedType = TypeCommonizer(classifiers).asCommonizer() - private val visibility = VisibilityCommonizer.lowering() +) : AssociativeCommonizer { - override fun commonizationResult() = CirTypeAlias.create( - annotations = emptyList(), - name = name, - typeParameters = typeParameters.result, - visibility = visibility.result, - underlyingType = underlyingType!!, - expandedType = expandedType.result as CirClassType - ) + override fun commonize(first: CirTypeAlias, second: CirTypeAlias): CirTypeAlias? { + val name = if (first.name == second.name) first.name else return null - override fun initialize(first: CirTypeAlias) { - name = first.name - } + val typeParameters = TypeParameterListCommonizer(classifiers) + .commonize(listOf(first.typeParameters, second.typeParameters)) ?: return null - override fun doCommonizeWith(next: CirTypeAlias): Boolean { - if (underlyingType == null) { - underlyingType = computeSuitableUnderlyingType(classifiers, next.underlyingType) ?: return false - } + val underlyingType = TypeCommonizer(classifiers) + .commonize(first.underlyingType, second.underlyingType) as? CirClassOrTypeAliasType ?: return null - return typeParameters.commonizeWith(next.typeParameters) - && expandedType.commonizeWith(next.expandedType) - && visibility.commonizeWith(next) - } -} - -private class TypeAliasLiftingUpCommonizer(classifiers: CirKnownClassifiers) : AbstractStandardCommonizer() { - private lateinit var name: CirName - private val typeParameters = TypeParameterListCommonizer(classifiers) - private val underlyingType = TypeCommonizer(classifiers).asCommonizer() - private val visibility = VisibilityCommonizer.lowering() - - override fun commonizationResult(): CirTypeAlias { - val underlyingType = underlyingType.result as CirClassOrTypeAliasType + val visibility = VisibilityCommonizer.lowering().commonize(listOf(first, second)) ?: return null return CirTypeAlias.create( annotations = emptyList(), name = name, - typeParameters = typeParameters.result, - visibility = visibility.result, + typeParameters = typeParameters, + visibility = visibility, underlyingType = underlyingType, - expandedType = computeExpandedType(underlyingType) + expandedType = underlyingType.expandedType() ) } - - override fun initialize(first: CirTypeAlias) { - name = first.name - } - - override fun doCommonizeWith(next: CirTypeAlias) = - typeParameters.commonizeWith(next.typeParameters) - && underlyingType.commonizeWith(next.underlyingType) - && visibility.commonizeWith(next) -} +} \ No newline at end of file diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/TypeAliasTypeCommonizer.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/TypeAliasTypeCommonizer.kt index 2be5e1c7da3..a0c051b5f44 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/TypeAliasTypeCommonizer.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/TypeAliasTypeCommonizer.kt @@ -15,6 +15,7 @@ internal class TypeAliasTypeCommonizer(private val classifiers: CirKnownClassifi private lateinit var typeAliasId: CirEntityId private val arguments = TypeArgumentListCommonizer(classifiers) + private val underlyingTypeArguments = TypeArgumentListCommonizer(classifiers) private var isMarkedNullable = false private var commonizedTypeBuilder: CommonizedTypeAliasTypeBuilder? = null // null means not selected yet @@ -22,6 +23,7 @@ internal class TypeAliasTypeCommonizer(private val classifiers: CirKnownClassifi (commonizedTypeBuilder ?: failInEmptyState()).build( typeAliasId = typeAliasId, arguments = arguments.result, + underlyingTypeArguments = underlyingTypeArguments.result, isMarkedNullable = isMarkedNullable ) @@ -50,24 +52,34 @@ internal class TypeAliasTypeCommonizer(private val classifiers: CirKnownClassifi } } - return arguments.commonizeWith(next.arguments) + return arguments.commonizeWith(next.arguments) && + underlyingTypeArguments.commonizeWith(next.underlyingType.arguments) } // builds a new type for "common" library fragment for the given combination of type alias types in "platform" fragments internal interface CommonizedTypeAliasTypeBuilder { - fun build(typeAliasId: CirEntityId, arguments: List, isMarkedNullable: Boolean): CirClassOrTypeAliasType + fun build( + typeAliasId: CirEntityId, + arguments: List, + underlyingTypeArguments: List, + isMarkedNullable: Boolean + ): CirClassOrTypeAliasType companion object { // type alias has been commonized to expect class, need to build type for expect class fun forClass(commonClass: CirClass) = object : CommonizedTypeAliasTypeBuilder { - override fun build(typeAliasId: CirEntityId, arguments: List, isMarkedNullable: Boolean) = - CirClassType.createInterned( - classId = typeAliasId, - outerType = null, // there can't be outer type - visibility = commonClass.visibility, - arguments = arguments, - isMarkedNullable = isMarkedNullable - ) + override fun build( + typeAliasId: CirEntityId, + arguments: List, + underlyingTypeArguments: List, + isMarkedNullable: Boolean + ) = CirClassType.createInterned( + classId = typeAliasId, + outerType = null, // there can't be outer type + visibility = commonClass.visibility, + arguments = arguments, + isMarkedNullable = isMarkedNullable + ) } // type alias has been commonized to another type alias with the different underlying type, need to build type for @@ -79,12 +91,16 @@ internal class TypeAliasTypeCommonizer(private val classifiers: CirKnownClassifi override fun build( typeAliasId: CirEntityId, arguments: List, + underlyingTypeArguments: List, isMarkedNullable: Boolean ): CirTypeAliasType { - val underlyingTypeWithProperNullability = underlyingType.makeNullableIfNecessary(isMarkedNullable) + val underlyingTypeWithProperNullability = underlyingType + .makeNullableIfNecessary(isMarkedNullable) + .withArguments(underlyingTypeArguments) + return CirTypeAliasType.createInterned( typeAliasId = typeAliasId, - underlyingType = underlyingTypeWithProperNullability, // TODO replace arguments??? + underlyingType = underlyingTypeWithProperNullability, arguments = arguments, isMarkedNullable = isMarkedNullable ) diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/mergedtree/nodeBuilders.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/mergedtree/nodeBuilders.kt index e3cb3888b86..cdf5841897b 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/mergedtree/nodeBuilders.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/mergedtree/nodeBuilders.kt @@ -115,7 +115,7 @@ internal fun buildTypeAliasNode( storageManager = storageManager, size = size, nodeRelationship = null, - commonizerProducer = { TypeAliasCommonizer(classifiers) }, + commonizerProducer = { TypeAliasCommonizer(classifiers).asCommonizer() }, recursionMarker = CirTypeAliasRecursionMarker, nodeProducer = { targetDeclarations, commonDeclaration -> CirTypeAliasNode(typeAliasId, targetDeclarations, commonDeclaration).also { diff --git a/native/commonizer/testData/classifierCommonization/typeAliases/commonized/common/package_root.kt b/native/commonizer/testData/classifierCommonization/typeAliases/commonized/common/package_root.kt index 4fde1eac476..5675a4c4c9a 100644 --- a/native/commonizer/testData/classifierCommonization/typeAliases/commonized/common/package_root.kt +++ b/native/commonizer/testData/classifierCommonization/typeAliases/commonized/common/package_root.kt @@ -6,7 +6,9 @@ typealias C2 = C // TA lifted up as is typealias C3 = C2 // TA lifted up as is typealias D = A // class/TA expanded to the same class at the RHS -typealias E = B // different TAs use common type from TA-chain +typealias D2 = A // class/TA expanded to the same class at the RHS +typealias E = A // different TAs use common type from TA-chain +typealias E2 = A // different TAs use common type from TA-chain typealias F = List // parameterized type at the RHS typealias H = List // TA with own parameters diff --git a/native/commonizer/testData/classifierCommonization/typeAliases/original/linux/package_root.kt b/native/commonizer/testData/classifierCommonization/typeAliases/original/linux/package_root.kt index 508dfe745a7..951c55404ad 100644 --- a/native/commonizer/testData/classifierCommonization/typeAliases/original/linux/package_root.kt +++ b/native/commonizer/testData/classifierCommonization/typeAliases/original/linux/package_root.kt @@ -7,7 +7,9 @@ typealias C2 = C // TA lifted up as is typealias C3 = C2 // TA lifted up as is typealias D = B // class/TA expanded to the same class at the RHS +typealias D2 = A //class/TA expanded to the same class at RHS typealias E = C // different TAs use common type from TA-chain +typealias E2 = B typealias F = List // parameterized type at the RHS typealias G = List // different parameterized types at the RHS diff --git a/native/commonizer/testData/classifierCommonization/typeAliases/original/macos/package_root.kt b/native/commonizer/testData/classifierCommonization/typeAliases/original/macos/package_root.kt index 14d016a74e4..5a6dd353762 100644 --- a/native/commonizer/testData/classifierCommonization/typeAliases/original/macos/package_root.kt +++ b/native/commonizer/testData/classifierCommonization/typeAliases/original/macos/package_root.kt @@ -7,7 +7,9 @@ typealias C2 = C // TA lifted up as is typealias C3 = C2 // TA lifted up as is typealias D = A // class/TA expanded to the same class at the RHS +typealias D2 = B typealias E = B // different TAs use common type from TA-chain +typealias E2 = C typealias F = List // parameterized type at the RHS typealias G = List // different parameterized types at the RHS diff --git a/native/commonizer/tests/org/jetbrains/kotlin/commonizer/hierarchical/HierarchicalTypeAliasCommonizationTest.kt b/native/commonizer/tests/org/jetbrains/kotlin/commonizer/hierarchical/HierarchicalTypeAliasCommonizationTest.kt index 1e07c96fb62..ab1e6efb971 100644 --- a/native/commonizer/tests/org/jetbrains/kotlin/commonizer/hierarchical/HierarchicalTypeAliasCommonizationTest.kt +++ b/native/commonizer/tests/org/jetbrains/kotlin/commonizer/hierarchical/HierarchicalTypeAliasCommonizationTest.kt @@ -101,4 +101,65 @@ class HierarchicalTypeAliasCommonizationTest : AbstractInlineSourcesCommonizatio result.assertCommonized("(a, b, c, d)", """expect class x expect constructor()""") result.assertCommonized("(a, b, c, d, e, f)", """expect class x expect constructor()""") } + + + fun `test typealias chain`() { + val result = commonize { + outputTarget("(a, b)") + + simpleSingleSourceTarget( + "a", """ + typealias A = Map + typealias B = A + """.trimIndent() + ) + + simpleSingleSourceTarget( + "b", """ + typealias A = Map + typealias B = A + """.trimIndent() + ) + } + + result.assertCommonized( + "(a, b)", """ + typealias A = Map + typealias B = A + """.trimIndent() + ) + } + + fun `KT-47574 - test long typealias chain`() { + val result = commonize { + outputTarget("(a, b)") + + simpleSingleSourceTarget( + "a", """ + typealias A = Map + typealias B = A + typealias C = B + typealias D = C + """.trimIndent() + ) + + simpleSingleSourceTarget( + "b", """ + typealias A = Map + typealias B = A + typealias C = B + typealias D = C + """.trimIndent() + ) + } + + result.assertCommonized( + "(a, b)", """ + typealias A = Map + typealias B = A + typealias C = B + typealias D = C + """.trimIndent() + ) + } }