[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 = ">")
|
if (arguments.isNotEmpty()) arguments.joinTo(builder, prefix = "<", postfix = ">")
|
||||||
super.appendDescriptionTo(builder)
|
super.appendDescriptionTo(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract fun withArguments(arguments: List<CirTypeProjection>): CirClassOrTypeAliasType
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class CirClassType : CirClassOrTypeAliasType(), CirHasVisibility {
|
abstract class CirClassType : CirClassOrTypeAliasType(), CirHasVisibility {
|
||||||
@@ -98,6 +100,16 @@ abstract class CirClassType : CirClassOrTypeAliasType(), CirHasVisibility {
|
|||||||
super.appendDescriptionTo(builder, shortNameOnly = outerType != null)
|
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 {
|
companion object {
|
||||||
fun createInterned(
|
fun createInterned(
|
||||||
classId: CirEntityId,
|
classId: CirEntityId,
|
||||||
@@ -134,6 +146,15 @@ abstract class CirTypeAliasType : CirClassOrTypeAliasType() {
|
|||||||
underlyingType.appendDescriptionTo(builder)
|
underlyingType.appendDescriptionTo(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun withArguments(arguments: List<CirTypeProjection>): CirClassOrTypeAliasType {
|
||||||
|
return createInterned(
|
||||||
|
typeAliasId = classifierId,
|
||||||
|
underlyingType = underlyingType,
|
||||||
|
arguments = arguments,
|
||||||
|
isMarkedNullable = isMarkedNullable
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun createInterned(
|
fun createInterned(
|
||||||
typeAliasId: CirEntityId,
|
typeAliasId: CirEntityId,
|
||||||
|
|||||||
@@ -7,91 +7,29 @@ package org.jetbrains.kotlin.commonizer.core
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.commonizer.cir.*
|
import org.jetbrains.kotlin.commonizer.cir.*
|
||||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers
|
import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
|
||||||
|
|
||||||
/**
|
class TypeAliasCommonizer(
|
||||||
* 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(
|
|
||||||
private val classifiers: CirKnownClassifiers
|
private val classifiers: CirKnownClassifiers
|
||||||
) : AbstractStandardCommonizer<CirTypeAlias, CirTypeAlias>() {
|
) : AssociativeCommonizer<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()
|
|
||||||
|
|
||||||
override fun commonizationResult() = CirTypeAlias.create(
|
override fun commonize(first: CirTypeAlias, second: CirTypeAlias): CirTypeAlias? {
|
||||||
annotations = emptyList(),
|
val name = if (first.name == second.name) first.name else return null
|
||||||
name = name,
|
|
||||||
typeParameters = typeParameters.result,
|
|
||||||
visibility = visibility.result,
|
|
||||||
underlyingType = underlyingType!!,
|
|
||||||
expandedType = expandedType.result as CirClassType
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun initialize(first: CirTypeAlias) {
|
val typeParameters = TypeParameterListCommonizer(classifiers)
|
||||||
name = first.name
|
.commonize(listOf(first.typeParameters, second.typeParameters)) ?: return null
|
||||||
}
|
|
||||||
|
|
||||||
override fun doCommonizeWith(next: CirTypeAlias): Boolean {
|
val underlyingType = TypeCommonizer(classifiers)
|
||||||
if (underlyingType == null) {
|
.commonize(first.underlyingType, second.underlyingType) as? CirClassOrTypeAliasType ?: return null
|
||||||
underlyingType = computeSuitableUnderlyingType(classifiers, next.underlyingType) ?: return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return typeParameters.commonizeWith(next.typeParameters)
|
val visibility = VisibilityCommonizer.lowering().commonize(listOf(first, second)) ?: return null
|
||||||
&& 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
|
|
||||||
|
|
||||||
return CirTypeAlias.create(
|
return CirTypeAlias.create(
|
||||||
annotations = emptyList(),
|
annotations = emptyList(),
|
||||||
name = name,
|
name = name,
|
||||||
typeParameters = typeParameters.result,
|
typeParameters = typeParameters,
|
||||||
visibility = visibility.result,
|
visibility = visibility,
|
||||||
underlyingType = underlyingType,
|
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 lateinit var typeAliasId: CirEntityId
|
||||||
private val arguments = TypeArgumentListCommonizer(classifiers)
|
private val arguments = TypeArgumentListCommonizer(classifiers)
|
||||||
|
private val underlyingTypeArguments = TypeArgumentListCommonizer(classifiers)
|
||||||
private var isMarkedNullable = false
|
private var isMarkedNullable = false
|
||||||
private var commonizedTypeBuilder: CommonizedTypeAliasTypeBuilder? = null // null means not selected yet
|
private var commonizedTypeBuilder: CommonizedTypeAliasTypeBuilder? = null // null means not selected yet
|
||||||
|
|
||||||
@@ -22,6 +23,7 @@ internal class TypeAliasTypeCommonizer(private val classifiers: CirKnownClassifi
|
|||||||
(commonizedTypeBuilder ?: failInEmptyState()).build(
|
(commonizedTypeBuilder ?: failInEmptyState()).build(
|
||||||
typeAliasId = typeAliasId,
|
typeAliasId = typeAliasId,
|
||||||
arguments = arguments.result,
|
arguments = arguments.result,
|
||||||
|
underlyingTypeArguments = underlyingTypeArguments.result,
|
||||||
isMarkedNullable = isMarkedNullable
|
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
|
// builds a new type for "common" library fragment for the given combination of type alias types in "platform" fragments
|
||||||
internal interface CommonizedTypeAliasTypeBuilder {
|
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 {
|
companion object {
|
||||||
// type alias has been commonized to expect class, need to build type for expect class
|
// type alias has been commonized to expect class, need to build type for expect class
|
||||||
fun forClass(commonClass: CirClass) = object : CommonizedTypeAliasTypeBuilder {
|
fun forClass(commonClass: CirClass) = object : CommonizedTypeAliasTypeBuilder {
|
||||||
override fun build(typeAliasId: CirEntityId, arguments: List<CirTypeProjection>, isMarkedNullable: Boolean) =
|
override fun build(
|
||||||
CirClassType.createInterned(
|
typeAliasId: CirEntityId,
|
||||||
classId = typeAliasId,
|
arguments: List<CirTypeProjection>,
|
||||||
outerType = null, // there can't be outer type
|
underlyingTypeArguments: List<CirTypeProjection>,
|
||||||
visibility = commonClass.visibility,
|
isMarkedNullable: Boolean
|
||||||
arguments = arguments,
|
) = CirClassType.createInterned(
|
||||||
isMarkedNullable = isMarkedNullable
|
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
|
// 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(
|
override fun build(
|
||||||
typeAliasId: CirEntityId,
|
typeAliasId: CirEntityId,
|
||||||
arguments: List<CirTypeProjection>,
|
arguments: List<CirTypeProjection>,
|
||||||
|
underlyingTypeArguments: List<CirTypeProjection>,
|
||||||
isMarkedNullable: Boolean
|
isMarkedNullable: Boolean
|
||||||
): CirTypeAliasType {
|
): CirTypeAliasType {
|
||||||
val underlyingTypeWithProperNullability = underlyingType.makeNullableIfNecessary(isMarkedNullable)
|
val underlyingTypeWithProperNullability = underlyingType
|
||||||
|
.makeNullableIfNecessary(isMarkedNullable)
|
||||||
|
.withArguments(underlyingTypeArguments)
|
||||||
|
|
||||||
return CirTypeAliasType.createInterned(
|
return CirTypeAliasType.createInterned(
|
||||||
typeAliasId = typeAliasId,
|
typeAliasId = typeAliasId,
|
||||||
underlyingType = underlyingTypeWithProperNullability, // TODO replace arguments???
|
underlyingType = underlyingTypeWithProperNullability,
|
||||||
arguments = arguments,
|
arguments = arguments,
|
||||||
isMarkedNullable = isMarkedNullable
|
isMarkedNullable = isMarkedNullable
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ internal fun buildTypeAliasNode(
|
|||||||
storageManager = storageManager,
|
storageManager = storageManager,
|
||||||
size = size,
|
size = size,
|
||||||
nodeRelationship = null,
|
nodeRelationship = null,
|
||||||
commonizerProducer = { TypeAliasCommonizer(classifiers) },
|
commonizerProducer = { TypeAliasCommonizer(classifiers).asCommonizer() },
|
||||||
recursionMarker = CirTypeAliasRecursionMarker,
|
recursionMarker = CirTypeAliasRecursionMarker,
|
||||||
nodeProducer = { targetDeclarations, commonDeclaration ->
|
nodeProducer = { targetDeclarations, commonDeclaration ->
|
||||||
CirTypeAliasNode(typeAliasId, targetDeclarations, commonDeclaration).also {
|
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 C3 = C2 // TA lifted up as is
|
||||||
|
|
||||||
typealias D = A // class/TA expanded to the same class at the RHS
|
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 F = List<String> // parameterized type at the RHS
|
||||||
typealias H<T> = List<T> // TA with own parameters
|
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 C3 = C2 // TA lifted up as is
|
||||||
|
|
||||||
typealias D = B // class/TA expanded to the same class at the RHS
|
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 E = C // different TAs use common type from TA-chain
|
||||||
|
typealias E2 = B
|
||||||
|
|
||||||
typealias F = List<String> // parameterized type at the RHS
|
typealias F = List<String> // parameterized type at the RHS
|
||||||
typealias G = List<Int> // different parameterized types 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 C3 = C2 // TA lifted up as is
|
||||||
|
|
||||||
typealias D = A // class/TA expanded to the same class at the RHS
|
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 E = B // different TAs use common type from TA-chain
|
||||||
|
typealias E2 = C
|
||||||
|
|
||||||
typealias F = List<String> // parameterized type at the RHS
|
typealias F = List<String> // parameterized type at the RHS
|
||||||
typealias G = List<String> // different parameterized types 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)", """expect class x expect constructor()""")
|
||||||
result.assertCommonized("(a, b, c, d, e, f)", """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