[Commonizer] Avoid leaking non-commonized underlying types in TAs

This commit is contained in:
Dmitriy Dolovov
2021-01-26 10:58:30 +03:00
parent 4bf6e58f2b
commit 85f79695b9
3 changed files with 78 additions and 60 deletions
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirClassFactory
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirTypeAliasFactory
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirTypeFactory
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirKnownClassifiers
import org.jetbrains.kotlin.name.Name
@@ -70,70 +69,13 @@ private class TypeAliasShortCircuitingCommonizer(
override fun doCommonizeWith(next: CirTypeAlias): Boolean {
if (underlyingType == null) {
underlyingType = computeUnderlyingType(next.underlyingType) ?: return false
underlyingType = computeSuitableUnderlyingType(classifiers, next.underlyingType) ?: return false
}
return typeParameters.commonizeWith(next.typeParameters)
&& expandedType.commonizeWith(next.expandedType)
&& visibility.commonizeWith(next)
}
private tailrec fun computeUnderlyingType(underlyingType: CirClassOrTypeAliasType): CirClassOrTypeAliasType? {
return when (underlyingType) {
is CirClassType -> underlyingType.withCommonizedArguments()
is CirTypeAliasType -> if (classifiers.commonDependeeLibraries.hasClassifier(underlyingType.classifierId))
underlyingType.withCommonizedArguments()
else
computeUnderlyingType(underlyingType.underlyingType)
}
}
private fun CirClassType.withCommonizedArguments(): CirClassType? {
val existingArguments = arguments
val newArguments = existingArguments.toCommonizedArguments() ?: return null
val existingOuterType = outerType
val newOuterType = existingOuterType?.let { it.withCommonizedArguments() ?: return null }
return if (newArguments !== existingArguments || newOuterType !== existingOuterType)
CirTypeFactory.createClassType(
classId = classifierId,
outerType = newOuterType,
visibility = visibility,
arguments = newArguments,
isMarkedNullable = isMarkedNullable
)
else
this
}
private fun CirTypeAliasType.withCommonizedArguments(): CirTypeAliasType? {
val existingArguments = arguments
val newArguments = existingArguments.toCommonizedArguments() ?: return null
val existingUnderlyingType = underlyingType
val newUnderlyingType = when (existingUnderlyingType) {
is CirClassType -> existingUnderlyingType.withCommonizedArguments()
is CirTypeAliasType -> existingUnderlyingType.withCommonizedArguments()
} ?: return null
return if (newArguments !== existingArguments || newUnderlyingType !== existingUnderlyingType)
CirTypeFactory.createTypeAliasType(
typeAliasId = classifierId,
underlyingType = newUnderlyingType,
arguments = newArguments,
isMarkedNullable = isMarkedNullable
)
else
this
}
@Suppress("NOTHING_TO_INLINE")
private inline fun List<CirTypeProjection>.toCommonizedArguments(): List<CirTypeProjection>? =
if (isEmpty())
this
else
TypeArgumentListCommonizer(classifiers).let { if (it.commonizeWith(this)) it.result else null }
}
private class TypeAliasLiftingUpCommonizer(classifiers: CirKnownClassifiers) : AbstractStandardCommonizer<CirTypeAlias, CirTypeAlias>() {
@@ -109,7 +109,10 @@ private class TypeAliasTypeCommonizer(private val classifiers: CirKnownClassifie
commonizedTypeBuilder = when (val commonClassifier = answer.commonClassifier) {
is CirClass -> CommonizedTypeAliasTypeBuilder.forClass(commonClassifier)
is CirTypeAlias -> CommonizedTypeAliasTypeBuilder.forTypeAlias(commonClassifier)
null -> CommonizedTypeAliasTypeBuilder.forKnownUnderlyingType(next.underlyingType)
null -> {
val underlyingType = computeSuitableUnderlyingType(classifiers, next.underlyingType) ?: return false
CommonizedTypeAliasTypeBuilder.forKnownUnderlyingType(underlyingType)
}
else -> error("Unexpected common classifier type: ${commonClassifier::class.java}, $commonClassifier")
}
}
@@ -0,0 +1,73 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.commonizer.core
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirClassOrTypeAliasType
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirClassType
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirTypeAliasType
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirTypeProjection
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirTypeFactory
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirKnownClassifiers
internal tailrec fun computeSuitableUnderlyingType(
classifiers: CirKnownClassifiers,
underlyingType: CirClassOrTypeAliasType
): CirClassOrTypeAliasType? {
return when (underlyingType) {
is CirClassType -> underlyingType.withCommonizedArguments(classifiers)
is CirTypeAliasType -> if (classifiers.commonDependeeLibraries.hasClassifier(underlyingType.classifierId))
underlyingType.withCommonizedArguments(classifiers)
else
computeSuitableUnderlyingType(classifiers, underlyingType.underlyingType)
}
}
private fun CirClassType.withCommonizedArguments(classifiers: CirKnownClassifiers): CirClassType? {
val existingArguments = arguments
val newArguments = existingArguments.toCommonizedArguments(classifiers) ?: return null
val existingOuterType = outerType
val newOuterType = existingOuterType?.let { it.withCommonizedArguments(classifiers) ?: return null }
return if (newArguments !== existingArguments || newOuterType !== existingOuterType)
CirTypeFactory.createClassType(
classId = classifierId,
outerType = newOuterType,
visibility = visibility,
arguments = newArguments,
isMarkedNullable = isMarkedNullable
)
else
this
}
private fun CirTypeAliasType.withCommonizedArguments(classifiers: CirKnownClassifiers): CirTypeAliasType? {
val existingArguments = arguments
val newArguments = existingArguments.toCommonizedArguments(classifiers) ?: return null
val existingUnderlyingType = underlyingType
val newUnderlyingType = when (existingUnderlyingType) {
is CirClassType -> existingUnderlyingType.withCommonizedArguments(classifiers)
is CirTypeAliasType -> existingUnderlyingType.withCommonizedArguments(classifiers)
} ?: return null
return if (newArguments !== existingArguments || newUnderlyingType !== existingUnderlyingType)
CirTypeFactory.createTypeAliasType(
typeAliasId = classifierId,
underlyingType = newUnderlyingType,
arguments = newArguments,
isMarkedNullable = isMarkedNullable
)
else
this
}
@Suppress("NOTHING_TO_INLINE")
private inline fun List<CirTypeProjection>.toCommonizedArguments(classifiers: CirKnownClassifiers): List<CirTypeProjection>? =
if (isEmpty())
this
else
TypeArgumentListCommonizer(classifiers).let { if (it.commonizeWith(this)) it.result else null }