[Commonizer] Short-circuiting of type aliases
^KT-41220
This commit is contained in:
+6
-2
@@ -70,10 +70,14 @@ private fun CirTypeAlias.buildDescriptor(
|
||||
typeAliasDescriptor
|
||||
)
|
||||
|
||||
val lazyUnderlyingType = storageManager.createLazyValue {
|
||||
underlyingType.buildType(targetComponents, typeParameterResolver)
|
||||
}
|
||||
|
||||
typeAliasDescriptor.initialize(
|
||||
declaredTypeParameters = declaredTypeParameters,
|
||||
underlyingType = storageManager.createLazyValue { underlyingType.buildType(targetComponents, typeParameterResolver) },
|
||||
expandedType = storageManager.createLazyValue { expandedType.buildType(targetComponents, typeParameterResolver) }
|
||||
underlyingType = lazyUnderlyingType,
|
||||
expandedType = lazyUnderlyingType
|
||||
)
|
||||
|
||||
// cache created type alias descriptor:
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ object CirTypeAliasFactory {
|
||||
typeParameters = source.declaredTypeParameters.map(CirTypeParameterFactory::create),
|
||||
visibility = source.visibility,
|
||||
underlyingType = CirTypeFactory.create(source.underlyingType),
|
||||
expandedType = CirTypeFactory.create(source.expandedType)
|
||||
expandedType = CirTypeFactory.create(source.expandedType, useAbbreviation = false)
|
||||
)
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
+6
-5
@@ -25,21 +25,22 @@ object CirTypeFactory {
|
||||
}
|
||||
}
|
||||
|
||||
fun create(source: SimpleType): CirSimpleType {
|
||||
val abbreviation: SimpleType = (source as? AbbreviatedType)?.abbreviation ?: source
|
||||
val classifierDescriptor: ClassifierDescriptor = abbreviation.declarationDescriptor
|
||||
fun create(source: SimpleType, useAbbreviation: Boolean = true): CirSimpleType {
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val source = if (useAbbreviation && source is AbbreviatedType) source.abbreviation else source
|
||||
val classifierDescriptor: ClassifierDescriptor = source.declarationDescriptor
|
||||
|
||||
return create(
|
||||
classifierId = CirClassifierIdFactory.create(classifierDescriptor),
|
||||
visibility = (classifierDescriptor as? ClassifierDescriptorWithTypeParameters)?.visibility ?: Visibilities.UNKNOWN,
|
||||
arguments = abbreviation.arguments.map { projection ->
|
||||
arguments = source.arguments.map { projection ->
|
||||
CirTypeProjection(
|
||||
projectionKind = projection.projectionKind,
|
||||
isStarProjection = projection.isStarProjection,
|
||||
type = create(projection.type)
|
||||
)
|
||||
},
|
||||
isMarkedNullable = abbreviation.isMarkedNullable
|
||||
isMarkedNullable = source.isMarkedNullable
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ data class CirTypeAliasImpl(
|
||||
override val typeParameters: List<CirTypeParameter>,
|
||||
override val visibility: Visibility,
|
||||
override val underlyingType: CirSimpleType,
|
||||
override val expandedType: CirSimpleType
|
||||
override val expandedType: CirSimpleType // only for commonization algorithm; does not participate in building resulting declarations
|
||||
) : CirTypeAlias {
|
||||
// any TA in "common" fragment is already lifted up
|
||||
override val isLiftedUp get() = true
|
||||
|
||||
+44
-7
@@ -14,30 +14,67 @@ import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirClassifiersCach
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
/**
|
||||
* Main (optimistic) branch:
|
||||
* 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.
|
||||
*
|
||||
* Secondary (backup) branch:
|
||||
* Tertiary (backup) branch:
|
||||
* - Produce an "expect class" for "common" fragment and the corresponding "actual typealias" declarations for each platform fragment.
|
||||
*/
|
||||
class TypeAliasCommonizer(cache: CirClassifiersCache) : AbstractStandardCommonizer<CirTypeAlias, CirClassifier>() {
|
||||
private val main = TypeAliasLiftingUpCommonizer(cache)
|
||||
private val secondary = TypeAliasExpectClassCommonizer()
|
||||
private val primary = TypeAliasShortCircuitingCommonizer(cache)
|
||||
private val secondary = TypeAliasLiftingUpCommonizer(cache)
|
||||
private val tertiary = TypeAliasExpectClassCommonizer()
|
||||
|
||||
override fun commonizationResult(): CirClassifier = main.resultOrNull ?: secondary.result
|
||||
override fun commonizationResult(): CirClassifier = primary.resultOrNull ?: secondary.resultOrNull ?: tertiary.result
|
||||
|
||||
override fun initialize(first: CirTypeAlias) = Unit
|
||||
|
||||
@Suppress("ReplaceNegatedIsEmptyWithIsNotEmpty")
|
||||
override fun doCommonizeWith(next: CirTypeAlias): Boolean {
|
||||
val mainResult = main.commonizeWith(next)
|
||||
val primaryResult = primary.commonizeWith(next)
|
||||
val secondaryResult = secondary.commonizeWith(next)
|
||||
val tertiaryResult = tertiary.commonizeWith(next)
|
||||
|
||||
// Note: don't call commonizeWith() functions in return statement to avoid short-circuiting!
|
||||
return mainResult || secondaryResult
|
||||
return primaryResult || secondaryResult || tertiaryResult
|
||||
}
|
||||
}
|
||||
|
||||
private class TypeAliasShortCircuitingCommonizer(cache: CirClassifiersCache) : AbstractStandardCommonizer<CirTypeAlias, CirTypeAlias>() {
|
||||
private lateinit var name: Name
|
||||
private val expandedType = TypeCommonizer(cache)
|
||||
private val visibility = VisibilityCommonizer.lowering()
|
||||
|
||||
override fun commonizationResult(): CirTypeAlias {
|
||||
val expandedType = expandedType.result as CirSimpleType
|
||||
|
||||
return CirTypeAliasFactory.create(
|
||||
annotations = emptyList(),
|
||||
name = name,
|
||||
typeParameters = emptyList(),
|
||||
visibility = visibility.result,
|
||||
underlyingType = expandedType, // pass expanded type as underlying type
|
||||
expandedType = expandedType
|
||||
)
|
||||
}
|
||||
|
||||
val resultOrNull: CirTypeAlias?
|
||||
get() = if (hasResult) commonizationResult() else null
|
||||
|
||||
override fun initialize(first: CirTypeAlias) {
|
||||
name = first.name
|
||||
}
|
||||
|
||||
override fun doCommonizeWith(next: CirTypeAlias) =
|
||||
next.typeParameters.isEmpty() // short-circuiting of TAs with type parameters is too complex case, consider implementing it later
|
||||
&& next.expandedType.arguments.isEmpty() // short-circuiting of TAs with type arguments in expanded type is too complex case
|
||||
&& expandedType.commonizeWith(next.expandedType)
|
||||
&& visibility.commonizeWith(next)
|
||||
}
|
||||
|
||||
private class TypeAliasLiftingUpCommonizer(cache: CirClassifiersCache) : AbstractStandardCommonizer<CirTypeAlias, CirTypeAlias>() {
|
||||
private lateinit var name: Name
|
||||
private val typeParameters = TypeParameterListCommonizer(cache)
|
||||
|
||||
Vendored
+7
-2
@@ -2,7 +2,12 @@ expect class A()
|
||||
|
||||
// Lifted up type aliases:
|
||||
typealias B = A // class at the RHS
|
||||
typealias C = B // TA at the RHS
|
||||
typealias C = A // TA at the RHS, expanded to the same class
|
||||
typealias C2 = A // 2x TA at the RHS, expanded to the same class
|
||||
typealias C3 = A // 3x TA at the RHS, expanded to the same class
|
||||
|
||||
typealias D = A // class/TA expanded to the same class at the RHS
|
||||
typealias E = A // different TAs expanded to the same class at the RHS
|
||||
|
||||
typealias F = List<String> // parameterized type at the RHS
|
||||
typealias H<T> = List<T> // TA with own parameters
|
||||
@@ -21,5 +26,5 @@ expect class T
|
||||
// Nullability:
|
||||
typealias U = A // same nullability of the RHS class
|
||||
expect class V // different nullability of the RHS class
|
||||
typealias W = U // same nullability of the RHS TA
|
||||
typealias W = A // same nullability of the RHS TA
|
||||
typealias Y = V // TA at the RHS with the different nullability of own RHS
|
||||
|
||||
Vendored
-3
@@ -1,9 +1,6 @@
|
||||
actual class A actual constructor()
|
||||
|
||||
// Lifted up type aliases:
|
||||
typealias D = B // class/TA at the RHS
|
||||
typealias E = C // different TAs at the RHS
|
||||
|
||||
typealias G = List<Int> // different parameterized types at the RHS
|
||||
|
||||
typealias I<T> = List<T> // TAs with own parameters with different names
|
||||
|
||||
Vendored
-3
@@ -1,9 +1,6 @@
|
||||
actual class A actual constructor()
|
||||
|
||||
// Lifted up type aliases:
|
||||
typealias D = A // class/TA at the RHS
|
||||
typealias E = B // different TAs at the RHS
|
||||
|
||||
typealias G = List<String> // different parameterized types at the RHS
|
||||
|
||||
typealias I<R> = List<R> // TAs with own parameters with different names
|
||||
|
||||
+5
-3
@@ -2,10 +2,12 @@ class A
|
||||
|
||||
// Lifted up type aliases:
|
||||
typealias B = A // class at the RHS
|
||||
typealias C = B // TA at the RHS
|
||||
typealias C = B // TA at the RHS, expanded to the same class
|
||||
typealias C2 = C // 2x TA at the RHS, expanded to the same class
|
||||
typealias C3 = C2 // 3x TA at the RHS, expanded to the same class
|
||||
|
||||
typealias D = B // class/TA at the RHS
|
||||
typealias E = C // different TAs at the RHS
|
||||
typealias D = B // class/TA expanded to the same class at the RHS
|
||||
typealias E = C // different TAs expanded to the same class at the RHS
|
||||
|
||||
typealias F = List<String> // parameterized type at the RHS
|
||||
typealias G = List<Int> // different parameterized types at the RHS
|
||||
|
||||
Vendored
+5
-3
@@ -2,10 +2,12 @@ class A
|
||||
|
||||
// Lifted up type aliases:
|
||||
typealias B = A // class at the RHS
|
||||
typealias C = B // TA at the RHS
|
||||
typealias C = B // TA at the RHS, expanded to the same class
|
||||
typealias C2 = C // 2x TA at the RHS, expanded to the same class
|
||||
typealias C3 = C2 // 3x TA at the RHS, expanded to the same class
|
||||
|
||||
typealias D = A // class/TA at the RHS
|
||||
typealias E = B // different TAs at the RHS
|
||||
typealias D = A // class/TA expanded to the same class at the RHS
|
||||
typealias E = B // different TAs expanded to the same class at the RHS
|
||||
|
||||
typealias F = List<String> // parameterized type at the RHS
|
||||
typealias G = List<String> // different parameterized types at the RHS
|
||||
|
||||
+16
-10
@@ -279,8 +279,13 @@ class TypeCommonizerTest : AbstractCommonizerTest<CirType, CirType>() {
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Bar") }
|
||||
)
|
||||
|
||||
@Test(expected = IllegalCommonizerStateException::class)
|
||||
fun multilevelTATypesInUserPackageWithSameNameAndRightHandSideClass1() = doTestFailure(
|
||||
@Test
|
||||
// why success: short-circuiting & lifting up
|
||||
fun multilevelTATypesInUserPackageWithSameNameAndRightHandSideClass1() = doTestSuccess(
|
||||
expected = mockTAType("org.sample.FooAlias") {
|
||||
mockClassType("org.sample.Foo")
|
||||
},
|
||||
|
||||
mockTAType("org.sample.FooAlias") {
|
||||
mockClassType("org.sample.Foo")
|
||||
},
|
||||
@@ -289,13 +294,16 @@ class TypeCommonizerTest : AbstractCommonizerTest<CirType, CirType>() {
|
||||
mockTAType("org.sample.FooAliasL2") {
|
||||
mockClassType("org.sample.Foo")
|
||||
}
|
||||
},
|
||||
|
||||
shouldFailOnFirstVariant = true
|
||||
}
|
||||
)
|
||||
|
||||
@Test(expected = IllegalCommonizerStateException::class)
|
||||
fun multilevelTATypesInUserPackageWithSameNameAndRightHandSideClass2() = doTestFailure(
|
||||
@Test
|
||||
// why success: short-circuiting & lifting up
|
||||
fun multilevelTATypesInUserPackageWithSameNameAndRightHandSideClass2() = doTestSuccess(
|
||||
expected = mockTAType("org.sample.FooAlias") {
|
||||
mockClassType("org.sample.Foo")
|
||||
},
|
||||
|
||||
mockTAType("org.sample.FooAlias") {
|
||||
mockTAType("org.sample.FooAliasL2") {
|
||||
mockClassType("org.sample.Foo")
|
||||
@@ -304,9 +312,7 @@ class TypeCommonizerTest : AbstractCommonizerTest<CirType, CirType>() {
|
||||
|
||||
mockTAType("org.sample.FooAlias") {
|
||||
mockClassType("org.sample.Foo")
|
||||
},
|
||||
|
||||
shouldFailOnFirstVariant = true
|
||||
}
|
||||
)
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user