[Commonizer] Restore TypeAliasCommonizer's Commutative property & TypeAliasTypeCommonizer: substitute underlying-type arguments
^KT-47574 The fix done here supports only one level of substituting underlying type-arguments. HierarchicalTypeAliasCommonizationTest.`KT-47574 - test long typealias chain` will assert proper behaviour for nested chains.
This commit is contained in:
committed by
Space
parent
448302d19b
commit
5b5dddc2d1
@@ -84,6 +84,8 @@ sealed class CirClassOrTypeAliasType : CirSimpleType() {
|
||||
if (arguments.isNotEmpty()) arguments.joinTo(builder, prefix = "<", postfix = ">")
|
||||
super.appendDescriptionTo(builder)
|
||||
}
|
||||
|
||||
abstract fun withArguments(arguments: List<CirTypeProjection>): 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<CirTypeProjection>): 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<CirTypeProjection>): CirClassOrTypeAliasType {
|
||||
return createInterned(
|
||||
typeAliasId = classifierId,
|
||||
underlyingType = underlyingType,
|
||||
arguments = arguments,
|
||||
isMarkedNullable = isMarkedNullable
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun createInterned(
|
||||
typeAliasId: CirEntityId,
|
||||
|
||||
@@ -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<CirTypeAlias, CirTypeAlias>() {
|
||||
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<CirTypeAlias, CirTypeAlias>() {
|
||||
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<CirTypeAlias> {
|
||||
|
||||
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<CirTypeAlias, CirTypeAlias>() {
|
||||
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)
|
||||
}
|
||||
}
|
||||
+28
-12
@@ -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<CirTypeProjection>, isMarkedNullable: Boolean): CirClassOrTypeAliasType
|
||||
fun build(
|
||||
typeAliasId: CirEntityId,
|
||||
arguments: List<CirTypeProjection>,
|
||||
underlyingTypeArguments: List<CirTypeProjection>,
|
||||
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<CirTypeProjection>, 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<CirTypeProjection>,
|
||||
underlyingTypeArguments: List<CirTypeProjection>,
|
||||
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<CirTypeProjection>,
|
||||
underlyingTypeArguments: List<CirTypeProjection>,
|
||||
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
|
||||
)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Vendored
+3
-1
@@ -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<String> // parameterized type at the RHS
|
||||
typealias H<T> = List<T> // TA with own parameters
|
||||
|
||||
Vendored
+2
@@ -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<String> // parameterized type at the RHS
|
||||
typealias G = List<Int> // different parameterized types at the RHS
|
||||
|
||||
Vendored
+2
@@ -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<String> // parameterized type at the RHS
|
||||
typealias G = List<String> // different parameterized types at the RHS
|
||||
|
||||
+61
@@ -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<N, M> = Map<N, M>
|
||||
typealias B = A<String, Int>
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
simpleSingleSourceTarget(
|
||||
"b", """
|
||||
typealias A<N, M> = Map<N, M>
|
||||
typealias B = A<String, Int>
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
result.assertCommonized(
|
||||
"(a, b)", """
|
||||
typealias A<N, M> = Map<N, M>
|
||||
typealias B = A<String, Int>
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
fun `KT-47574 - test long typealias chain`() {
|
||||
val result = commonize {
|
||||
outputTarget("(a, b)")
|
||||
|
||||
simpleSingleSourceTarget(
|
||||
"a", """
|
||||
typealias A<N, M> = Map<N, M>
|
||||
typealias B<N, M> = A<N, M>
|
||||
typealias C<N> = B<N, Int>
|
||||
typealias D = C<String>
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
simpleSingleSourceTarget(
|
||||
"b", """
|
||||
typealias A<N, M> = Map<N, M>
|
||||
typealias B<N, M> = A<N, M>
|
||||
typealias C<N> = B<N, Int>
|
||||
typealias D = C<String>
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
result.assertCommonized(
|
||||
"(a, b)", """
|
||||
typealias A<N, M> = Map<N, M>
|
||||
typealias B<N, M> = A<N, M>
|
||||
typealias C<N> = B<N, Int>
|
||||
typealias D = C<String>
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user