[Commonizer] Avoid leaking non-commonized types as arguments in short-circuited TAs

This commit is contained in:
Dmitriy Dolovov
2021-01-15 16:09:03 +03:00
parent 8fa848bed3
commit ee93efc19d
13 changed files with 141 additions and 40 deletions

View File

@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.descriptors.commonizer.core
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirType
import org.jetbrains.kotlin.descriptors.commonizer.utils.compactMap
/**
* Unlike [Commonizer] which commonizes only single elements, this [AbstractListCommonizer] commonizes lists of elements using
@@ -22,7 +23,7 @@ abstract class AbstractListCommonizer<T, R>(
private var error = false
final override val result: List<R>
get() = checkState(commonizers, error).map { it.result }
get() = checkState(commonizers, error).compactMap { it.result }
final override fun commonizeWith(next: List<T>): Boolean {
if (error)

View File

@@ -10,6 +10,7 @@ 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
@@ -47,7 +48,7 @@ private class TypeAliasShortCircuitingCommonizer(
) : AbstractStandardCommonizer<CirTypeAlias, CirTypeAlias>() {
private lateinit var name: Name
private val typeParameters = TypeParameterListCommonizer(classifiers)
private lateinit var underlyingType: CirClassOrTypeAliasType
private var underlyingType: CirClassOrTypeAliasType? = null // null means not computed yet
private val expandedType = TypeCommonizer(classifiers)
private val visibility = VisibilityCommonizer.lowering()
@@ -56,7 +57,7 @@ private class TypeAliasShortCircuitingCommonizer(
name = name,
typeParameters = typeParameters.result,
visibility = visibility.result,
underlyingType = computeCommonizedUnderlyingType(underlyingType),
underlyingType = underlyingType!!,
expandedType = expandedType.result as CirClassType
)
@@ -65,23 +66,74 @@ private class TypeAliasShortCircuitingCommonizer(
override fun initialize(first: CirTypeAlias) {
name = first.name
underlyingType = first.underlyingType
}
override fun doCommonizeWith(next: CirTypeAlias) =
typeParameters.commonizeWith(next.typeParameters)
override fun doCommonizeWith(next: CirTypeAlias): Boolean {
if (underlyingType == null) {
underlyingType = computeUnderlyingType(next.underlyingType) ?: return false
}
return typeParameters.commonizeWith(next.typeParameters)
&& expandedType.commonizeWith(next.expandedType)
&& visibility.commonizeWith(next)
}
private tailrec fun computeCommonizedUnderlyingType(underlyingType: CirClassOrTypeAliasType): CirClassOrTypeAliasType {
private tailrec fun computeUnderlyingType(underlyingType: CirClassOrTypeAliasType): CirClassOrTypeAliasType? {
return when (underlyingType) {
is CirClassType -> underlyingType
is CirClassType -> underlyingType.withCommonizedArguments()
is CirTypeAliasType -> if (classifiers.commonDependeeLibraries.hasClassifier(underlyingType.classifierId))
underlyingType
underlyingType.withCommonizedArguments()
else
computeCommonizedUnderlyingType(underlyingType.underlyingType)
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>() {

View File

@@ -0,0 +1,37 @@
/*
* 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.CirStarTypeProjection
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirTypeProjection
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirTypeProjectionImpl
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirKnownClassifiers
import org.jetbrains.kotlin.types.Variance
class TypeArgumentCommonizer(
classifiers: CirKnownClassifiers
) : AbstractStandardCommonizer<CirTypeProjection, CirTypeProjection>() {
private var isStar = false
private lateinit var projectionKind: Variance
private val type = TypeCommonizer(classifiers)
override fun commonizationResult() = if (isStar) CirStarTypeProjection else CirTypeProjectionImpl(
projectionKind = projectionKind,
type = type.result
)
override fun initialize(first: CirTypeProjection) {
when (first) {
is CirStarTypeProjection -> isStar = true
is CirTypeProjectionImpl -> projectionKind = first.projectionKind
}
}
override fun doCommonizeWith(next: CirTypeProjection) = when (next) {
is CirStarTypeProjection -> isStar
is CirTypeProjectionImpl -> !isStar && projectionKind == next.projectionKind && type.commonizeWith(next.type)
}
}

View File

@@ -0,0 +1,13 @@
/*
* 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.CirTypeProjection
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirKnownClassifiers
class TypeArgumentListCommonizer(classifiers: CirKnownClassifiers) : AbstractListCommonizer<CirTypeProjection, CirTypeProjection>(
singleElementCommonizerFactory = { TypeArgumentCommonizer(classifiers) }
)

View File

@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.descriptors.commonizer.core.CommonizedTypeAliasAnswe
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirKnownClassifiers
import org.jetbrains.kotlin.descriptors.commonizer.utils.isUnderKotlinNativeSyntheticPackages
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.types.Variance
class TypeCommonizer(private val classifiers: CirKnownClassifiers) : AbstractStandardCommonizer<CirType, CirType>() {
private lateinit var wrapped: Commonizer<*, CirType>
@@ -190,35 +189,6 @@ private class FlexibleTypeCommonizer(classifiers: CirKnownClassifiers) : Abstrac
lowerBound.commonizeWith(next.lowerBound) && upperBound.commonizeWith(next.upperBound)
}
private class TypeArgumentCommonizer(
classifiers: CirKnownClassifiers
) : AbstractStandardCommonizer<CirTypeProjection, CirTypeProjection>() {
private var isStar = false
private lateinit var projectionKind: Variance
private val type = TypeCommonizer(classifiers)
override fun commonizationResult() = if (isStar) CirStarTypeProjection else CirTypeProjectionImpl(
projectionKind = projectionKind,
type = type.result
)
override fun initialize(first: CirTypeProjection) {
when (first) {
is CirStarTypeProjection -> isStar = true
is CirTypeProjectionImpl -> projectionKind = first.projectionKind
}
}
override fun doCommonizeWith(next: CirTypeProjection) = when (next) {
is CirStarTypeProjection -> isStar
is CirTypeProjectionImpl -> !isStar && projectionKind == next.projectionKind && type.commonizeWith(next.type)
}
}
private class TypeArgumentListCommonizer(classifiers: CirKnownClassifiers) : AbstractListCommonizer<CirTypeProjection, CirTypeProjection>(
singleElementCommonizerFactory = { TypeArgumentCommonizer(classifiers) }
)
private fun commonizeClass(classId: ClassId, classifiers: CirKnownClassifiers): Boolean {
if (classifiers.commonDependeeLibraries.hasClassifier(classId)) {
// The class is from common fragment of dependee library (ex: stdlib). Already commonized.

View File

@@ -41,6 +41,13 @@ internal inline fun <T, R> Collection<T>.compactMap(transform: (T) -> R): List<R
else -> mapTo(ArrayList(size), transform)
}
internal inline fun <T, R> Array<T>.compactMap(transform: (T) -> R): List<R> =
when (size) {
0 -> emptyList()
1 -> singletonList(transform(this[0]))
else -> mapTo(ArrayList(size), transform)
}
internal inline fun <T, reified R : Any> Collection<T>.compactMapNotNull(transform: (T) -> R?): List<R> =
if (isEmpty()) emptyList() else mapNotNullTo(ArrayList(size), transform).compact()

View File

@@ -0,0 +1,3 @@
typealias my_long_t = common.stuff.MyLong
typealias MyTypeAlias = common.stuff.Wrapper<my_long_t>
expect val property: MyTypeAlias

View File

@@ -0,0 +1,2 @@
typealias my_linux_long_t = common.stuff.MyLong
actual val property: MyTypeAlias = TODO()

View File

@@ -0,0 +1,2 @@
typealias my_macos_long_t = common.stuff.MyLong
actual val property: MyTypeAlias = TODO()

View File

@@ -0,0 +1,4 @@
package common.stuff
class Wrapper<T>
class MyLong

View File

@@ -0,0 +1,4 @@
typealias my_long_t = my_linux_long_t
typealias my_linux_long_t = common.stuff.MyLong
typealias MyTypeAlias = common.stuff.Wrapper<my_long_t>
val property: MyTypeAlias = TODO()

View File

@@ -0,0 +1,4 @@
typealias my_long_t = my_macos_long_t
typealias my_macos_long_t = common.stuff.MyLong
typealias MyTypeAlias = common.stuff.Wrapper<my_long_t>
val property: MyTypeAlias = TODO()

View File

@@ -23,4 +23,6 @@ class ClassifierCommonizationFromSourcesTest : AbstractCommonizationFromSourcesT
fun testSupertypes() = doTestSuccessfulCommonization()
fun testTypeAliases() = doTestSuccessfulCommonization()
fun testDifferentTypeAliasesInArguments() = doTestSuccessfulCommonization()
}