[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
|
val isPrimary: Boolean
|
||||||
override val containingClass: CirContainingClass // non-nullable
|
override val containingClass: CirContainingClass // non-nullable
|
||||||
|
|
||||||
|
override fun withContainingClass(containingClass: CirContainingClass): CirClassConstructor
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun create(
|
inline fun create(
|
||||||
@@ -48,4 +50,8 @@ data class CirClassConstructorImpl(
|
|||||||
override var valueParameters: List<CirValueParameter>,
|
override var valueParameters: List<CirValueParameter>,
|
||||||
override var hasStableParameterNames: Boolean,
|
override var hasStableParameterNames: Boolean,
|
||||||
override val isPrimary: 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
|
val modality: Modality
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface CirMaybeCallableMemberOfClass {
|
interface CirMaybeCallableMemberOfClass {
|
||||||
val containingClass: CirContainingClass? // null assumes no containing class
|
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 {
|
interface CirFunction : CirFunctionOrProperty, CirCallableMemberWithParameters {
|
||||||
val modifiers: CirFunctionModifiers
|
val modifiers: CirFunctionModifiers
|
||||||
|
|
||||||
|
override fun withContainingClass(containingClass: CirContainingClass): CirFunction
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun create(
|
inline fun create(
|
||||||
@@ -57,4 +59,8 @@ data class CirFunctionImpl(
|
|||||||
override val returnType: CirType,
|
override val returnType: CirType,
|
||||||
override val kind: CallableMemberDescriptor.Kind,
|
override val kind: CallableMemberDescriptor.Kind,
|
||||||
override val modifiers: CirFunctionModifiers
|
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 delegateFieldAnnotations: List<CirAnnotation>
|
||||||
val compileTimeInitializer: CirConstantValue
|
val compileTimeInitializer: CirConstantValue
|
||||||
|
|
||||||
|
override fun withContainingClass(containingClass: CirContainingClass): CirProperty
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun create(
|
inline fun create(
|
||||||
@@ -90,4 +92,8 @@ data class CirPropertyImpl(
|
|||||||
) : CirProperty {
|
) : CirProperty {
|
||||||
// const property in "common" fragment is already lifted up
|
// const property in "common" fragment is already lifted up
|
||||||
override val isLiftedUp get() = isConst
|
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:
|
* Secondary (less optimistic) branch:
|
||||||
* - Make sure that all TAs are identical, so the resulting TA can be lifted up into "common" fragment.
|
* - 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>() {
|
class TypeAliasCommonizer(classifiers: CirKnownClassifiers) : AbstractStandardCommonizer<CirTypeAlias, CirClassifier>() {
|
||||||
private val primary = TypeAliasShortCircuitingCommonizer(classifiers)
|
private val primary = TypeAliasShortCircuitingCommonizer(classifiers)
|
||||||
private val secondary = TypeAliasLiftingUpCommonizer(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 initialize(first: CirTypeAlias) = Unit
|
||||||
|
|
||||||
override fun doCommonizeWith(next: CirTypeAlias): Boolean {
|
override fun doCommonizeWith(next: CirTypeAlias): Boolean {
|
||||||
val primaryResult = primary.commonizeWith(next)
|
val primaryResult = primary.commonizeWith(next)
|
||||||
val secondaryResult = secondary.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!
|
// 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) {
|
override fun initialize(first: CirTypeAlias) {
|
||||||
name = first.name
|
name = first.name
|
||||||
}
|
}
|
||||||
@@ -106,43 +98,3 @@ private class TypeAliasLiftingUpCommonizer(classifiers: CirKnownClassifiers) : A
|
|||||||
&& underlyingType.commonizeWith(next.underlyingType)
|
&& underlyingType.commonizeWith(next.underlyingType)
|
||||||
&& visibility.commonizeWith(next)
|
&& 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.cir.*
|
||||||
import org.jetbrains.kotlin.commonizer.core.CommonizedTypeAliasAnswer.Companion.FAILURE_MISSING_IN_SOME_TARGET
|
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.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.mergedtree.CirKnownClassifiers
|
||||||
import org.jetbrains.kotlin.commonizer.utils.isUnderKotlinNativeSyntheticPackages
|
import org.jetbrains.kotlin.commonizer.utils.isUnderKotlinNativeSyntheticPackages
|
||||||
import org.jetbrains.kotlin.descriptors.Visibility
|
import org.jetbrains.kotlin.descriptors.Visibility
|
||||||
@@ -203,16 +204,9 @@ private fun commonizeClass(classId: CirEntityId, classifiers: CirKnownClassifier
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return when (val node = classifiers.commonizedNodes.classNode(classId)) {
|
// Looking for a a node that provides a non-null (successfully commonized) classifier declaration
|
||||||
null -> {
|
return (classifiers.commonizedNodes.classNode(classId)?.commonDeclaration?.invoke()
|
||||||
// No node means that the type alias was not subject for commonization. It is missing in some target(s) => not commonized.
|
?: classifiers.commonizedNodes.typeAliasNode(classId)?.commonDeclaration?.invoke()) != null
|
||||||
false
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
// Common declaration in node is not null -> successfully commonized.
|
|
||||||
(node.commonDeclaration() != null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun commonizeTypeAlias(typeAliasId: CirEntityId, classifiers: CirKnownClassifiers): CommonizedTypeAliasAnswer {
|
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 SUCCESS_FROM_DEPENDENCY_LIBRARY
|
||||||
}
|
}
|
||||||
|
|
||||||
return when (val node = classifiers.commonizedNodes.typeAliasNode(typeAliasId)) {
|
val typeAliasNode = classifiers.commonizedNodes.typeAliasNode(typeAliasId)
|
||||||
null -> {
|
val classNode = classifiers.commonizedNodes.classNode(typeAliasId)
|
||||||
// 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
|
if (typeAliasNode == null && classNode == null) {
|
||||||
}
|
return FAILURE_MISSING_IN_SOME_TARGET
|
||||||
else -> {
|
|
||||||
// Common declaration in node is not null -> successfully commonized.
|
|
||||||
CommonizedTypeAliasAnswer.create(node.commonDeclaration())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return create(typeAliasNode?.commonDeclaration?.invoke() ?: classNode?.commonDeclaration?.invoke())
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CommonizedTypeAliasAnswer(val commonized: Boolean, val commonClassifier: CirClassifier?) {
|
private class CommonizedTypeAliasAnswer(val commonized: Boolean, val commonClassifier: CirClassifier?) {
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ internal tailrec fun computeSuitableUnderlyingType(
|
|||||||
return when (underlyingType) {
|
return when (underlyingType) {
|
||||||
is CirClassType -> underlyingType.withCommonizedArguments(classifiers)
|
is CirClassType -> underlyingType.withCommonizedArguments(classifiers)
|
||||||
is CirTypeAliasType -> if (classifiers.commonDependencies.hasClassifier(underlyingType.classifierId))
|
is CirTypeAliasType -> if (classifiers.commonDependencies.hasClassifier(underlyingType.classifierId))
|
||||||
underlyingType.withCommonizedArguments(classifiers)
|
underlyingType.withCommonizedArguments(classifiers) else
|
||||||
else
|
|
||||||
computeSuitableUnderlyingType(classifiers, underlyingType.underlyingType)
|
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.CirNode.Companion.targetIndices
|
||||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirRootNode
|
import org.jetbrains.kotlin.commonizer.mergedtree.CirRootNode
|
||||||
import org.jetbrains.kotlin.commonizer.metadata.CirTreeSerializer.serializeSingleTarget
|
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.CirTreeRoot
|
||||||
import org.jetbrains.kotlin.commonizer.tree.assembleCirTree
|
import org.jetbrains.kotlin.commonizer.tree.assembleCirTree
|
||||||
import org.jetbrains.kotlin.commonizer.tree.deserializeCirTree
|
import org.jetbrains.kotlin.commonizer.tree.deserializeCirTree
|
||||||
@@ -50,6 +52,7 @@ private fun commonize(
|
|||||||
)
|
)
|
||||||
|
|
||||||
val mergedTree = merge(storageManager, classifiers, cirTrees) ?: return null
|
val mergedTree = merge(storageManager, classifiers, cirTrees) ?: return null
|
||||||
|
InlineTypeAliasCirNodeTransformer(storageManager, classifiers).invoke(mergedTree)
|
||||||
mergedTree.accept(CommonizationVisitor(classifiers, mergedTree), Unit)
|
mergedTree.accept(CommonizationVisitor(classifiers, mergedTree), Unit)
|
||||||
parameters.logProgress("Commonized declarations for $target")
|
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(
|
): CirRootNode = buildNode(
|
||||||
storageManager = storageManager,
|
storageManager = storageManager,
|
||||||
size = size,
|
size = size,
|
||||||
|
commonizerCondition = CommonizerCondition.none(),
|
||||||
commonizerProducer = ::RootCommonizer,
|
commonizerProducer = ::RootCommonizer,
|
||||||
nodeProducer = ::CirRootNode
|
nodeProducer = ::CirRootNode
|
||||||
)
|
)
|
||||||
@@ -30,6 +31,7 @@ internal fun buildModuleNode(
|
|||||||
): CirModuleNode = buildNode(
|
): CirModuleNode = buildNode(
|
||||||
storageManager = storageManager,
|
storageManager = storageManager,
|
||||||
size = size,
|
size = size,
|
||||||
|
commonizerCondition = CommonizerCondition.none(),
|
||||||
commonizerProducer = ::ModuleCommonizer,
|
commonizerProducer = ::ModuleCommonizer,
|
||||||
nodeProducer = ::CirModuleNode
|
nodeProducer = ::CirModuleNode
|
||||||
)
|
)
|
||||||
@@ -40,6 +42,7 @@ internal fun buildPackageNode(
|
|||||||
): CirPackageNode = buildNode(
|
): CirPackageNode = buildNode(
|
||||||
storageManager = storageManager,
|
storageManager = storageManager,
|
||||||
size = size,
|
size = size,
|
||||||
|
commonizerCondition = CommonizerCondition.none(),
|
||||||
commonizerProducer = ::PackageCommonizer,
|
commonizerProducer = ::PackageCommonizer,
|
||||||
nodeProducer = ::CirPackageNode
|
nodeProducer = ::CirPackageNode
|
||||||
)
|
)
|
||||||
@@ -48,11 +51,11 @@ internal fun buildPropertyNode(
|
|||||||
storageManager: StorageManager,
|
storageManager: StorageManager,
|
||||||
size: Int,
|
size: Int,
|
||||||
classifiers: CirKnownClassifiers,
|
classifiers: CirKnownClassifiers,
|
||||||
parentCommonDeclaration: NullableLazyValue<*>?
|
condition: CommonizerCondition = CommonizerCondition.none(),
|
||||||
): CirPropertyNode = buildNode(
|
): CirPropertyNode = buildNode(
|
||||||
storageManager = storageManager,
|
storageManager = storageManager,
|
||||||
size = size,
|
size = size,
|
||||||
parentCommonDeclaration = parentCommonDeclaration,
|
commonizerCondition = condition,
|
||||||
commonizerProducer = { PropertyCommonizer(classifiers) },
|
commonizerProducer = { PropertyCommonizer(classifiers) },
|
||||||
nodeProducer = ::CirPropertyNode
|
nodeProducer = ::CirPropertyNode
|
||||||
)
|
)
|
||||||
@@ -61,11 +64,11 @@ internal fun buildFunctionNode(
|
|||||||
storageManager: StorageManager,
|
storageManager: StorageManager,
|
||||||
size: Int,
|
size: Int,
|
||||||
classifiers: CirKnownClassifiers,
|
classifiers: CirKnownClassifiers,
|
||||||
parentCommonDeclaration: NullableLazyValue<*>?
|
condition: CommonizerCondition = CommonizerCondition.none(),
|
||||||
): CirFunctionNode = buildNode(
|
): CirFunctionNode = buildNode(
|
||||||
storageManager = storageManager,
|
storageManager = storageManager,
|
||||||
size = size,
|
size = size,
|
||||||
parentCommonDeclaration = parentCommonDeclaration,
|
commonizerCondition = condition,
|
||||||
commonizerProducer = { FunctionCommonizer(classifiers) },
|
commonizerProducer = { FunctionCommonizer(classifiers) },
|
||||||
nodeProducer = ::CirFunctionNode
|
nodeProducer = ::CirFunctionNode
|
||||||
)
|
)
|
||||||
@@ -74,12 +77,12 @@ internal fun buildClassNode(
|
|||||||
storageManager: StorageManager,
|
storageManager: StorageManager,
|
||||||
size: Int,
|
size: Int,
|
||||||
classifiers: CirKnownClassifiers,
|
classifiers: CirKnownClassifiers,
|
||||||
parentCommonDeclaration: NullableLazyValue<*>?,
|
condition: CommonizerCondition = CommonizerCondition.none(),
|
||||||
classId: CirEntityId
|
classId: CirEntityId
|
||||||
): CirClassNode = buildNode(
|
): CirClassNode = buildNode(
|
||||||
storageManager = storageManager,
|
storageManager = storageManager,
|
||||||
size = size,
|
size = size,
|
||||||
parentCommonDeclaration = parentCommonDeclaration,
|
commonizerCondition = condition,
|
||||||
commonizerProducer = { ClassCommonizer(classifiers) },
|
commonizerProducer = { ClassCommonizer(classifiers) },
|
||||||
recursionMarker = CirClassRecursionMarker,
|
recursionMarker = CirClassRecursionMarker,
|
||||||
nodeProducer = { targetDeclarations, commonDeclaration ->
|
nodeProducer = { targetDeclarations, commonDeclaration ->
|
||||||
@@ -89,15 +92,16 @@ internal fun buildClassNode(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
internal fun buildClassConstructorNode(
|
internal fun buildClassConstructorNode(
|
||||||
storageManager: StorageManager,
|
storageManager: StorageManager,
|
||||||
size: Int,
|
size: Int,
|
||||||
classifiers: CirKnownClassifiers,
|
classifiers: CirKnownClassifiers,
|
||||||
parentCommonDeclaration: NullableLazyValue<*>?
|
condition: ParentNodeCommonizerCondition,
|
||||||
): CirClassConstructorNode = buildNode(
|
): CirClassConstructorNode = buildNode(
|
||||||
storageManager = storageManager,
|
storageManager = storageManager,
|
||||||
size = size,
|
size = size,
|
||||||
parentCommonDeclaration = parentCommonDeclaration,
|
commonizerCondition = condition,
|
||||||
commonizerProducer = { ClassConstructorCommonizer(classifiers) },
|
commonizerProducer = { ClassConstructorCommonizer(classifiers) },
|
||||||
nodeProducer = ::CirClassConstructorNode
|
nodeProducer = ::CirClassConstructorNode
|
||||||
)
|
)
|
||||||
@@ -110,6 +114,7 @@ internal fun buildTypeAliasNode(
|
|||||||
): CirTypeAliasNode = buildNode(
|
): CirTypeAliasNode = buildNode(
|
||||||
storageManager = storageManager,
|
storageManager = storageManager,
|
||||||
size = size,
|
size = size,
|
||||||
|
commonizerCondition = CommonizerCondition.none(),
|
||||||
commonizerProducer = { TypeAliasCommonizer(classifiers) },
|
commonizerProducer = { TypeAliasCommonizer(classifiers) },
|
||||||
recursionMarker = CirClassifierRecursionMarker,
|
recursionMarker = CirClassifierRecursionMarker,
|
||||||
nodeProducer = { targetDeclarations, commonDeclaration ->
|
nodeProducer = { targetDeclarations, commonDeclaration ->
|
||||||
@@ -122,14 +127,14 @@ internal fun buildTypeAliasNode(
|
|||||||
private fun <T : CirDeclaration, R : CirDeclaration, N : CirNode<T, R>> buildNode(
|
private fun <T : CirDeclaration, R : CirDeclaration, N : CirNode<T, R>> buildNode(
|
||||||
storageManager: StorageManager,
|
storageManager: StorageManager,
|
||||||
size: Int,
|
size: Int,
|
||||||
parentCommonDeclaration: NullableLazyValue<*>? = null,
|
commonizerCondition: CommonizerCondition,
|
||||||
commonizerProducer: () -> Commonizer<T, R>,
|
commonizerProducer: () -> Commonizer<T, R>,
|
||||||
recursionMarker: R? = null,
|
recursionMarker: R? = null,
|
||||||
nodeProducer: (CommonizedGroup<T>, NullableLazyValue<R>) -> N
|
nodeProducer: (CommonizedGroup<T>, NullableLazyValue<R>) -> N
|
||||||
): N {
|
): N {
|
||||||
val targetDeclarations = CommonizedGroup<T>(size)
|
val targetDeclarations = CommonizedGroup<T>(size)
|
||||||
|
|
||||||
val commonComputable = { commonize(parentCommonDeclaration, targetDeclarations, commonizerProducer()) }
|
val commonComputable = { commonize(commonizerCondition, targetDeclarations, commonizerProducer()) }
|
||||||
|
|
||||||
val commonLazyValue = if (recursionMarker != null)
|
val commonLazyValue = if (recursionMarker != null)
|
||||||
storageManager.createRecursionTolerantNullableLazyValue(commonComputable, recursionMarker)
|
storageManager.createRecursionTolerantNullableLazyValue(commonComputable, recursionMarker)
|
||||||
@@ -153,14 +158,13 @@ internal fun <T : Any, R> commonize(
|
|||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
private inline fun <T : Any, R> commonize(
|
private inline fun <T : Any, R> commonize(
|
||||||
parentCommonDeclaration: NullableLazyValue<*>?,
|
commonizerCondition: CommonizerCondition,
|
||||||
targetDeclarations: CommonizedGroup<T>,
|
targetDeclarations: CommonizedGroup<T>,
|
||||||
commonizer: Commonizer<T, R>
|
commonizer: Commonizer<T, R>
|
||||||
): R? {
|
): R? {
|
||||||
if (parentCommonDeclaration != null && parentCommonDeclaration.invoke() == null) {
|
if (commonizerCondition.allowCommonization()) {
|
||||||
// don't commonize declaration if it's parent failed to commonize
|
return commonize(targetDeclarations, commonizer)
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return commonize(targetDeclarations, commonizer)
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ private class CirTreeSerializationVisitor(
|
|||||||
classContext: CirTreeSerializationContext
|
classContext: CirTreeSerializationContext
|
||||||
): KmClass? {
|
): KmClass? {
|
||||||
val cirClass = classContext.get<CirClass>(node) ?: return null
|
val cirClass = classContext.get<CirClass>(node) ?: return null
|
||||||
|
|
||||||
val classTypeParametersCount = cirClass.typeParameters.size
|
val classTypeParametersCount = cirClass.typeParameters.size
|
||||||
val fullClassName = classContext.currentPath.toString()
|
val fullClassName = classContext.currentPath.toString()
|
||||||
|
|
||||||
@@ -403,7 +404,8 @@ internal data class CirTreeSerializationContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : CirDeclaration> get(node: CirNode<*, *>): T? {
|
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? {
|
inline fun <reified T : CirDeclaration> get(node: CirNodeWithLiftingUp<*, *>): T? {
|
||||||
@@ -411,7 +413,7 @@ internal data class CirTreeSerializationContext(
|
|||||||
isCommon -> node.commonDeclaration() as T?
|
isCommon -> node.commonDeclaration() as T?
|
||||||
node.isLiftedUp -> null
|
node.isLiftedUp -> null
|
||||||
else -> node.targetDeclarations[targetIndex] as T?
|
else -> node.targetDeclarations[targetIndex] as T?
|
||||||
}
|
}.takeIf { it !is ArtificialCirDeclaration }
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
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
|
context: TargetBuildingContext, treeClass: CirTreeClass, parent: CirNode<*, *>? = null
|
||||||
) {
|
) {
|
||||||
val classNode = classes.getOrPut(treeClass.clazz.name) {
|
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
|
classNode.targetDeclarations[context.targetIndex] = treeClass.clazz
|
||||||
treeClass.functions.forEach { function -> classNode.buildFunction(context, function, classNode) }
|
treeClass.functions.forEach { function -> classNode.buildFunction(context, function, classNode) }
|
||||||
@@ -65,7 +65,7 @@ internal fun CirNodeWithMembers<*, *>.buildFunction(
|
|||||||
context: TargetBuildingContext, treeFunction: CirTreeFunction, parent: CirNode<*, *>? = null
|
context: TargetBuildingContext, treeFunction: CirTreeFunction, parent: CirNode<*, *>? = null
|
||||||
) {
|
) {
|
||||||
val functionNode = functions.getOrPut(treeFunction.approximationKey) {
|
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
|
functionNode.targetDeclarations[context.targetIndex] = treeFunction.function
|
||||||
}
|
}
|
||||||
@@ -74,16 +74,16 @@ internal fun CirNodeWithMembers<*, *>.buildProperty(
|
|||||||
context: TargetBuildingContext, treeProperty: CirTreeProperty, parent: CirNode<*, *>? = null
|
context: TargetBuildingContext, treeProperty: CirTreeProperty, parent: CirNode<*, *>? = null
|
||||||
) {
|
) {
|
||||||
val propertyNode = properties.getOrPut(treeProperty.approximationKey) {
|
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
|
propertyNode.targetDeclarations[context.targetIndex] = treeProperty.property
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun CirClassNode.buildConstructor(
|
internal fun CirClassNode.buildConstructor(
|
||||||
context: TargetBuildingContext, treeConstructor: CirTreeClassConstructor, parent: CirNode<*, *>?
|
context: TargetBuildingContext, treeConstructor: CirTreeClassConstructor, parent: CirNode<*, *>
|
||||||
) {
|
) {
|
||||||
val constructorNode = constructors.getOrPut(treeConstructor.approximationKey) {
|
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
|
constructorNode.targetDeclarations[context.targetIndex] = treeConstructor.constructor
|
||||||
}
|
}
|
||||||
@@ -94,4 +94,3 @@ internal fun CirPackageNode.buildTypeAlias(context: TargetBuildingContext, treeT
|
|||||||
}
|
}
|
||||||
typeAliasNode.targetDeclarations[context.targetIndex] = treeTypeAlias.typeAlias
|
typeAliasNode.targetDeclarations[context.targetIndex] = treeTypeAlias.typeAlias
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+2
-2
@@ -1,5 +1,4 @@
|
|||||||
expect class A()
|
expect class A()
|
||||||
|
|
||||||
// Lifted up type aliases:
|
// Lifted up type aliases:
|
||||||
typealias B = A // class at the RHS
|
typealias B = A // class at the RHS
|
||||||
typealias C = A // TA at the RHS, expanded to the same class
|
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
|
expect class V // different nullability of the RHS class
|
||||||
typealias W = A // same nullability of the RHS TA
|
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
|
typealias Y = V // TA at the RHS with the different nullability of own RHS
|
||||||
|
|
||||||
// Supertypes:
|
// 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 uuid_t = kotlinx.cinterop.CArrayPointer<kotlinx.cinterop.UByteVar>
|
||||||
typealias __darwin_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
|
protected typealias E2 = A1
|
||||||
internal typealias E3 = A1
|
internal typealias E3 = A1
|
||||||
|
|
||||||
public expect class E4
|
public expect class E4()
|
||||||
|
|
||||||
protected typealias F1 = A1
|
protected typealias F1 = A1
|
||||||
|
|
||||||
public expect class F2
|
public expect class F2()
|
||||||
public expect class F3
|
public expect class F3()
|
||||||
|
|
||||||
internal typealias G1 = A1
|
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 I1 = A1
|
||||||
public typealias I2 = B1
|
public typealias I2 = B1
|
||||||
|
|||||||
Vendored
+1
-1
@@ -19,4 +19,4 @@ expect class AnnotatedClass(value: String) {
|
|||||||
}
|
}
|
||||||
typealias AnnotatedLiftedUpTypeAlias = AnnotatedClass
|
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
|
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
|
@Test
|
||||||
// why success: short-circuiting & lifting up
|
// why success: short-circuiting & lifting up
|
||||||
fun multilevelTATypesInUserPackageWithSameNameAndRightHandSideClass1() = doTestSuccess(
|
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
|
@Test
|
||||||
// why success: types with the same nullability are treated as equal
|
// why success: types with the same nullability are treated as equal
|
||||||
fun taTypesInKotlinPackageWithSameNullability1() = doTestSuccess(
|
fun taTypesInKotlinPackageWithSameNullability1() = doTestSuccess(
|
||||||
@@ -432,30 +402,16 @@ class TypeCommonizerTest : AbstractCommonizerTest<CirType, CirType>() {
|
|||||||
fun taTypesInUserPackageWithDifferentNullability1() = doTestFailure(
|
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 = 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)
|
@Test(expected = IllegalCommonizerStateException::class)
|
||||||
fun taTypesInUserPackageWithDifferentNullability2() = doTestFailure(
|
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 = 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") }
|
mockTAType("org/sample/FooAlias", nullable = false) { mockClassType("org/sample/Foo") },
|
||||||
)
|
shouldFailOnFirstVariant = true
|
||||||
|
|
||||||
@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) }
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun prepareCache(variants: Array<out CirClassOrTypeAliasType>) {
|
private fun prepareCache(variants: Array<out CirClassOrTypeAliasType>) {
|
||||||
@@ -469,7 +425,7 @@ class TypeCommonizerTest : AbstractCommonizerTest<CirType, CirType>() {
|
|||||||
storageManager = LockBasedStorageManager.NO_LOCKS,
|
storageManager = LockBasedStorageManager.NO_LOCKS,
|
||||||
size = variants.size,
|
size = variants.size,
|
||||||
classifiers = classifiers,
|
classifiers = classifiers,
|
||||||
parentCommonDeclaration = null,
|
condition = CommonizerCondition.none(),
|
||||||
classId = type.classifierId
|
classId = type.classifierId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+137
@@ -104,4 +104,141 @@ class HierarchicalClassAndTypeAliasCommonizationTest : AbstractInlineSourcesComm
|
|||||||
""".trimIndent()
|
""".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()"""
|
"(e,f)", """expect class x expect constructor()"""
|
||||||
)
|
)
|
||||||
|
|
||||||
result.assertCommonized("((a,b), (c,d))", """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""")
|
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