[Commonizer] Split type substitution into forward and backwards
^KT-48288
This commit is contained in:
committed by
Space
parent
698b3fce9e
commit
bfa433fa06
@@ -85,3 +85,32 @@ internal tailrec fun computeExpandedType(underlyingType: CirClassOrTypeAliasType
|
|||||||
|
|
||||||
@Suppress("unused", "NOTHING_TO_INLINE")
|
@Suppress("unused", "NOTHING_TO_INLINE")
|
||||||
internal inline fun CirDeclaration.unsupported(): Nothing = error("This method should never be called on ${this::class.java}, $this")
|
internal inline fun CirDeclaration.unsupported(): Nothing = error("This method should never be called on ${this::class.java}, $this")
|
||||||
|
|
||||||
|
internal fun CirClassOrTypeAliasType.withParentArguments(
|
||||||
|
parentArguments: List<CirTypeProjection>, parentIsMarkedNullable: Boolean
|
||||||
|
): CirClassOrTypeAliasType {
|
||||||
|
val newIsMarkedNullable = isMarkedNullable || parentIsMarkedNullable
|
||||||
|
|
||||||
|
val newArguments = arguments.map { oldArgument ->
|
||||||
|
if (oldArgument is CirRegularTypeProjection) {
|
||||||
|
val oldArgumentType = oldArgument.type
|
||||||
|
if (oldArgumentType is CirTypeParameterType) {
|
||||||
|
return@map parentArguments[oldArgumentType.index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oldArgument
|
||||||
|
}
|
||||||
|
|
||||||
|
return when (val newUnderlyingType = makeNullableIfNecessary(newIsMarkedNullable).withArguments(newArguments)) {
|
||||||
|
this -> this
|
||||||
|
is CirClassType -> newUnderlyingType
|
||||||
|
is CirTypeAliasType -> newUnderlyingType.withUnderlyingType(
|
||||||
|
newUnderlyingType.underlyingType.withParentArguments(newArguments, newIsMarkedNullable)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal tailrec fun CirClassOrTypeAliasType.expandedType(): CirClassType = when (this) {
|
||||||
|
is CirClassType -> this
|
||||||
|
is CirTypeAliasType -> this.underlyingType.expandedType()
|
||||||
|
}
|
||||||
|
|||||||
+39
-32
@@ -92,44 +92,51 @@ internal class ClassOrTypeAliasTypeCommonizer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("KotlinConstantConditions") // Improved readability
|
||||||
private fun selectClassifierId(types: List<CirClassOrTypeAliasType>): CirEntityId? {
|
private fun selectClassifierId(types: List<CirClassOrTypeAliasType>): CirEntityId? {
|
||||||
types.singleDistinctValueOrNull { it.classifierId }?.let { return it }
|
types.singleDistinctValueOrNull { it.classifierId }?.let { return it }
|
||||||
|
|
||||||
if (typeCommonizer.options.enableTypeAliasSubstitution) {
|
val forwardSubstitutionAllowed = typeCommonizer.options.enableForwardTypeAliasSubstitution
|
||||||
val commonId = types.singleDistinctValueOrNull {
|
val backwardsSubstitutionAllowed = typeCommonizer.options.enableBackwardsTypeAliasSubstitution
|
||||||
classifiers.commonClassifierIdResolver.findCommonId(it.classifierId)
|
|
||||||
} ?: return null
|
|
||||||
|
|
||||||
return commonId.aliases.maxByOrNull { candidate -> types.count { it.classifierId == candidate } }!!
|
/* No substitution allowed in any direction */
|
||||||
} else return null
|
if (!forwardSubstitutionAllowed && !backwardsSubstitutionAllowed) {
|
||||||
}
|
return null
|
||||||
}
|
|
||||||
|
|
||||||
private fun CirClassOrTypeAliasType.withParentArguments(
|
|
||||||
parentArguments: List<CirTypeProjection>, parentIsMarkedNullable: Boolean
|
|
||||||
): CirClassOrTypeAliasType {
|
|
||||||
val newIsMarkedNullable = isMarkedNullable || parentIsMarkedNullable
|
|
||||||
|
|
||||||
val newArguments = arguments.map { oldArgument ->
|
|
||||||
if (oldArgument is CirRegularTypeProjection) {
|
|
||||||
val oldArgumentType = oldArgument.type
|
|
||||||
if (oldArgumentType is CirTypeParameterType) {
|
|
||||||
return@map parentArguments[oldArgumentType.index]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
oldArgument
|
|
||||||
|
val commonId = types.singleDistinctValueOrNull {
|
||||||
|
classifiers.commonClassifierIdResolver.findCommonId(it.classifierId)
|
||||||
|
} ?: return null
|
||||||
|
|
||||||
|
val candidates = when {
|
||||||
|
forwardSubstitutionAllowed && backwardsSubstitutionAllowed -> commonId.aliases
|
||||||
|
|
||||||
|
/* Only forward substitutions allowed -> Only substitute with any underlying type */
|
||||||
|
forwardSubstitutionAllowed -> commonId.aliases.filter { candidate ->
|
||||||
|
types.all { type -> type.isAnyUnderlyingClassifier(candidate) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only backward substitutions allowed -> Only substitute with any typealias pointing to this types */
|
||||||
|
backwardsSubstitutionAllowed -> commonId.aliases.filter { candidate ->
|
||||||
|
types.none { type -> type.isAnyUnderlyingClassifier(candidate) }
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> error("Failed to select classifierId: Unexpected when branch")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidates.isEmpty()) return null
|
||||||
|
|
||||||
|
return candidates.maxByOrNull { candidate -> types.count { it.classifierId == candidate } }!!
|
||||||
}
|
}
|
||||||
|
|
||||||
return when (val newUnderlyingType = makeNullableIfNecessary(newIsMarkedNullable).withArguments(newArguments)) {
|
private fun CirClassOrTypeAliasType.isAnyUnderlyingClassifier(classifierId: CirEntityId): Boolean {
|
||||||
this -> this
|
return when (this) {
|
||||||
is CirClassType -> newUnderlyingType
|
is CirClassType -> false
|
||||||
is CirTypeAliasType -> newUnderlyingType.withUnderlyingType(
|
is CirTypeAliasType -> this.isAnyUnderlyingClassifier(classifierId)
|
||||||
newUnderlyingType.underlyingType.withParentArguments(newArguments, newIsMarkedNullable)
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
|
private fun CirTypeAliasType.isAnyUnderlyingClassifier(classifierId: CirEntityId): Boolean {
|
||||||
|
return underlyingType.classifierId == classifierId || underlyingType.isAnyUnderlyingClassifier(classifierId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal tailrec fun CirClassOrTypeAliasType.expandedType(): CirClassType = when (this) {
|
|
||||||
is CirClassType -> this
|
|
||||||
is CirTypeAliasType -> this.underlyingType.expandedType()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class TypeAliasCommonizer(
|
|||||||
) : NullableSingleInvocationCommonizer<CirTypeAlias> {
|
) : NullableSingleInvocationCommonizer<CirTypeAlias> {
|
||||||
|
|
||||||
private val typeCommonizer = typeCommonizer.withOptions {
|
private val typeCommonizer = typeCommonizer.withOptions {
|
||||||
withTypeAliasSubstitutionEnabled(false).withOptimisticNumberTypeCommonizationEnabled(true)
|
withBackwardsTypeAliasSubstitutionEnabled(false).withOptimisticNumberTypeCommonizationEnabled(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invoke(values: List<CirTypeAlias>): CirTypeAlias? {
|
override fun invoke(values: List<CirTypeAlias>): CirTypeAlias? {
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ class TypeCommonizer(
|
|||||||
data class Options(
|
data class Options(
|
||||||
val enableOptimisticNumberTypeCommonization: Boolean = false,
|
val enableOptimisticNumberTypeCommonization: Boolean = false,
|
||||||
val enableCovariantNullabilityCommonization: Boolean = false,
|
val enableCovariantNullabilityCommonization: Boolean = false,
|
||||||
val enableTypeAliasSubstitution: Boolean = true
|
val enableForwardTypeAliasSubstitution: Boolean = true,
|
||||||
|
val enableBackwardsTypeAliasSubstitution: Boolean = true,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun withOptimisticNumberTypeCommonizationEnabled(enabled: Boolean = true): Options {
|
fun withOptimisticNumberTypeCommonizationEnabled(enabled: Boolean = true): Options {
|
||||||
@@ -49,9 +50,18 @@ class TypeCommonizer(
|
|||||||
else copy(enableCovariantNullabilityCommonization = enabled)
|
else copy(enableCovariantNullabilityCommonization = enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun withForwardTypeAliasSubstitutionEnabled(enabled: Boolean = true): Options {
|
||||||
|
return if (enableForwardTypeAliasSubstitution == enabled) this
|
||||||
|
else copy(enableForwardTypeAliasSubstitution = enabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun withBackwardsTypeAliasSubstitutionEnabled(enabled: Boolean = true): Options {
|
||||||
|
return if (enableBackwardsTypeAliasSubstitution == enabled) this
|
||||||
|
else copy(enableBackwardsTypeAliasSubstitution = enabled)
|
||||||
|
}
|
||||||
|
|
||||||
fun withTypeAliasSubstitutionEnabled(enabled: Boolean = true): Options {
|
fun withTypeAliasSubstitutionEnabled(enabled: Boolean = true): Options {
|
||||||
return if (enableTypeAliasSubstitution == enabled) this
|
return withForwardTypeAliasSubstitutionEnabled(enabled).withBackwardsTypeAliasSubstitutionEnabled(enabled)
|
||||||
else copy(enableTypeAliasSubstitution = enabled)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
+1
-5
@@ -6,11 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.commonizer.transformer
|
package org.jetbrains.kotlin.commonizer.transformer
|
||||||
|
|
||||||
import org.jetbrains.kotlin.commonizer.TargetDependent
|
import org.jetbrains.kotlin.commonizer.TargetDependent
|
||||||
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
|
import org.jetbrains.kotlin.commonizer.cir.*
|
||||||
import org.jetbrains.kotlin.commonizer.cir.CirName
|
|
||||||
import org.jetbrains.kotlin.commonizer.cir.CirType
|
|
||||||
import org.jetbrains.kotlin.commonizer.cir.CirTypeAliasType
|
|
||||||
import org.jetbrains.kotlin.commonizer.core.expandedType
|
|
||||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirClassifierIndex
|
import org.jetbrains.kotlin.commonizer.mergedtree.CirClassifierIndex
|
||||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirTypeSubstitutor
|
import org.jetbrains.kotlin.commonizer.mergedtree.CirTypeSubstitutor
|
||||||
import org.jetbrains.kotlin.commonizer.mergedtree.findTypeAlias
|
import org.jetbrains.kotlin.commonizer.mergedtree.findTypeAlias
|
||||||
|
|||||||
+1
-1
@@ -618,7 +618,7 @@ class HierarchicalOptimisticNumbersTypeCommonizerTest : AbstractInlineSourcesCom
|
|||||||
@UnsafeNumber(["a: kotlin.Int", "b: kotlin.Long"])
|
@UnsafeNumber(["a: kotlin.Int", "b: kotlin.Long"])
|
||||||
typealias B = A
|
typealias B = A
|
||||||
@UnsafeNumber(["a: kotlin.Int", "b: kotlin.Long"])
|
@UnsafeNumber(["a: kotlin.Int", "b: kotlin.Long"])
|
||||||
typealias X = Int
|
typealias X = A
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user