[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")
|
||||
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? {
|
||||
types.singleDistinctValueOrNull { it.classifierId }?.let { return it }
|
||||
|
||||
if (typeCommonizer.options.enableTypeAliasSubstitution) {
|
||||
val commonId = types.singleDistinctValueOrNull {
|
||||
classifiers.commonClassifierIdResolver.findCommonId(it.classifierId)
|
||||
} ?: return null
|
||||
val forwardSubstitutionAllowed = typeCommonizer.options.enableForwardTypeAliasSubstitution
|
||||
val backwardsSubstitutionAllowed = typeCommonizer.options.enableBackwardsTypeAliasSubstitution
|
||||
|
||||
return commonId.aliases.maxByOrNull { candidate -> types.count { it.classifierId == candidate } }!!
|
||||
} else 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]
|
||||
}
|
||||
/* No substitution allowed in any direction */
|
||||
if (!forwardSubstitutionAllowed && !backwardsSubstitutionAllowed) {
|
||||
return null
|
||||
}
|
||||
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)) {
|
||||
this -> this
|
||||
is CirClassType -> newUnderlyingType
|
||||
is CirTypeAliasType -> newUnderlyingType.withUnderlyingType(
|
||||
newUnderlyingType.underlyingType.withParentArguments(newArguments, newIsMarkedNullable)
|
||||
)
|
||||
private fun CirClassOrTypeAliasType.isAnyUnderlyingClassifier(classifierId: CirEntityId): Boolean {
|
||||
return when (this) {
|
||||
is CirClassType -> false
|
||||
is CirTypeAliasType -> this.isAnyUnderlyingClassifier(classifierId)
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
|
||||
private val typeCommonizer = typeCommonizer.withOptions {
|
||||
withTypeAliasSubstitutionEnabled(false).withOptimisticNumberTypeCommonizationEnabled(true)
|
||||
withBackwardsTypeAliasSubstitutionEnabled(false).withOptimisticNumberTypeCommonizationEnabled(true)
|
||||
}
|
||||
|
||||
override fun invoke(values: List<CirTypeAlias>): CirTypeAlias? {
|
||||
|
||||
@@ -36,7 +36,8 @@ class TypeCommonizer(
|
||||
data class Options(
|
||||
val enableOptimisticNumberTypeCommonization: Boolean = false,
|
||||
val enableCovariantNullabilityCommonization: Boolean = false,
|
||||
val enableTypeAliasSubstitution: Boolean = true
|
||||
val enableForwardTypeAliasSubstitution: Boolean = true,
|
||||
val enableBackwardsTypeAliasSubstitution: Boolean = true,
|
||||
) {
|
||||
|
||||
fun withOptimisticNumberTypeCommonizationEnabled(enabled: Boolean = true): Options {
|
||||
@@ -49,9 +50,18 @@ class TypeCommonizer(
|
||||
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 {
|
||||
return if (enableTypeAliasSubstitution == enabled) this
|
||||
else copy(enableTypeAliasSubstitution = enabled)
|
||||
return withForwardTypeAliasSubstitutionEnabled(enabled).withBackwardsTypeAliasSubstitutionEnabled(enabled)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
+1
-5
@@ -6,11 +6,7 @@
|
||||
package org.jetbrains.kotlin.commonizer.transformer
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.TargetDependent
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
|
||||
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.cir.*
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirClassifierIndex
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirTypeSubstitutor
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.findTypeAlias
|
||||
|
||||
+1
-1
@@ -618,7 +618,7 @@ class HierarchicalOptimisticNumbersTypeCommonizerTest : AbstractInlineSourcesCom
|
||||
@UnsafeNumber(["a: kotlin.Int", "b: kotlin.Long"])
|
||||
typealias B = A
|
||||
@UnsafeNumber(["a: kotlin.Int", "b: kotlin.Long"])
|
||||
typealias X = Int
|
||||
typealias X = A
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user