[Commonizer] Prototype: Commonize TypeAliases with Classes
^KT-45992 Fixed ^KT-46061 Fixed
This commit is contained in:
committed by
Space
parent
b394dde339
commit
8272564ca0
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this delegate code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.commonizer.cir
|
||||
|
||||
/**
|
||||
* Marker for classifiers that are made up to support commonization.
|
||||
* E.g. TypeAliases might create artificial classes for the types they are pointing to.
|
||||
*/
|
||||
internal interface ArtificialCirDeclaration : CirDeclaration
|
||||
|
||||
internal class ArtificialCirModule(val delegate: CirModule) : CirModule by delegate, ArtificialCirDeclaration
|
||||
|
||||
internal fun CirModule.markedArtificial() = ArtificialCirModule(this)
|
||||
|
||||
internal class ArtificialCirClass(val delegate: CirClass) : CirClass by delegate, ArtificialCirDeclaration
|
||||
|
||||
internal fun CirClass.markedArtificial(): ArtificialCirClass = ArtificialCirClass(this)
|
||||
|
||||
internal class ArtificialCirClassConstructor(val delegate: CirClassConstructor) : CirClassConstructor by delegate, ArtificialCirDeclaration
|
||||
|
||||
internal fun CirClassConstructor.markedArtificial() = ArtificialCirClassConstructor(this)
|
||||
|
||||
internal class ArtificialCirFunction(val delegate: CirFunction) : CirFunction by delegate, ArtificialCirDeclaration
|
||||
|
||||
internal fun CirFunction.markedArtificial() = ArtificialCirFunction(this)
|
||||
|
||||
internal class ArtificialCirProperty(val delegate: CirProperty) : CirProperty by delegate, ArtificialCirDeclaration
|
||||
|
||||
internal fun CirProperty.markedArtificial() = ArtificialCirProperty(this)
|
||||
@@ -18,6 +18,8 @@ interface CirClassConstructor :
|
||||
val isPrimary: Boolean
|
||||
override val containingClass: CirContainingClass // non-nullable
|
||||
|
||||
override fun withContainingClass(containingClass: CirContainingClass): CirClassConstructor
|
||||
|
||||
companion object {
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun create(
|
||||
@@ -48,4 +50,8 @@ data class CirClassConstructorImpl(
|
||||
override var valueParameters: List<CirValueParameter>,
|
||||
override var hasStableParameterNames: Boolean,
|
||||
override val isPrimary: Boolean
|
||||
) : CirClassConstructor
|
||||
) : CirClassConstructor {
|
||||
override fun withContainingClass(containingClass: CirContainingClass): CirClassConstructor {
|
||||
return copy(containingClass = containingClass)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,8 +41,13 @@ interface CirHasModality {
|
||||
val modality: Modality
|
||||
}
|
||||
|
||||
|
||||
interface CirMaybeCallableMemberOfClass {
|
||||
val containingClass: CirContainingClass? // null assumes no containing class
|
||||
|
||||
fun withContainingClass(containingClass: CirContainingClass): CirMaybeCallableMemberOfClass = object : CirMaybeCallableMemberOfClass {
|
||||
override val containingClass: CirContainingClass = containingClass
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,6 +12,8 @@ import org.jetbrains.kotlin.descriptors.Visibility
|
||||
interface CirFunction : CirFunctionOrProperty, CirCallableMemberWithParameters {
|
||||
val modifiers: CirFunctionModifiers
|
||||
|
||||
override fun withContainingClass(containingClass: CirContainingClass): CirFunction
|
||||
|
||||
companion object {
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun create(
|
||||
@@ -57,4 +59,8 @@ data class CirFunctionImpl(
|
||||
override val returnType: CirType,
|
||||
override val kind: CallableMemberDescriptor.Kind,
|
||||
override val modifiers: CirFunctionModifiers
|
||||
) : CirFunction
|
||||
) : CirFunction {
|
||||
override fun withContainingClass(containingClass: CirContainingClass): CirFunction {
|
||||
return copy(containingClass = containingClass)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ interface CirProperty : CirFunctionOrProperty, CirLiftedUpDeclaration {
|
||||
val delegateFieldAnnotations: List<CirAnnotation>
|
||||
val compileTimeInitializer: CirConstantValue
|
||||
|
||||
override fun withContainingClass(containingClass: CirContainingClass): CirProperty
|
||||
|
||||
companion object {
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun create(
|
||||
@@ -90,4 +92,8 @@ data class CirPropertyImpl(
|
||||
) : CirProperty {
|
||||
// const property in "common" fragment is already lifted up
|
||||
override val isLiftedUp get() = isConst
|
||||
|
||||
override fun withContainingClass(containingClass: CirContainingClass): CirProperty {
|
||||
return copy(containingClass = containingClass)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,26 +16,21 @@ 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.
|
||||
*
|
||||
* Tertiary (backup) branch:
|
||||
* - Produce an "expect class" for "common" fragment and the corresponding "actual typealias" declarations for each platform fragment.
|
||||
*/
|
||||
class TypeAliasCommonizer(classifiers: CirKnownClassifiers) : AbstractStandardCommonizer<CirTypeAlias, CirClassifier>() {
|
||||
private val primary = TypeAliasShortCircuitingCommonizer(classifiers)
|
||||
private val secondary = TypeAliasLiftingUpCommonizer(classifiers)
|
||||
private val tertiary = TypeAliasExpectClassCommonizer()
|
||||
|
||||
override fun commonizationResult(): CirClassifier = primary.resultOrNull ?: secondary.resultOrNull ?: tertiary.result
|
||||
override fun commonizationResult(): CirClassifier = primary.resultOrNull ?: secondary.result
|
||||
|
||||
override fun initialize(first: CirTypeAlias) = Unit
|
||||
|
||||
override fun doCommonizeWith(next: CirTypeAlias): Boolean {
|
||||
val primaryResult = primary.commonizeWith(next)
|
||||
val secondaryResult = secondary.commonizeWith(next)
|
||||
val tertiaryResult = tertiary.commonizeWith(next)
|
||||
|
||||
// Note: don't call commonizeWith() functions in return statement to avoid short-circuiting!
|
||||
return primaryResult || secondaryResult || tertiaryResult
|
||||
return primaryResult || secondaryResult
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,9 +89,6 @@ private class TypeAliasLiftingUpCommonizer(classifiers: CirKnownClassifiers) : A
|
||||
)
|
||||
}
|
||||
|
||||
val resultOrNull: CirTypeAlias?
|
||||
get() = if (hasResult) commonizationResult() else null
|
||||
|
||||
override fun initialize(first: CirTypeAlias) {
|
||||
name = first.name
|
||||
}
|
||||
@@ -106,43 +98,3 @@ private class TypeAliasLiftingUpCommonizer(classifiers: CirKnownClassifiers) : A
|
||||
&& underlyingType.commonizeWith(next.underlyingType)
|
||||
&& visibility.commonizeWith(next)
|
||||
}
|
||||
|
||||
private class TypeAliasExpectClassCommonizer : AbstractStandardCommonizer<CirTypeAlias, CirClass>() {
|
||||
private lateinit var name: CirName
|
||||
private val classVisibility = VisibilityCommonizer.equalizing()
|
||||
|
||||
override fun commonizationResult(): CirClass = CirClass.create(
|
||||
annotations = emptyList(),
|
||||
name = name,
|
||||
typeParameters = emptyList(),
|
||||
visibility = classVisibility.result,
|
||||
modality = Modality.FINAL,
|
||||
kind = ClassKind.CLASS,
|
||||
companion = null,
|
||||
isCompanion = false,
|
||||
isData = false,
|
||||
isValue = false,
|
||||
isInner = false,
|
||||
isExternal = false
|
||||
)
|
||||
|
||||
override fun initialize(first: CirTypeAlias) {
|
||||
name = first.name
|
||||
}
|
||||
|
||||
override fun doCommonizeWith(next: CirTypeAlias): Boolean {
|
||||
if (next.typeParameters.isNotEmpty())
|
||||
return false // TAs with declared type parameters can't be commonized
|
||||
|
||||
val underlyingType = next.underlyingType as? CirClassType ?: return false // right-hand side could have only class
|
||||
return hasNoArguments(underlyingType) // TAs with functional types or types with arguments at the right-hand side can't be commonized
|
||||
&& classVisibility.commonizeWith(underlyingType) // the visibilities of the right-hand classes should be equal
|
||||
}
|
||||
|
||||
private tailrec fun hasNoArguments(type: CirClassType?): Boolean =
|
||||
when {
|
||||
type == null -> true
|
||||
type.arguments.isNotEmpty() -> false
|
||||
else -> hasNoArguments(type.outerType)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.commonizer.core
|
||||
import org.jetbrains.kotlin.commonizer.cir.*
|
||||
import org.jetbrains.kotlin.commonizer.core.CommonizedTypeAliasAnswer.Companion.FAILURE_MISSING_IN_SOME_TARGET
|
||||
import org.jetbrains.kotlin.commonizer.core.CommonizedTypeAliasAnswer.Companion.SUCCESS_FROM_DEPENDENCY_LIBRARY
|
||||
import org.jetbrains.kotlin.commonizer.core.CommonizedTypeAliasAnswer.Companion.create
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers
|
||||
import org.jetbrains.kotlin.commonizer.utils.isUnderKotlinNativeSyntheticPackages
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
@@ -203,16 +204,9 @@ private fun commonizeClass(classId: CirEntityId, classifiers: CirKnownClassifier
|
||||
return true
|
||||
}
|
||||
|
||||
return when (val node = classifiers.commonizedNodes.classNode(classId)) {
|
||||
null -> {
|
||||
// No node means that the type alias was not subject for commonization. It is missing in some target(s) => not commonized.
|
||||
false
|
||||
}
|
||||
else -> {
|
||||
// Common declaration in node is not null -> successfully commonized.
|
||||
(node.commonDeclaration() != null)
|
||||
}
|
||||
}
|
||||
// Looking for a a node that provides a non-null (successfully commonized) classifier declaration
|
||||
return (classifiers.commonizedNodes.classNode(classId)?.commonDeclaration?.invoke()
|
||||
?: classifiers.commonizedNodes.typeAliasNode(classId)?.commonDeclaration?.invoke()) != null
|
||||
}
|
||||
|
||||
private fun commonizeTypeAlias(typeAliasId: CirEntityId, classifiers: CirKnownClassifiers): CommonizedTypeAliasAnswer {
|
||||
@@ -221,16 +215,14 @@ private fun commonizeTypeAlias(typeAliasId: CirEntityId, classifiers: CirKnownCl
|
||||
return SUCCESS_FROM_DEPENDENCY_LIBRARY
|
||||
}
|
||||
|
||||
return when (val node = classifiers.commonizedNodes.typeAliasNode(typeAliasId)) {
|
||||
null -> {
|
||||
// No node means that the type alias was not subject for commonization. It is missing in some target(s) => not commonized.
|
||||
FAILURE_MISSING_IN_SOME_TARGET
|
||||
}
|
||||
else -> {
|
||||
// Common declaration in node is not null -> successfully commonized.
|
||||
CommonizedTypeAliasAnswer.create(node.commonDeclaration())
|
||||
}
|
||||
val typeAliasNode = classifiers.commonizedNodes.typeAliasNode(typeAliasId)
|
||||
val classNode = classifiers.commonizedNodes.classNode(typeAliasId)
|
||||
|
||||
if (typeAliasNode == null && classNode == null) {
|
||||
return FAILURE_MISSING_IN_SOME_TARGET
|
||||
}
|
||||
|
||||
return create(typeAliasNode?.commonDeclaration?.invoke() ?: classNode?.commonDeclaration?.invoke())
|
||||
}
|
||||
|
||||
private class CommonizedTypeAliasAnswer(val commonized: Boolean, val commonClassifier: CirClassifier?) {
|
||||
|
||||
@@ -18,8 +18,7 @@ internal tailrec fun computeSuitableUnderlyingType(
|
||||
return when (underlyingType) {
|
||||
is CirClassType -> underlyingType.withCommonizedArguments(classifiers)
|
||||
is CirTypeAliasType -> if (classifiers.commonDependencies.hasClassifier(underlyingType.classifierId))
|
||||
underlyingType.withCommonizedArguments(classifiers)
|
||||
else
|
||||
underlyingType.withCommonizedArguments(classifiers) else
|
||||
computeSuitableUnderlyingType(classifiers, underlyingType.underlyingType)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ import org.jetbrains.kotlin.commonizer.mergedtree.CirNode.Companion.indexOfCommo
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirNode.Companion.targetIndices
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirRootNode
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirTreeSerializer.serializeSingleTarget
|
||||
import org.jetbrains.kotlin.commonizer.transformer.Checked.Companion.invoke
|
||||
import org.jetbrains.kotlin.commonizer.transformer.InlineTypeAliasCirNodeTransformer
|
||||
import org.jetbrains.kotlin.commonizer.tree.CirTreeRoot
|
||||
import org.jetbrains.kotlin.commonizer.tree.assembleCirTree
|
||||
import org.jetbrains.kotlin.commonizer.tree.deserializeCirTree
|
||||
@@ -50,6 +52,7 @@ private fun commonize(
|
||||
)
|
||||
|
||||
val mergedTree = merge(storageManager, classifiers, cirTrees) ?: return null
|
||||
InlineTypeAliasCirNodeTransformer(storageManager, classifiers).invoke(mergedTree)
|
||||
mergedTree.accept(CommonizationVisitor(classifiers, mergedTree), Unit)
|
||||
parameters.logProgress("Commonized declarations for $target")
|
||||
|
||||
|
||||
+37
@@ -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.commonizer.mergedtree
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirDeclaration
|
||||
import org.jetbrains.kotlin.storage.NullableLazyValue
|
||||
|
||||
|
||||
internal fun interface CommonizerCondition {
|
||||
|
||||
fun allowCommonization(): Boolean
|
||||
|
||||
infix fun and(other: CommonizerCondition) = CommonizerCondition { allowCommonization() && other.allowCommonization() }
|
||||
|
||||
companion object Factory {
|
||||
fun none(): CommonizerCondition = NoneCommonizerCondition
|
||||
|
||||
fun nodeIsNotCommonized(node: CirNode<*, *>) = CommonizerCondition { node.commonDeclaration() == null }
|
||||
|
||||
fun parent(parent: CirNode<*, *>): ParentNodeCommonizerCondition = ParentNodeCommonizerCondition(parent.commonDeclaration)
|
||||
|
||||
fun parent(parent: CirNode<*, *>?): CommonizerCondition = if (parent == null) none() else parent(parent)
|
||||
}
|
||||
}
|
||||
|
||||
private object NoneCommonizerCondition : CommonizerCondition {
|
||||
override fun allowCommonization(): Boolean = true
|
||||
}
|
||||
|
||||
internal class ParentNodeCommonizerCondition(
|
||||
private val parentNodeCommonDeclaration: NullableLazyValue<CirDeclaration>
|
||||
) : CommonizerCondition {
|
||||
override fun allowCommonization(): Boolean = parentNodeCommonDeclaration() != null
|
||||
}
|
||||
@@ -20,6 +20,7 @@ internal fun buildRootNode(
|
||||
): CirRootNode = buildNode(
|
||||
storageManager = storageManager,
|
||||
size = size,
|
||||
commonizerCondition = CommonizerCondition.none(),
|
||||
commonizerProducer = ::RootCommonizer,
|
||||
nodeProducer = ::CirRootNode
|
||||
)
|
||||
@@ -30,6 +31,7 @@ internal fun buildModuleNode(
|
||||
): CirModuleNode = buildNode(
|
||||
storageManager = storageManager,
|
||||
size = size,
|
||||
commonizerCondition = CommonizerCondition.none(),
|
||||
commonizerProducer = ::ModuleCommonizer,
|
||||
nodeProducer = ::CirModuleNode
|
||||
)
|
||||
@@ -40,6 +42,7 @@ internal fun buildPackageNode(
|
||||
): CirPackageNode = buildNode(
|
||||
storageManager = storageManager,
|
||||
size = size,
|
||||
commonizerCondition = CommonizerCondition.none(),
|
||||
commonizerProducer = ::PackageCommonizer,
|
||||
nodeProducer = ::CirPackageNode
|
||||
)
|
||||
@@ -48,11 +51,11 @@ internal fun buildPropertyNode(
|
||||
storageManager: StorageManager,
|
||||
size: Int,
|
||||
classifiers: CirKnownClassifiers,
|
||||
parentCommonDeclaration: NullableLazyValue<*>?
|
||||
condition: CommonizerCondition = CommonizerCondition.none(),
|
||||
): CirPropertyNode = buildNode(
|
||||
storageManager = storageManager,
|
||||
size = size,
|
||||
parentCommonDeclaration = parentCommonDeclaration,
|
||||
commonizerCondition = condition,
|
||||
commonizerProducer = { PropertyCommonizer(classifiers) },
|
||||
nodeProducer = ::CirPropertyNode
|
||||
)
|
||||
@@ -61,11 +64,11 @@ internal fun buildFunctionNode(
|
||||
storageManager: StorageManager,
|
||||
size: Int,
|
||||
classifiers: CirKnownClassifiers,
|
||||
parentCommonDeclaration: NullableLazyValue<*>?
|
||||
condition: CommonizerCondition = CommonizerCondition.none(),
|
||||
): CirFunctionNode = buildNode(
|
||||
storageManager = storageManager,
|
||||
size = size,
|
||||
parentCommonDeclaration = parentCommonDeclaration,
|
||||
commonizerCondition = condition,
|
||||
commonizerProducer = { FunctionCommonizer(classifiers) },
|
||||
nodeProducer = ::CirFunctionNode
|
||||
)
|
||||
@@ -74,12 +77,12 @@ internal fun buildClassNode(
|
||||
storageManager: StorageManager,
|
||||
size: Int,
|
||||
classifiers: CirKnownClassifiers,
|
||||
parentCommonDeclaration: NullableLazyValue<*>?,
|
||||
condition: CommonizerCondition = CommonizerCondition.none(),
|
||||
classId: CirEntityId
|
||||
): CirClassNode = buildNode(
|
||||
storageManager = storageManager,
|
||||
size = size,
|
||||
parentCommonDeclaration = parentCommonDeclaration,
|
||||
commonizerCondition = condition,
|
||||
commonizerProducer = { ClassCommonizer(classifiers) },
|
||||
recursionMarker = CirClassRecursionMarker,
|
||||
nodeProducer = { targetDeclarations, commonDeclaration ->
|
||||
@@ -89,15 +92,16 @@ internal fun buildClassNode(
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
internal fun buildClassConstructorNode(
|
||||
storageManager: StorageManager,
|
||||
size: Int,
|
||||
classifiers: CirKnownClassifiers,
|
||||
parentCommonDeclaration: NullableLazyValue<*>?
|
||||
condition: ParentNodeCommonizerCondition,
|
||||
): CirClassConstructorNode = buildNode(
|
||||
storageManager = storageManager,
|
||||
size = size,
|
||||
parentCommonDeclaration = parentCommonDeclaration,
|
||||
commonizerCondition = condition,
|
||||
commonizerProducer = { ClassConstructorCommonizer(classifiers) },
|
||||
nodeProducer = ::CirClassConstructorNode
|
||||
)
|
||||
@@ -110,6 +114,7 @@ internal fun buildTypeAliasNode(
|
||||
): CirTypeAliasNode = buildNode(
|
||||
storageManager = storageManager,
|
||||
size = size,
|
||||
commonizerCondition = CommonizerCondition.none(),
|
||||
commonizerProducer = { TypeAliasCommonizer(classifiers) },
|
||||
recursionMarker = CirClassifierRecursionMarker,
|
||||
nodeProducer = { targetDeclarations, commonDeclaration ->
|
||||
@@ -122,14 +127,14 @@ internal fun buildTypeAliasNode(
|
||||
private fun <T : CirDeclaration, R : CirDeclaration, N : CirNode<T, R>> buildNode(
|
||||
storageManager: StorageManager,
|
||||
size: Int,
|
||||
parentCommonDeclaration: NullableLazyValue<*>? = null,
|
||||
commonizerCondition: CommonizerCondition,
|
||||
commonizerProducer: () -> Commonizer<T, R>,
|
||||
recursionMarker: R? = null,
|
||||
nodeProducer: (CommonizedGroup<T>, NullableLazyValue<R>) -> N
|
||||
): N {
|
||||
val targetDeclarations = CommonizedGroup<T>(size)
|
||||
|
||||
val commonComputable = { commonize(parentCommonDeclaration, targetDeclarations, commonizerProducer()) }
|
||||
val commonComputable = { commonize(commonizerCondition, targetDeclarations, commonizerProducer()) }
|
||||
|
||||
val commonLazyValue = if (recursionMarker != null)
|
||||
storageManager.createRecursionTolerantNullableLazyValue(commonComputable, recursionMarker)
|
||||
@@ -153,14 +158,13 @@ internal fun <T : Any, R> commonize(
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
private inline fun <T : Any, R> commonize(
|
||||
parentCommonDeclaration: NullableLazyValue<*>?,
|
||||
commonizerCondition: CommonizerCondition,
|
||||
targetDeclarations: CommonizedGroup<T>,
|
||||
commonizer: Commonizer<T, R>
|
||||
): R? {
|
||||
if (parentCommonDeclaration != null && parentCommonDeclaration.invoke() == null) {
|
||||
// don't commonize declaration if it's parent failed to commonize
|
||||
return null
|
||||
if (commonizerCondition.allowCommonization()) {
|
||||
return commonize(targetDeclarations, commonizer)
|
||||
}
|
||||
|
||||
return commonize(targetDeclarations, commonizer)
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -143,6 +143,7 @@ private class CirTreeSerializationVisitor(
|
||||
classContext: CirTreeSerializationContext
|
||||
): KmClass? {
|
||||
val cirClass = classContext.get<CirClass>(node) ?: return null
|
||||
|
||||
val classTypeParametersCount = cirClass.typeParameters.size
|
||||
val fullClassName = classContext.currentPath.toString()
|
||||
|
||||
@@ -403,7 +404,8 @@ internal data class CirTreeSerializationContext(
|
||||
}
|
||||
|
||||
inline fun <reified T : CirDeclaration> get(node: CirNode<*, *>): T? {
|
||||
return (if (isCommon) node.commonDeclaration() else node.targetDeclarations[targetIndex]) as T?
|
||||
return ((if (isCommon) node.commonDeclaration() else node.targetDeclarations[targetIndex]) as T?)
|
||||
.takeIf { it !is ArtificialCirDeclaration }
|
||||
}
|
||||
|
||||
inline fun <reified T : CirDeclaration> get(node: CirNodeWithLiftingUp<*, *>): T? {
|
||||
@@ -411,7 +413,7 @@ internal data class CirTreeSerializationContext(
|
||||
isCommon -> node.commonDeclaration() as T?
|
||||
node.isLiftedUp -> null
|
||||
else -> node.targetDeclarations[targetIndex] as T?
|
||||
}
|
||||
}.takeIf { it !is ArtificialCirDeclaration }
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.transformer
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.cir.ArtificialCirDeclaration
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.*
|
||||
|
||||
internal data class CirDeclarationCount(
|
||||
val artificialNodeCount: Int,
|
||||
val nonArtificialNodeCount: Int
|
||||
)
|
||||
|
||||
internal data class MutableCirDeclarationCount(
|
||||
var artificialNodeCount: Int = 0,
|
||||
var nonArtificialNodeCount: Int = 0
|
||||
) {
|
||||
fun toCirDeclarationCount() = CirDeclarationCount(
|
||||
artificialNodeCount = artificialNodeCount,
|
||||
nonArtificialNodeCount = nonArtificialNodeCount
|
||||
)
|
||||
}
|
||||
|
||||
internal fun CirNode<*, *>.countCirDeclarations(): CirDeclarationCount {
|
||||
val counter = MutableCirDeclarationCount()
|
||||
accept(CirNodeCounterVisitor, counter)
|
||||
return counter.toCirDeclarationCount()
|
||||
}
|
||||
|
||||
private object CirNodeCounterVisitor : CirNodeVisitor<MutableCirDeclarationCount, Unit> {
|
||||
|
||||
private operator fun MutableCirDeclarationCount.plusAssign(node: CirNode<*, *>) {
|
||||
node.targetDeclarations.forEach { declaration ->
|
||||
if (declaration == null) return@forEach
|
||||
if (declaration is ArtificialCirDeclaration) artificialNodeCount++ else nonArtificialNodeCount++
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitRootNode(node: CirRootNode, data: MutableCirDeclarationCount) {
|
||||
data += node
|
||||
node.modules.forEach { (_, module) -> module.accept(this, data) }
|
||||
}
|
||||
|
||||
override fun visitModuleNode(node: CirModuleNode, data: MutableCirDeclarationCount) {
|
||||
data += node
|
||||
node.packages.forEach { (_, pkg) -> pkg.accept(this, data) }
|
||||
}
|
||||
|
||||
override fun visitPackageNode(node: CirPackageNode, data: MutableCirDeclarationCount) {
|
||||
data += node
|
||||
node.typeAliases.forEach { (_, typeAlias) -> typeAlias.accept(this, data) }
|
||||
node.properties.forEach { (_, property) -> property.accept(this, data) }
|
||||
node.functions.forEach { (_, function) -> function.accept(this, data) }
|
||||
node.classes.forEach { (_, clazz) -> clazz.accept(this, data) }
|
||||
}
|
||||
|
||||
override fun visitPropertyNode(node: CirPropertyNode, data: MutableCirDeclarationCount) {
|
||||
data += node
|
||||
}
|
||||
|
||||
override fun visitFunctionNode(node: CirFunctionNode, data: MutableCirDeclarationCount) {
|
||||
data += node
|
||||
}
|
||||
|
||||
override fun visitClassNode(node: CirClassNode, data: MutableCirDeclarationCount) {
|
||||
data += node
|
||||
node.properties.forEach { (_, property) -> property.accept(this, data) }
|
||||
node.functions.forEach { (_, function) -> function.accept(this, data) }
|
||||
node.constructors.forEach { (_, constructor) -> constructor.accept(this, data) }
|
||||
node.classes.forEach { (_, clazz) -> clazz.accept(this, data) }
|
||||
}
|
||||
|
||||
override fun visitClassConstructorNode(node: CirClassConstructorNode, data: MutableCirDeclarationCount) {
|
||||
data += node
|
||||
}
|
||||
|
||||
override fun visitTypeAliasNode(node: CirTypeAliasNode, data: MutableCirDeclarationCount) {
|
||||
data += node
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.transformer
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirRootNode
|
||||
|
||||
internal fun interface CirNodeTransformer {
|
||||
|
||||
sealed class Context {
|
||||
object Unchecked : Context()
|
||||
}
|
||||
|
||||
operator fun Context.invoke(root: CirRootNode)
|
||||
}
|
||||
|
||||
internal class Checked private constructor() : CirNodeTransformer.Context() {
|
||||
companion object {
|
||||
private val areAssertionsEnabled = this::class.java.desiredAssertionStatus()
|
||||
|
||||
operator fun CirNodeTransformer.invoke(cirRootNode: CirRootNode) {
|
||||
val context = if (areAssertionsEnabled) Checked() else Unchecked
|
||||
val declarationCountBefore = if (areAssertionsEnabled) cirRootNode.countCirDeclarations() else null
|
||||
|
||||
with(this) {
|
||||
context.invoke(cirRootNode)
|
||||
}
|
||||
|
||||
if (declarationCountBefore != null) {
|
||||
val declarationCountAfter = cirRootNode.countCirDeclarations()
|
||||
if (declarationCountAfter.nonArtificialNodeCount > declarationCountBefore.nonArtificialNodeCount) {
|
||||
throw AssertionError(
|
||||
"$this attached declarations not marked as artificial\n" +
|
||||
"Declaration Count before: $declarationCountBefore\n" +
|
||||
"Declaration Count after: $declarationCountAfter"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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.transformer
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.cir.*
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.*
|
||||
import org.jetbrains.kotlin.commonizer.transformer.CirNodeTransformer.Context
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
internal class InlineTypeAliasCirNodeTransformer(
|
||||
private val storageManager: StorageManager,
|
||||
private val classifiers: CirKnownClassifiers
|
||||
) : CirNodeTransformer {
|
||||
override fun Context.invoke(root: CirRootNode) {
|
||||
root.modules.values.forEach(::invoke)
|
||||
}
|
||||
|
||||
private operator fun invoke(module: CirModuleNode) {
|
||||
val classNodeIndex = ClassNodeIndex(module)
|
||||
|
||||
module.packages.values.forEach { packageNode ->
|
||||
packageNode.typeAliases.values.forEach { typeAliasNode ->
|
||||
val targetClassNode = classNodeIndex[typeAliasNode.id] ?: packageNode.createArtificialClassNode(typeAliasNode)
|
||||
inlineTypeAliasIfPossible(classNodeIndex, typeAliasNode, targetClassNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun inlineTypeAliasIfPossible(classes: ClassNodeIndex, fromTypeAliasNode: CirTypeAliasNode, intoClassNode: CirClassNode) {
|
||||
fromTypeAliasNode.targetDeclarations.forEachIndexed { targetIndex, typeAlias ->
|
||||
if (typeAlias != null) {
|
||||
inlineTypeAliasIfPossible(classes, typeAlias, intoClassNode, targetIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun inlineTypeAliasIfPossible(
|
||||
classes: ClassNodeIndex, fromTypeAlias: CirTypeAlias, intoClassNode: CirClassNode, targetIndex: Int
|
||||
) {
|
||||
if (fromTypeAlias.typeParameters.isNotEmpty()) {
|
||||
// Inlining parameterized TAs is not supported yet
|
||||
return
|
||||
}
|
||||
|
||||
if (fromTypeAlias.underlyingType.arguments.isNotEmpty() ||
|
||||
fromTypeAlias.underlyingType.run { this as? CirClassType }?.outerType?.arguments?.isNotEmpty() == true
|
||||
) {
|
||||
// Inlining TAs with parameterized underlying types is not supported yet
|
||||
return
|
||||
}
|
||||
|
||||
if (intoClassNode.targetDeclarations[targetIndex] != null) {
|
||||
// No empty spot to inline the type-alias into
|
||||
return
|
||||
}
|
||||
|
||||
val fromAliasedClassNode = classes[fromTypeAlias.expandedType.classifierId]
|
||||
|
||||
val intoArtificialClass = ArtificialAliasedCirClass(
|
||||
pointingTypeAlias = fromTypeAlias,
|
||||
pointedClass = fromAliasedClassNode?.targetDeclarations?.get(targetIndex) ?: fromTypeAlias.toArtificialCirClass()
|
||||
)
|
||||
|
||||
intoClassNode.targetDeclarations[targetIndex] = intoArtificialClass
|
||||
|
||||
if (fromAliasedClassNode != null && !fromTypeAlias.expandedType.isMarkedNullable) {
|
||||
inlineArtificialMembers(fromAliasedClassNode, intoClassNode, intoArtificialClass, targetIndex)
|
||||
}
|
||||
}
|
||||
|
||||
private fun inlineArtificialMembers(
|
||||
fromAliasedClassNode: CirClassNode,
|
||||
intoClassNode: CirClassNode,
|
||||
intoClass: CirClass,
|
||||
targetIndex: Int
|
||||
) {
|
||||
val targetSize = intoClassNode.targetDeclarations.size
|
||||
|
||||
fromAliasedClassNode.constructors.forEach { (key, aliasedConstructorNode) ->
|
||||
val aliasedConstructor = aliasedConstructorNode.targetDeclarations[targetIndex] ?: return@forEach
|
||||
intoClassNode.constructors.getOrPut(key) {
|
||||
buildClassConstructorNode(storageManager, targetSize, classifiers, CommonizerCondition.parent(intoClassNode))
|
||||
}.targetDeclarations[targetIndex] = aliasedConstructor.withContainingClass(intoClass).markedArtificial()
|
||||
}
|
||||
|
||||
fromAliasedClassNode.functions.forEach { (key, aliasedFunctionNode) ->
|
||||
val aliasedFunction = aliasedFunctionNode.targetDeclarations[targetIndex] ?: return@forEach
|
||||
intoClassNode.functions.getOrPut(key) {
|
||||
buildFunctionNode(storageManager, targetSize, classifiers, CommonizerCondition.parent(intoClassNode))
|
||||
}.targetDeclarations[targetIndex] = aliasedFunction.withContainingClass(intoClass).markedArtificial()
|
||||
}
|
||||
|
||||
fromAliasedClassNode.properties.forEach { (key, aliasedPropertyNode) ->
|
||||
val aliasedProperty = aliasedPropertyNode.targetDeclarations[targetIndex] ?: return@forEach
|
||||
intoClassNode.properties.getOrPut(key) {
|
||||
buildPropertyNode(storageManager, targetSize, classifiers, CommonizerCondition.parent(intoClassNode))
|
||||
}.targetDeclarations[targetIndex] = aliasedProperty.withContainingClass(intoClass).markedArtificial()
|
||||
}
|
||||
}
|
||||
|
||||
private fun CirPackageNode.createArtificialClassNode(typeAliasNode: CirTypeAliasNode): CirClassNode {
|
||||
val classNode = buildClassNode(
|
||||
storageManager = storageManager,
|
||||
size = typeAliasNode.targetDeclarations.size,
|
||||
classifiers = classifiers,
|
||||
// This artificial class node should only try to commonize if the package node is commonized
|
||||
// and if the original typeAliasNode cannot be commonized.
|
||||
// Therefore, this artificial class node acts as a fallback with the original type-alias being still the preferred
|
||||
// option for commonization
|
||||
condition = CommonizerCondition.parent(this) and CommonizerCondition.nodeIsNotCommonized(typeAliasNode),
|
||||
classId = typeAliasNode.id
|
||||
)
|
||||
this.classes[typeAliasNode.classifierName] = classNode
|
||||
return classNode
|
||||
}
|
||||
}
|
||||
|
||||
private typealias ClassNodeIndex = Map<CirEntityId, CirClassNode>
|
||||
|
||||
private fun ClassNodeIndex(module: CirModuleNode): ClassNodeIndex = module.packages.values
|
||||
.flatMap { pkg -> pkg.classes.values }
|
||||
.associateBy { clazz -> clazz.id }
|
||||
|
||||
private data class ArtificialAliasedCirClass(
|
||||
val pointingTypeAlias: CirTypeAlias,
|
||||
val pointedClass: CirClass
|
||||
) : CirClass by pointedClass, ArtificialCirDeclaration {
|
||||
override val name: CirName = pointingTypeAlias.name
|
||||
override var companion: CirName?
|
||||
get() = null
|
||||
set(_) = throw UnsupportedOperationException("Can't set companion on artificial class (pointed by $pointingTypeAlias)")
|
||||
}
|
||||
|
||||
private fun CirTypeAlias.toArtificialCirClass(): CirClass = CirClass.create(
|
||||
annotations = emptyList(), name = name, typeParameters = typeParameters,
|
||||
visibility = this.visibility, modality = Modality.FINAL, kind = ClassKind.CLASS,
|
||||
companion = null, isCompanion = false, isData = false, isValue = false, isInner = false, isExternal = false
|
||||
).also { it.supertypes = emptyList() }.markedArtificial()
|
||||
@@ -52,7 +52,7 @@ internal fun CirNodeWithMembers<*, *>.buildClass(
|
||||
context: TargetBuildingContext, treeClass: CirTreeClass, parent: CirNode<*, *>? = null
|
||||
) {
|
||||
val classNode = classes.getOrPut(treeClass.clazz.name) {
|
||||
buildClassNode(context.storageManager, context.targets, context.classifiers, parent?.commonDeclaration, treeClass.id)
|
||||
buildClassNode(context.storageManager, context.targets, context.classifiers, CommonizerCondition.parent(parent), treeClass.id)
|
||||
}
|
||||
classNode.targetDeclarations[context.targetIndex] = treeClass.clazz
|
||||
treeClass.functions.forEach { function -> classNode.buildFunction(context, function, classNode) }
|
||||
@@ -65,7 +65,7 @@ internal fun CirNodeWithMembers<*, *>.buildFunction(
|
||||
context: TargetBuildingContext, treeFunction: CirTreeFunction, parent: CirNode<*, *>? = null
|
||||
) {
|
||||
val functionNode = functions.getOrPut(treeFunction.approximationKey) {
|
||||
buildFunctionNode(context.storageManager, context.targets, context.classifiers, parent?.commonDeclaration)
|
||||
buildFunctionNode(context.storageManager, context.targets, context.classifiers, CommonizerCondition.parent(parent))
|
||||
}
|
||||
functionNode.targetDeclarations[context.targetIndex] = treeFunction.function
|
||||
}
|
||||
@@ -74,16 +74,16 @@ internal fun CirNodeWithMembers<*, *>.buildProperty(
|
||||
context: TargetBuildingContext, treeProperty: CirTreeProperty, parent: CirNode<*, *>? = null
|
||||
) {
|
||||
val propertyNode = properties.getOrPut(treeProperty.approximationKey) {
|
||||
buildPropertyNode(context.storageManager, context.targets, context.classifiers, parent?.commonDeclaration)
|
||||
buildPropertyNode(context.storageManager, context.targets, context.classifiers, CommonizerCondition.parent(parent))
|
||||
}
|
||||
propertyNode.targetDeclarations[context.targetIndex] = treeProperty.property
|
||||
}
|
||||
|
||||
internal fun CirClassNode.buildConstructor(
|
||||
context: TargetBuildingContext, treeConstructor: CirTreeClassConstructor, parent: CirNode<*, *>?
|
||||
context: TargetBuildingContext, treeConstructor: CirTreeClassConstructor, parent: CirNode<*, *>
|
||||
) {
|
||||
val constructorNode = constructors.getOrPut(treeConstructor.approximationKey) {
|
||||
buildClassConstructorNode(context.storageManager, context.targets, context.classifiers, parent?.commonDeclaration)
|
||||
buildClassConstructorNode(context.storageManager, context.targets, context.classifiers, CommonizerCondition.parent(parent))
|
||||
}
|
||||
constructorNode.targetDeclarations[context.targetIndex] = treeConstructor.constructor
|
||||
}
|
||||
@@ -94,4 +94,3 @@ internal fun CirPackageNode.buildTypeAlias(context: TargetBuildingContext, treeT
|
||||
}
|
||||
typeAliasNode.targetDeclarations[context.targetIndex] = treeTypeAlias.typeAlias
|
||||
}
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -1,5 +1,4 @@
|
||||
expect class A()
|
||||
|
||||
// Lifted up type aliases:
|
||||
typealias B = A // class at the RHS
|
||||
typealias C = A // TA at the RHS, expanded to the same class
|
||||
@@ -40,10 +39,11 @@ typealias U = A // same nullability of the RHS class
|
||||
|
||||
expect class V // different nullability of the RHS class
|
||||
typealias W = A // same nullability of the RHS TA
|
||||
expect class X // different nullability of the RHS TA
|
||||
typealias Y = V // TA at the RHS with the different nullability of own RHS
|
||||
|
||||
// Supertypes:
|
||||
expect class FILE : kotlinx.cinterop.CStructVar
|
||||
expect class FILE expect constructor(): kotlinx.cinterop.CStructVar
|
||||
|
||||
typealias uuid_t = kotlinx.cinterop.CArrayPointer<kotlinx.cinterop.UByteVar>
|
||||
typealias __darwin_uuid_t = kotlinx.cinterop.CArrayPointer<kotlinx.cinterop.UByteVar>
|
||||
|
||||
Vendored
+5
-5
@@ -6,18 +6,18 @@ public typealias E1 = A1
|
||||
protected typealias E2 = A1
|
||||
internal typealias E3 = A1
|
||||
|
||||
public expect class E4
|
||||
public expect class E4()
|
||||
|
||||
protected typealias F1 = A1
|
||||
|
||||
public expect class F2
|
||||
public expect class F3
|
||||
public expect class F2()
|
||||
public expect class F3()
|
||||
|
||||
internal typealias G1 = A1
|
||||
|
||||
public expect class G2
|
||||
public expect class G2()
|
||||
|
||||
public expect class H1
|
||||
public expect class H1()
|
||||
|
||||
public typealias I1 = A1
|
||||
public typealias I2 = B1
|
||||
|
||||
Vendored
+1
-1
@@ -19,4 +19,4 @@ expect class AnnotatedClass(value: String) {
|
||||
}
|
||||
typealias AnnotatedLiftedUpTypeAlias = AnnotatedClass
|
||||
|
||||
expect class AnnotatedNonLiftedUpTypeAlias
|
||||
expect class AnnotatedNonLiftedUpTypeAlias expect constructor(expect val value: String)
|
||||
|
||||
@@ -272,14 +272,6 @@ class TypeCommonizerTest : AbstractCommonizerTest<CirType, CirType>() {
|
||||
shouldFailOnFirstVariant = true
|
||||
)
|
||||
|
||||
@Test
|
||||
// why success: expect class/actual TAs
|
||||
fun taTypesInUserPackageWithDifferentClasses() = doTestSuccess(
|
||||
expected = mockClassType("org/sample/FooAlias"),
|
||||
mockTAType("org/sample/FooAlias") { mockClassType("org/sample/Foo") },
|
||||
mockTAType("org/sample/FooAlias") { mockClassType("org/sample/Bar") }
|
||||
)
|
||||
|
||||
@Test
|
||||
// why success: short-circuiting & lifting up
|
||||
fun multilevelTATypesInUserPackageWithSameNameAndRightHandSideClass1() = doTestSuccess(
|
||||
@@ -338,28 +330,6 @@ class TypeCommonizerTest : AbstractCommonizerTest<CirType, CirType>() {
|
||||
}
|
||||
)
|
||||
|
||||
@Test
|
||||
// why success: lifting up outer TA and expect class for inner TA
|
||||
fun multilevelTATypesInUserPackageWithSameNameAndRightHandSideClass4() = doTestSuccess(
|
||||
expected = mockTAType("org/sample/FooAlias") {
|
||||
mockTAType("org/sample/FooAliasL2") {
|
||||
mockClassType("org/sample/Foo")
|
||||
}
|
||||
},
|
||||
|
||||
mockTAType("org/sample/FooAlias") {
|
||||
mockTAType("org/sample/FooAliasL2") {
|
||||
mockClassType("org/sample/Bar")
|
||||
}
|
||||
},
|
||||
|
||||
mockTAType("org/sample/FooAlias") {
|
||||
mockTAType("org/sample/FooAliasL2") {
|
||||
mockClassType("org/sample/Baz")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@Test
|
||||
// why success: types with the same nullability are treated as equal
|
||||
fun taTypesInKotlinPackageWithSameNullability1() = doTestSuccess(
|
||||
@@ -432,30 +402,16 @@ class TypeCommonizerTest : AbstractCommonizerTest<CirType, CirType>() {
|
||||
fun taTypesInUserPackageWithDifferentNullability1() = doTestFailure(
|
||||
mockTAType("org/sample/FooAlias", nullable = false) { mockClassType("org/sample/Foo") },
|
||||
mockTAType("org/sample/FooAlias", nullable = false) { mockClassType("org/sample/Foo") },
|
||||
mockTAType("org/sample/FooAlias", nullable = true) { mockClassType("org/sample/Foo") }
|
||||
mockTAType("org/sample/FooAlias", nullable = true) { mockClassType("org/sample/Foo") },
|
||||
shouldFailOnFirstVariant = true
|
||||
)
|
||||
|
||||
@Test(expected = IllegalCommonizerStateException::class)
|
||||
fun taTypesInUserPackageWithDifferentNullability2() = doTestFailure(
|
||||
mockTAType("org/sample/FooAlias", nullable = true) { mockClassType("org/sample/Foo") },
|
||||
mockTAType("org/sample/FooAlias", nullable = true) { mockClassType("org/sample/Foo") },
|
||||
mockTAType("org/sample/FooAlias", nullable = false) { mockClassType("org/sample/Foo") }
|
||||
)
|
||||
|
||||
@Test
|
||||
// why success: nullability of underlying type does not matter if expect class/actual TAs created
|
||||
fun taTypesInUserPackageWithDifferentNullability3() = doTestSuccess(
|
||||
expected = mockClassType("org/sample/FooAlias"),
|
||||
mockTAType("org/sample/FooAlias") { mockClassType("org/sample/Foo", nullable = false) },
|
||||
mockTAType("org/sample/FooAlias") { mockClassType("org/sample/Foo", nullable = true) }
|
||||
)
|
||||
|
||||
@Test
|
||||
// why success: nullability of underlying type does not matter if expect class/actual TAs created
|
||||
fun taTypesInUserPackageWithDifferentNullability4() = doTestSuccess(
|
||||
expected = mockClassType("org/sample/FooAlias"),
|
||||
mockTAType("org/sample/FooAlias") { mockClassType("org/sample/Foo", nullable = true) },
|
||||
mockTAType("org/sample/FooAlias") { mockClassType("org/sample/Foo", nullable = false) }
|
||||
mockTAType("org/sample/FooAlias", nullable = false) { mockClassType("org/sample/Foo") },
|
||||
shouldFailOnFirstVariant = true
|
||||
)
|
||||
|
||||
private fun prepareCache(variants: Array<out CirClassOrTypeAliasType>) {
|
||||
@@ -469,7 +425,7 @@ class TypeCommonizerTest : AbstractCommonizerTest<CirType, CirType>() {
|
||||
storageManager = LockBasedStorageManager.NO_LOCKS,
|
||||
size = variants.size,
|
||||
classifiers = classifiers,
|
||||
parentCommonDeclaration = null,
|
||||
condition = CommonizerCondition.none(),
|
||||
classId = type.classifierId
|
||||
)
|
||||
}
|
||||
|
||||
+137
@@ -104,4 +104,141 @@ class HierarchicalClassAndTypeAliasCommonizationTest : AbstractInlineSourcesComm
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
fun `test follow typeAlias on both platforms`() {
|
||||
val result = commonize {
|
||||
outputTarget("(a, b)")
|
||||
simpleSingleSourceTarget(
|
||||
"a", """
|
||||
class A {
|
||||
val x: Int = 42
|
||||
}
|
||||
typealias X = A
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
simpleSingleSourceTarget(
|
||||
"b", """
|
||||
class B {
|
||||
val x: Int = 42
|
||||
}
|
||||
typealias X = B
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
result.assertCommonized(
|
||||
"(a, b)", """
|
||||
expect class X expect constructor() {
|
||||
expect val x: Int
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
fun `test follow exact same typeAlias on both platforms`() {
|
||||
val result = commonize {
|
||||
outputTarget("(a, b)")
|
||||
simpleSingleSourceTarget(
|
||||
"a", """
|
||||
class AB {
|
||||
val x: Int = 42
|
||||
}
|
||||
typealias X = AB
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
simpleSingleSourceTarget(
|
||||
"b", """
|
||||
class AB {
|
||||
val x: Int = 42
|
||||
}
|
||||
typealias X = AB
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
result.assertCommonized(
|
||||
"(a, b)", """
|
||||
expect class AB expect constructor() {
|
||||
expect val x: Int
|
||||
}
|
||||
typealias X = AB
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
fun `test aliased class with companion`() {
|
||||
val result = commonize {
|
||||
outputTarget("(a, b)")
|
||||
simpleSingleSourceTarget(
|
||||
"a", """
|
||||
class A {
|
||||
companion object
|
||||
}
|
||||
|
||||
typealias X = A
|
||||
""".trimIndent()
|
||||
)
|
||||
simpleSingleSourceTarget(
|
||||
"b", """
|
||||
class X {
|
||||
companion object
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
result.assertCommonized("(a, b)", """expect class X expect constructor()""")
|
||||
}
|
||||
|
||||
fun `test typeAlias with nullability`() {
|
||||
val result = commonize {
|
||||
outputTarget("(a, b)")
|
||||
simpleSingleSourceTarget(
|
||||
"a", """
|
||||
class A
|
||||
typealias X = A?
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
simpleSingleSourceTarget(
|
||||
"b", """
|
||||
class B
|
||||
typealias X = B
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
result.assertCommonized("(a, b)", """expect class X""")
|
||||
}
|
||||
|
||||
fun `test typeAlias chain with nullability`() {
|
||||
val result = commonize {
|
||||
outputTarget("(a, b)")
|
||||
simpleSingleSourceTarget(
|
||||
"a", """
|
||||
class AB
|
||||
typealias V = AB?
|
||||
typealias Y = V
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
simpleSingleSourceTarget(
|
||||
"b", """
|
||||
class AB
|
||||
typealias V = AB
|
||||
typealias Y = V
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
result.assertCommonized(
|
||||
"(a, b)", """
|
||||
expect class AB expect constructor()
|
||||
expect class V
|
||||
typealias Y = V
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -111,7 +111,7 @@ class HierarchicalTypeAliasCommonizationTest : AbstractInlineSourcesCommonizatio
|
||||
"(e,f)", """expect class x expect constructor()"""
|
||||
)
|
||||
|
||||
result.assertCommonized("((a,b), (c,d))", """expect class x""")
|
||||
result.assertCommonized("(((a,b), (c,d)), (e,f))", """expect class x""")
|
||||
result.assertCommonized("((a,b), (c,d))", """expect class x expect constructor()""")
|
||||
result.assertCommonized("(((a,b), (c,d)), (e,f))", """expect class x expect constructor()""")
|
||||
}
|
||||
}
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.transformer
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirModule
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirName
|
||||
import org.jetbrains.kotlin.commonizer.cir.markedArtificial
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.buildModuleNode
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.buildRootNode
|
||||
import org.jetbrains.kotlin.commonizer.transformer.Checked.Companion.invoke
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertIs
|
||||
|
||||
class RunTransformationTest {
|
||||
|
||||
private val storageManager = LockBasedStorageManager("test")
|
||||
|
||||
@Test
|
||||
fun `fails when attaching non-artificial declarations`() {
|
||||
val badTransformer = CirNodeTransformer { root ->
|
||||
root.modules[CirName.create("bad-module")] = buildModuleNode(storageManager, 1).also { moduleNode ->
|
||||
moduleNode.targetDeclarations[0] = CirModule.create(CirName.create("bad-module"))
|
||||
}
|
||||
}
|
||||
|
||||
val node = buildRootNode(storageManager, 0)
|
||||
assertFailsWith<AssertionError> { badTransformer(node) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when attaching non-artificial declarations`() {
|
||||
val goodTransformer = CirNodeTransformer { root ->
|
||||
assertIs<Checked>(this, "Expected 'Checked' context")
|
||||
|
||||
root.modules[CirName.create("artificial-module")] = buildModuleNode(storageManager, 1).also { moduleNode ->
|
||||
moduleNode.targetDeclarations[0] = CirModule.create(CirName.create("artificial-module")).markedArtificial()
|
||||
}
|
||||
}
|
||||
|
||||
val node = buildRootNode(storageManager, 0)
|
||||
goodTransformer(node)
|
||||
|
||||
assertEquals(CirName.create("artificial-module"), node.modules.values.single().targetDeclarations.single()?.name)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user