mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-10 08:31:29 +00:00
[Commonizer] Implement new ClassOrTypeAliasTypeCommonizer
^KT-47432 Verification Pending ^KT-47434 Verification Pending
This commit is contained in:
committed by
Space
parent
8e2780345c
commit
8f73df0f85
@@ -25,9 +25,12 @@ object CirClassRecursionMarker : CirClass, CirRecursionMarker {
|
||||
set(_) = unsupported()
|
||||
}
|
||||
|
||||
object CirClassifierRecursionMarker : CirClassifier, CirRecursionMarker {
|
||||
object CirTypeAliasRecursionMarker : CirTypeAlias, CirRecursionMarker {
|
||||
override val underlyingType: CirClassOrTypeAliasType get() = unsupported()
|
||||
override val expandedType: CirClassType get() = unsupported()
|
||||
override val annotations get() = unsupported()
|
||||
override val name get() = unsupported()
|
||||
override val typeParameters get() = unsupported()
|
||||
override val visibility get() = unsupported()
|
||||
override val isLiftedUp: Boolean get() = unsupported()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.commonizer.core
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirClassOrTypeAliasType
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirClassType
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirTypeAliasType
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers
|
||||
|
||||
internal class ClassOrTypeAliasTypeStatelessCommonizer(
|
||||
private val classifiers: CirKnownClassifiers
|
||||
) : StatelessCommonizer<CirClassOrTypeAliasType, CirClassOrTypeAliasType> {
|
||||
|
||||
override fun commonize(values: List<CirClassOrTypeAliasType>): CirClassOrTypeAliasType? {
|
||||
if (values.isEmpty()) return null
|
||||
values.singleOrNull()?.let { return it }
|
||||
|
||||
val classTypes = values.filterIsInstance<CirClassType>()
|
||||
val typeAliasTypes = values.filterIsInstance<CirTypeAliasType>()
|
||||
val expandedTypeAliasTypes = typeAliasTypes.map { it.expandedType() }
|
||||
|
||||
if (values.all { it is CirClassType }) {
|
||||
return ClassTypeCommonizer(classifiers).commonize(classTypes)
|
||||
}
|
||||
|
||||
if (values.all { it is CirTypeAliasType }) {
|
||||
/*
|
||||
In case regular type-alias-type commonization fails, we try to expand all type-aliases and
|
||||
try our luck with commonizing those class types
|
||||
*/
|
||||
return TypeAliasTypeCommonizer(classifiers).commonize(typeAliasTypes)
|
||||
?: ClassTypeCommonizer(classifiers).commonize(expandedTypeAliasTypes)
|
||||
}
|
||||
|
||||
/*
|
||||
There are type-alias types & class types enqueued for commonization.
|
||||
We reduce all classes to a common representation and all type aliases to a common representation.
|
||||
*/
|
||||
val commonizedClass = ClassTypeCommonizer(classifiers).commonize(classTypes) ?: return null
|
||||
val commonizedTypeAlias = TypeAliasTypeCommonizer(classifiers).commonize(typeAliasTypes)
|
||||
|
||||
if (commonizedTypeAlias != null) {
|
||||
return ClassTypeCommonizer(classifiers).commonize(listOf(commonizedClass, commonizedTypeAlias.expandedType()))
|
||||
}
|
||||
|
||||
/*
|
||||
If type-alias type commonization failed:
|
||||
Last attempt: Try to commonize all type-alias expansions with the commonized class
|
||||
*/
|
||||
return ClassTypeCommonizer(classifiers).commonize(expandedTypeAliasTypes + commonizedClass)
|
||||
}
|
||||
}
|
||||
|
||||
internal class ClassOrTypeAliasTypeCommonizer(classifiers: CirKnownClassifiers) :
|
||||
StatelessCommonizerAdapter<CirClassOrTypeAliasType, CirClassOrTypeAliasType>(ClassOrTypeAliasTypeStatelessCommonizer(classifiers))
|
||||
|
||||
internal tailrec fun CirClassOrTypeAliasType.expandedType(): CirClassType = when (this) {
|
||||
is CirClassType -> this
|
||||
is CirTypeAliasType -> this.underlyingType.expandedType()
|
||||
}
|
||||
@@ -10,6 +10,16 @@ interface Commonizer<T, R> {
|
||||
fun commonizeWith(next: T): Boolean
|
||||
}
|
||||
|
||||
fun <T, R> Commonizer<T, R>.commonize(values: List<T>): R? {
|
||||
/* Fast path: If commonizer supports StatelessCommonizer interface */
|
||||
if (this is StatelessCommonizerAdapter) {
|
||||
return commonize(values)
|
||||
}
|
||||
|
||||
values.forEach { value -> if (!commonizeWith(value)) return null }
|
||||
return result
|
||||
}
|
||||
|
||||
abstract class AbstractStandardCommonizer<T, R> : Commonizer<T, R> {
|
||||
private enum class State {
|
||||
EMPTY,
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.commonizer.core
|
||||
|
||||
interface StatelessCommonizer<T, R> {
|
||||
fun commonize(values: List<T>): R?
|
||||
}
|
||||
|
||||
open class StatelessCommonizerAdapter<T, R : Any>(
|
||||
private val commonizer: StatelessCommonizer<T, R>
|
||||
) : AbstractStandardCommonizer<T, R>(), StatelessCommonizer<T, R> by commonizer {
|
||||
private val values = mutableListOf<T>()
|
||||
|
||||
override fun commonizationResult(): R {
|
||||
try {
|
||||
return checkNotNull(commonize(values.toList()))
|
||||
} finally {
|
||||
values.clear()
|
||||
}
|
||||
}
|
||||
|
||||
override fun initialize(first: T) = Unit
|
||||
|
||||
override fun doCommonizeWith(next: T): Boolean {
|
||||
values.add(next)
|
||||
return commonize(values.toList()) != null
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,11 @@ import org.jetbrains.kotlin.descriptors.Modality
|
||||
* Secondary (less optimistic) branch:
|
||||
* - Make sure that all TAs are identical, so the resulting TA can be lifted up into "common" fragment.
|
||||
*/
|
||||
class TypeAliasCommonizer(classifiers: CirKnownClassifiers) : AbstractStandardCommonizer<CirTypeAlias, CirClassifier>() {
|
||||
class TypeAliasCommonizer(classifiers: CirKnownClassifiers) : AbstractStandardCommonizer<CirTypeAlias, CirTypeAlias>() {
|
||||
private val primary = TypeAliasShortCircuitingCommonizer(classifiers)
|
||||
private val secondary = TypeAliasLiftingUpCommonizer(classifiers)
|
||||
|
||||
override fun commonizationResult(): CirClassifier = primary.resultOrNull ?: secondary.result
|
||||
override fun commonizationResult(): CirTypeAlias = primary.resultOrNull ?: secondary.result
|
||||
|
||||
override fun initialize(first: CirTypeAlias) = Unit
|
||||
|
||||
|
||||
@@ -14,61 +14,30 @@ import org.jetbrains.kotlin.commonizer.utils.isUnderKotlinNativeSyntheticPackage
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
|
||||
class TypeCommonizer(private val classifiers: CirKnownClassifiers) : AbstractStandardCommonizer<CirType, CirType>() {
|
||||
private var typeCommonizer: AbstractStandardCommonizer<*, CirType>? = null
|
||||
private var underlyingTypeCommonizer: TypeCommonizer? = null
|
||||
private lateinit var typeCommonizer: Commonizer<*, CirType>
|
||||
|
||||
override fun commonizationResult() = typeCommonizer?.resultOrNull
|
||||
?: underlyingTypeCommonizer?.result
|
||||
?: typeCommonizer?.result
|
||||
?: failInErrorState()
|
||||
override fun commonizationResult() = typeCommonizer.result
|
||||
|
||||
override fun initialize(first: CirType) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
typeCommonizer = when (first) {
|
||||
is CirClassType -> ClassTypeCommonizer(classifiers)
|
||||
is CirTypeAliasType -> TypeAliasTypeCommonizer(classifiers)
|
||||
is CirClassOrTypeAliasType -> ClassOrTypeAliasTypeCommonizer(classifiers)
|
||||
is CirTypeParameterType -> TypeParameterTypeCommonizer()
|
||||
is CirFlexibleType -> FlexibleTypeCommonizer(classifiers)
|
||||
} as AbstractStandardCommonizer<*, CirType>
|
||||
|
||||
if (first is CirTypeAliasType) {
|
||||
underlyingTypeCommonizer = TypeCommonizer(classifiers)
|
||||
}
|
||||
} as Commonizer<*, CirType>
|
||||
}
|
||||
|
||||
override fun doCommonizeWith(next: CirType): Boolean {
|
||||
return when (next) {
|
||||
is CirClassType -> doCommonizeWithClassType(next)
|
||||
is CirTypeAliasType -> doCommonizeWithTypeAliasType(next)
|
||||
is CirClassOrTypeAliasType -> (typeCommonizer as? ClassOrTypeAliasTypeCommonizer)?.commonizeWith(next) == true
|
||||
is CirTypeParameterType -> (typeCommonizer as? TypeParameterTypeCommonizer)?.commonizeWith(next) == true
|
||||
is CirFlexibleType -> (typeCommonizer as? FlexibleTypeCommonizer)?.commonizeWith(next) == true
|
||||
}
|
||||
}
|
||||
|
||||
private fun doCommonizeWithClassType(next: CirClassType): Boolean {
|
||||
if ((typeCommonizer as? ClassTypeCommonizer) == null) {
|
||||
typeCommonizer = null
|
||||
}
|
||||
|
||||
val firstAnswer = (typeCommonizer as? ClassTypeCommonizer)?.commonizeWith(next) == true
|
||||
val secondAnswer = underlyingTypeCommonizer?.commonizeWith(next) == true
|
||||
return firstAnswer || secondAnswer
|
||||
}
|
||||
|
||||
private fun doCommonizeWithTypeAliasType(next: CirTypeAliasType): Boolean {
|
||||
if (typeCommonizer != null && underlyingTypeCommonizer == null) {
|
||||
underlyingTypeCommonizer = TypeCommonizer(classifiers)
|
||||
underlyingTypeCommonizer?.commonizeWith(typeCommonizer?.resultOrNull ?: return false)
|
||||
typeCommonizer = null
|
||||
}
|
||||
|
||||
val firstAnswer = (typeCommonizer as? TypeAliasTypeCommonizer)?.commonizeWith(next) == true
|
||||
val secondAnswer = underlyingTypeCommonizer?.commonizeWith(next.underlyingType) == true
|
||||
return firstAnswer || secondAnswer
|
||||
}
|
||||
}
|
||||
|
||||
private class ClassTypeCommonizer(private val classifiers: CirKnownClassifiers) : AbstractStandardCommonizer<CirClassType, CirClassType>() {
|
||||
internal class ClassTypeCommonizer(private val classifiers: CirKnownClassifiers) :
|
||||
AbstractStandardCommonizer<CirClassType, CirClassType>() {
|
||||
private lateinit var classId: CirEntityId
|
||||
private val outerType = OuterClassTypeCommonizer(classifiers)
|
||||
private lateinit var anyVisibility: Visibility
|
||||
@@ -101,14 +70,15 @@ private class ClassTypeCommonizer(private val classifiers: CirKnownClassifiers)
|
||||
&& arguments.commonizeWith(next.arguments)
|
||||
}
|
||||
|
||||
private class OuterClassTypeCommonizer(classifiers: CirKnownClassifiers) :
|
||||
// TODO NOW
|
||||
internal class OuterClassTypeCommonizer(classifiers: CirKnownClassifiers) :
|
||||
AbstractNullableCommonizer<CirClassType, CirClassType, CirClassType, CirClassType>(
|
||||
wrappedCommonizerFactory = { ClassTypeCommonizer(classifiers) },
|
||||
extractor = { it },
|
||||
builder = { it }
|
||||
)
|
||||
|
||||
private class TypeAliasTypeCommonizer(private val classifiers: CirKnownClassifiers) :
|
||||
internal class TypeAliasTypeCommonizer(private val classifiers: CirKnownClassifiers) :
|
||||
AbstractStandardCommonizer<CirTypeAliasType, CirClassOrTypeAliasType>() {
|
||||
|
||||
private lateinit var typeAliasId: CirEntityId
|
||||
@@ -125,11 +95,11 @@ private class TypeAliasTypeCommonizer(private val classifiers: CirKnownClassifie
|
||||
|
||||
override fun initialize(first: CirTypeAliasType) {
|
||||
typeAliasId = first.classifierId
|
||||
isMarkedNullable = first.isMarkedNullable
|
||||
isMarkedNullable = first.expandedType().isMarkedNullable
|
||||
}
|
||||
|
||||
override fun doCommonizeWith(next: CirTypeAliasType): Boolean {
|
||||
if (isMarkedNullable != next.isMarkedNullable || typeAliasId != next.classifierId)
|
||||
if (isMarkedNullable != next.expandedType().isMarkedNullable || typeAliasId != next.classifierId)
|
||||
return false
|
||||
|
||||
if (commonizedTypeBuilder == null) {
|
||||
@@ -152,7 +122,7 @@ private class TypeAliasTypeCommonizer(private val classifiers: CirKnownClassifie
|
||||
}
|
||||
|
||||
// builds a new type for "common" library fragment for the given combination of type alias types in "platform" fragments
|
||||
private interface CommonizedTypeAliasTypeBuilder {
|
||||
internal interface CommonizedTypeAliasTypeBuilder {
|
||||
fun build(typeAliasId: CirEntityId, arguments: List<CirTypeProjection>, isMarkedNullable: Boolean): CirClassOrTypeAliasType
|
||||
|
||||
companion object {
|
||||
@@ -161,7 +131,7 @@ private class TypeAliasTypeCommonizer(private val classifiers: CirKnownClassifie
|
||||
override fun build(typeAliasId: CirEntityId, arguments: List<CirTypeProjection>, isMarkedNullable: Boolean) =
|
||||
CirClassType.createInterned(
|
||||
classId = typeAliasId,
|
||||
outerType = null, // there can't be outer type
|
||||
outerType = null, // there can't be outer type // TODO NOW!!!
|
||||
visibility = commonClass.visibility,
|
||||
arguments = arguments,
|
||||
isMarkedNullable = isMarkedNullable
|
||||
@@ -257,7 +227,7 @@ private fun commonizeTypeAlias(typeAliasId: CirEntityId, classifiers: CirKnownCl
|
||||
return create(typeAliasNode?.commonDeclaration?.invoke() ?: classNode?.commonDeclaration?.invoke())
|
||||
}
|
||||
|
||||
private class CommonizedTypeAliasAnswer(val commonized: Boolean, val commonClassifier: CirClassifier?) {
|
||||
internal class CommonizedTypeAliasAnswer(val commonized: Boolean, val commonClassifier: CirClassifier?) {
|
||||
companion object {
|
||||
val SUCCESS_FROM_DEPENDENCY_LIBRARY = CommonizedTypeAliasAnswer(true, null)
|
||||
val FAILURE_MISSING_IN_SOME_TARGET = CommonizedTypeAliasAnswer(false, null)
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.commonizer.mergedtree
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirClassifier
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirTypeAlias
|
||||
import org.jetbrains.kotlin.commonizer.utils.CommonizedGroup
|
||||
@@ -14,8 +13,8 @@ import org.jetbrains.kotlin.storage.NullableLazyValue
|
||||
class CirTypeAliasNode(
|
||||
val id: CirEntityId,
|
||||
override val targetDeclarations: CommonizedGroup<CirTypeAlias>,
|
||||
override val commonDeclaration: NullableLazyValue<CirClassifier>,
|
||||
) : CirClassifierNode<CirTypeAlias, CirClassifier>, CirNodeWithLiftingUp<CirTypeAlias, CirClassifier> {
|
||||
override val commonDeclaration: NullableLazyValue<CirTypeAlias>,
|
||||
) : CirClassifierNode<CirTypeAlias, CirTypeAlias>, CirNodeWithLiftingUp<CirTypeAlias, CirTypeAlias> {
|
||||
|
||||
override fun <T, R> accept(visitor: CirNodeVisitor<T, R>, data: T): R =
|
||||
visitor.visitTypeAliasNode(this, data)
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
package org.jetbrains.kotlin.commonizer.mergedtree
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirClassRecursionMarker
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirClassifierRecursionMarker
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirDeclaration
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirTypeAliasRecursionMarker
|
||||
import org.jetbrains.kotlin.commonizer.core.*
|
||||
import org.jetbrains.kotlin.commonizer.utils.CommonizedGroup
|
||||
import org.jetbrains.kotlin.storage.NullableLazyValue
|
||||
@@ -116,7 +116,7 @@ internal fun buildTypeAliasNode(
|
||||
size = size,
|
||||
nodeRelationship = null,
|
||||
commonizerProducer = { TypeAliasCommonizer(classifiers) },
|
||||
recursionMarker = CirClassifierRecursionMarker,
|
||||
recursionMarker = CirTypeAliasRecursionMarker,
|
||||
nodeProducer = { targetDeclarations, commonDeclaration ->
|
||||
CirTypeAliasNode(typeAliasId, targetDeclarations, commonDeclaration).also {
|
||||
classifiers.commonizedNodes.addTypeAliasNode(typeAliasId, it)
|
||||
@@ -148,12 +148,8 @@ internal fun <T : Any, R> commonize(
|
||||
targetDeclarations: CommonizedGroup<T>,
|
||||
commonizer: Commonizer<T, R>
|
||||
): R? {
|
||||
for (targetDeclaration in targetDeclarations) {
|
||||
if (targetDeclaration == null || !commonizer.commonizeWith(targetDeclaration))
|
||||
return null
|
||||
}
|
||||
|
||||
return commonizer.result
|
||||
if (targetDeclarations.any { it == null }) return null
|
||||
return commonizer.commonize(targetDeclarations.filterNotNull())
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@@ -176,4 +172,4 @@ private fun CirNodeRelationship?.shouldCommonize(): Boolean {
|
||||
is CirNodeRelationship.PreferredNode -> node.commonDeclaration() == null
|
||||
is CirNodeRelationship.Composite -> relationships.all { it.shouldCommonize() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,21 +103,21 @@ class TypeCommonizerTest : AbstractCommonizerTest<CirType, CirType>() {
|
||||
fun classTypesInUserPackageWithDifferentNames1() = doTestFailure(
|
||||
mockClassType("org/sample/Foo"),
|
||||
mockClassType("org/fictitiousPackageName/Foo"),
|
||||
shouldFailOnFirstVariant = true
|
||||
shouldFailOnFirstVariant = false
|
||||
)
|
||||
|
||||
@Test(expected = IllegalCommonizerStateException::class)
|
||||
fun classTypesInUserPackageWithDifferentNames2() = doTestFailure(
|
||||
mockClassType("org/sample/Foo"),
|
||||
mockClassType("org/sample/Bar"),
|
||||
shouldFailOnFirstVariant = true
|
||||
shouldFailOnFirstVariant = false
|
||||
)
|
||||
|
||||
@Test(expected = IllegalCommonizerStateException::class)
|
||||
fun classTypesInUserPackageWithDifferentNames3() = doTestFailure(
|
||||
mockClassType("org/sample/Foo"),
|
||||
mockClassType("kotlin/String"),
|
||||
shouldFailOnFirstVariant = true
|
||||
shouldFailOnFirstVariant = false
|
||||
)
|
||||
|
||||
@Test
|
||||
@@ -364,19 +364,17 @@ class TypeCommonizerTest : AbstractCommonizerTest<CirType, CirType>() {
|
||||
mockTAType("kotlin/sequences/SequenceBuilder", nullable = false) { mockClassType("kotlin/sequences/SequenceScope") }
|
||||
)
|
||||
|
||||
@Test
|
||||
// why success: nullability of underlying type does not matter if typealias belongs to one of the standard Kotlin packages
|
||||
fun taTypesInKotlinPackageWithDifferentNullability3() = doTestSuccess(
|
||||
expected = mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = false) },
|
||||
@Test(expected = IllegalCommonizerStateException::class)
|
||||
// why failure: Different nullability in type-expansion can't be commonized by now
|
||||
fun taTypesInKotlinPackageWithDifferentNullability3() = doTestFailure(
|
||||
mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = false) },
|
||||
mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = false) },
|
||||
mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = true) }
|
||||
)
|
||||
|
||||
@Test
|
||||
// why success: nullability of underlying type does not matter if typealias belongs to one of the standard Kotlin packages
|
||||
fun taTypesInKotlinPackageWithDifferentNullability4() = doTestSuccess(
|
||||
expected = mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = true) },
|
||||
@Test(expected = IllegalCommonizerStateException::class)
|
||||
// why failure: Different nullability in type-expansion can't be commonized by now
|
||||
fun taTypesInKotlinPackageWithDifferentNullability4() = doTestFailure(
|
||||
mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = true) },
|
||||
mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = true) },
|
||||
mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = false) }
|
||||
|
||||
Reference in New Issue
Block a user