[Commonizer] Introduce metadata builder

This commit is contained in:
Dmitriy Dolovov
2020-07-08 14:39:41 +07:00
parent e28c1fd310
commit 2bcaf1fa63
12 changed files with 782 additions and 15 deletions
@@ -18,6 +18,16 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.types.*
object CirTypeFactory {
object StandardTypes {
val ANY: CirClassType = createClassType(
classId = ANY_CID,
outerType = null,
visibility = DescriptorVisibilities.PUBLIC,
arguments = emptyList(),
isMarkedNullable = false
)
}
private val classTypeInterner = Interner<CirClassType>()
private val typeAliasTypeInterner = Interner<CirTypeAliasType>()
private val typeParameterTypeInterner = Interner<CirTypeParameterType>()
@@ -7,10 +7,12 @@ package org.jetbrains.kotlin.descriptors.commonizer.core
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirClass
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirType
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirTypeFactory
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.*
import org.jetbrains.kotlin.descriptors.commonizer.utils.CommonizedGroup
import org.jetbrains.kotlin.descriptors.commonizer.utils.*
import org.jetbrains.kotlin.descriptors.commonizer.utils.compactMapNotNull
import org.jetbrains.kotlin.descriptors.commonizer.utils.internedClassId
import org.jetbrains.kotlin.name.ClassId
internal class CommonizationVisitor(
private val classifiers: CirKnownClassifiers,
@@ -97,7 +99,7 @@ internal class CommonizationVisitor(
}
// find out common (and commonized) supertypes
commonClass.commonizeSupertypes(node.collectCommonSupertypes())
commonClass.commonizeSupertypes(node.classId, node.collectCommonSupertypes())
}
}
@@ -110,7 +112,7 @@ internal class CommonizationVisitor(
if (commonClassifier is CirClass) {
// find out common (and commonized) supertypes
commonClassifier.commonizeSupertypes(node.collectCommonSupertypes())
commonClassifier.commonizeSupertypes(node.classId, node.collectCommonSupertypes())
}
}
@@ -142,10 +144,13 @@ internal class CommonizationVisitor(
return supertypesMap
}
private fun CirClass.commonizeSupertypes(supertypesMap: Map<CirType, CommonizedGroup<CirType>>?) {
private fun CirClass.commonizeSupertypes(
classId: ClassId,
supertypesMap: Map<CirType, CommonizedGroup<CirType>>?
) {
setSupertypes(
if (supertypesMap.isNullOrEmpty())
emptyList()
if (classId in SPECIAL_CLASS_WITHOUT_SUPERTYPES_CIDS) emptyList() else listOf(CirTypeFactory.StandardTypes.ANY)
else
supertypesMap.values.compactMapNotNull { supertypesGroup -> commonize(supertypesGroup, TypeCommonizer(classifiers)) }
)
@@ -93,7 +93,7 @@ private class TypeAliasLiftingUpCommonizer(classifiers: CirKnownClassifiers) : A
typeParameters = typeParameters.result,
visibility = visibility.result,
underlyingType = underlyingType,
expandedType = computeCommonizedExpandedType(underlyingType)
expandedType = computeExpandedType(underlyingType)
)
}
@@ -108,13 +108,6 @@ private class TypeAliasLiftingUpCommonizer(classifiers: CirKnownClassifiers) : A
typeParameters.commonizeWith(next.typeParameters)
&& underlyingType.commonizeWith(next.underlyingType)
&& visibility.commonizeWith(next)
private tailrec fun computeCommonizedExpandedType(underlyingType: CirClassOrTypeAliasType): CirClassType {
return when (underlyingType) {
is CirClassType -> underlyingType
is CirTypeAliasType -> computeCommonizedExpandedType(underlyingType.underlyingType)
}
}
}
private class TypeAliasExpectClassCommonizer : AbstractStandardCommonizer<CirTypeAlias, CirClass>() {
@@ -12,6 +12,13 @@ import org.jetbrains.kotlin.descriptors.commonizer.cir.CirTypeProjection
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirTypeFactory
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirKnownClassifiers
tailrec fun computeExpandedType(underlyingType: CirClassOrTypeAliasType): CirClassType {
return when (underlyingType) {
is CirClassType -> underlyingType
is CirTypeAliasType -> computeExpandedType(underlyingType.underlyingType)
}
}
internal tailrec fun computeSuitableUnderlyingType(
classifiers: CirKnownClassifiers,
underlyingType: CirClassOrTypeAliasType
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.commonizer.mergedtree
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirDeclaration
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirLiftedUpDeclaration
interface CirNodeWithLiftingUp<T : CirDeclaration, R : CirDeclaration> : CirNode<T, R> {
val isLiftedUp: Boolean
get() = (commonDeclaration() as? CirLiftedUpDeclaration)?.isLiftedUp == true
}
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.storage.NullableLazyValue
class CirPropertyNode(
override val targetDeclarations: CommonizedGroup<CirProperty>,
override val commonDeclaration: NullableLazyValue<CirProperty>
) : CirNode<CirProperty, CirProperty> {
) : CirNodeWithLiftingUp<CirProperty, CirProperty> {
override fun <T, R> accept(visitor: CirNodeVisitor<T, R>, data: T) =
visitor.visitPropertyNode(this, data)
@@ -15,7 +15,7 @@ class CirTypeAliasNode(
override val targetDeclarations: CommonizedGroup<CirTypeAlias>,
override val commonDeclaration: NullableLazyValue<CirClassifier>,
override val classId: ClassId
) : CirNodeWithClassId<CirTypeAlias, CirClassifier> {
) : CirNodeWithClassId<CirTypeAlias, CirClassifier>, CirNodeWithLiftingUp<CirTypeAlias, CirClassifier> {
override fun <T, R> accept(visitor: CirNodeVisitor<T, R>, data: T): R =
visitor.visitTypeAliasNode(this, data)
@@ -0,0 +1,357 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.commonizer.metadata
import kotlinx.metadata.*
import kotlinx.metadata.klib.*
import org.jetbrains.kotlin.backend.common.serialization.metadata.DynamicTypeDeserializer
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
import org.jetbrains.kotlin.descriptors.commonizer.cir.impl.CirValueParameterImpl
import org.jetbrains.kotlin.descriptors.commonizer.core.computeExpandedType
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.*
import org.jetbrains.kotlin.descriptors.commonizer.metadata.TypeAliasExpansion.*
import org.jetbrains.kotlin.descriptors.commonizer.utils.strip
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.types.Variance
internal fun CirModule.buildModule(
fragments: Collection<KmModuleFragment>
): KlibModuleMetadata = KlibModuleMetadata(
name = name.strip(),
fragments = fragments.toList(),
annotations = emptyList()
)
internal fun CirPackage.buildModuleFragment(
allClasses: Collection<KmClass>,
topLevelTypeAliases: Collection<KmTypeAlias>,
topLevelFunctions: Collection<KmFunction>,
topLevelProperties: Collection<KmProperty>
): KmModuleFragment = KmModuleFragment().also { fragment ->
fragment.fqName = fqName.asString()
allClasses.forEach {
fragment.classes += it
fragment.className += it.name
}
if (topLevelTypeAliases.isNotEmpty() || topLevelFunctions.isNotEmpty() || topLevelProperties.isNotEmpty()) {
fragment.pkg = KmPackage().also { pkg ->
pkg.fqName = fqName.asString()
pkg.typeAliases += topLevelTypeAliases
pkg.functions += topLevelFunctions
pkg.properties += topLevelProperties
}
}
}
internal fun addEmptyFragments(fragments: MutableCollection<KmModuleFragment>) {
val existingPackageFqNames: Set<String> = fragments.mapTo(HashSet()) { it.fqName!! }
val missingPackageFqNames: Set<String> = existingPackageFqNames.flatMapTo(HashSet()) { fqName ->
fqName.mapIndexedNotNull { index, ch ->
if (ch == '.') {
val parentFqName = fqName.substring(0, index)
if (parentFqName !in existingPackageFqNames)
return@mapIndexedNotNull parentFqName
}
null
}
}
missingPackageFqNames.forEach { fqName ->
fragments += KmModuleFragment().also { fragment ->
fragment.fqName = fqName
}
}
}
internal fun CirClass.buildClass(
context: VisitingContext,
className: ClassName,
directNestedClasses: Collection<KmClass>,
nestedConstructors: Collection<KmConstructor>,
nestedFunctions: Collection<KmFunction>,
nestedProperties: Collection<KmProperty>
): KmClass = KmClass().also { clazz ->
clazz.flags = classFlags(isExpect = context.isCommon)
annotations.mapTo(clazz.annotations) { it.buildAnnotation() }
typeParameters.buildTypeParameters(context, output = clazz.typeParameters)
clazz.name = className
clazz.constructors += nestedConstructors
clazz.functions += nestedFunctions
clazz.properties += nestedProperties
directNestedClasses.forEach { directNestedClass ->
val shortClassName = directNestedClass.name.substringAfterLast('.')
if (Flag.Class.IS_ENUM_ENTRY(directNestedClass.flags)) {
clazz.enumEntries += shortClassName
clazz.klibEnumEntries += KlibEnumEntry(name = shortClassName, annotations = directNestedClass.annotations)
} else {
clazz.nestedClasses += shortClassName
}
}
clazz.companionObject = companion?.asString()
supertypes.mapTo(clazz.supertypes) { it.buildType(context) }
}
internal fun linkSealedClassesWithSubclasses(packageFqName: FqName, classConsumer: ClassConsumer) {
if (classConsumer.allClasses.isEmpty() || classConsumer.sealedClasses.isEmpty()) return
val packageName = packageFqName.asString().replace('.', '/')
fun ClassName.isInSamePackage(): Boolean = substringBeforeLast('/', "") == packageName
val sealedClassesMap: Map<ClassName, KmClass> = classConsumer.sealedClasses.associateBy { it.name }
classConsumer.allClasses.forEach { clazz ->
clazz.supertypes.forEach supertype@{ supertype ->
val superclassName = (supertype.classifier as? KmClassifier.Class)?.name ?: return@supertype
if (!superclassName.isInSamePackage()) return@supertype
val sealedClass = sealedClassesMap[superclassName] ?: return@supertype
sealedClass.sealedSubclasses += clazz.name
}
}
}
internal fun CirClassConstructor.buildClassConstructor(
context: VisitingContext
): KmConstructor = KmConstructor(
flags = classConstructorFlags()
).also { constructor ->
annotations.mapTo(constructor.annotations) { it.buildAnnotation() }
valueParameters.mapTo(constructor.valueParameters) { it.buildValueParameter(context) }
}
internal fun CirTypeAlias.buildTypeAlias(
context: VisitingContext
): KmTypeAlias = KmTypeAlias(
flags = typeAliasFlags(),
name = name.asString()
).also { typeAlias ->
annotations.mapTo(typeAlias.annotations) { it.buildAnnotation() }
typeParameters.buildTypeParameters(context, output = typeAlias.typeParameters)
typeAlias.underlyingType = underlyingType.buildType(context, expansion = ONLY_ABBREVIATIONS)
typeAlias.expandedType = underlyingType.buildType(context, expansion = FOR_TOP_LEVEL_TYPE)
}
internal fun CirProperty.buildProperty(
context: VisitingContext,
): KmProperty = KmProperty(
flags = propertyFlags(isExpect = context.isCommon && !isLiftedUp),
name = name.asString(),
getterFlags = getter?.propertyAccessorFlags(this, this) ?: NO_FLAGS,
setterFlags = setter?.let { setter -> setter.propertyAccessorFlags(setter, this) } ?: NO_FLAGS
).also { property ->
annotations.mapTo(property.annotations) { it.buildAnnotation() }
getter?.annotations?.mapTo(property.getterAnnotations) { it.buildAnnotation() }
setter?.annotations?.mapTo(property.setterAnnotations) { it.buildAnnotation() }
property.compileTimeValue = compileTimeInitializer?.takeIf { it !is NullValue }?.buildAnnotationArgument()
typeParameters.buildTypeParameters(context, output = property.typeParameters)
extensionReceiver?.let { receiver ->
// TODO nowhere to write receiver annotations, see KT-42490
property.receiverParameterType = receiver.type.buildType(context)
}
setter?.takeIf { !it.isDefault }?.let { setter ->
property.setterParameter = CirValueParameterImpl(
annotations = setter.parameterAnnotations,
name = SETTER_VALUE_NAME,
returnType = returnType,
varargElementType = null,
declaresDefaultValue = false,
isCrossinline = false,
isNoinline = false
).buildValueParameter(context)
}
property.returnType = returnType.buildType(context)
}
internal fun CirFunction.buildFunction(
context: VisitingContext,
): KmFunction = KmFunction(
flags = functionFlags(isExpect = context.isCommon),
name = name.asString()
).also { function ->
annotations.mapTo(function.annotations) { it.buildAnnotation() }
typeParameters.buildTypeParameters(context, output = function.typeParameters)
valueParameters.mapTo(function.valueParameters) { it.buildValueParameter(context) }
extensionReceiver?.let { receiver ->
// TODO nowhere to write receiver annotations, see KT-42490
function.receiverParameterType = receiver.type.buildType(context)
}
function.returnType = returnType.buildType(context)
}
private fun CirAnnotation.buildAnnotation(): KmAnnotation {
val arguments = LinkedHashMap<String, KmAnnotationArgument<*>>(constantValueArguments.size + annotationValueArguments.size, 1F)
constantValueArguments.forEach { (name: Name, value: ConstantValue<*>) ->
arguments[name.asString()] = value.buildAnnotationArgument()
}
annotationValueArguments.forEach { (name: Name, nested: CirAnnotation) ->
arguments[name.asString()] = KmAnnotationArgument.AnnotationValue(nested.buildAnnotation())
}
return KmAnnotation(
className = type.classifierId.asString(),
arguments = arguments
)
}
private fun ConstantValue<*>.buildAnnotationArgument(): KmAnnotationArgument<*> = when (this) {
is StringValue -> KmAnnotationArgument.StringValue(value)
is CharValue -> KmAnnotationArgument.CharValue(value)
is ByteValue -> KmAnnotationArgument.ByteValue(value)
is ShortValue -> KmAnnotationArgument.ShortValue(value)
is IntValue -> KmAnnotationArgument.IntValue(value)
is LongValue -> KmAnnotationArgument.LongValue(value)
is UByteValue -> KmAnnotationArgument.UByteValue(value)
is UShortValue -> KmAnnotationArgument.UShortValue(value)
is UIntValue -> KmAnnotationArgument.UIntValue(value)
is ULongValue -> KmAnnotationArgument.ULongValue(value)
is FloatValue -> KmAnnotationArgument.FloatValue(value)
is DoubleValue -> KmAnnotationArgument.DoubleValue(value)
is BooleanValue -> KmAnnotationArgument.BooleanValue(value)
is EnumValue -> KmAnnotationArgument.EnumValue(enumClassId.asString(), enumEntryName.asString())
is ArrayValue -> KmAnnotationArgument.ArrayValue(value.map { it.buildAnnotationArgument() })
else -> error("Unsupported annotation argument type: ${this::class.java}, $this")
}
private fun CirValueParameter.buildValueParameter(
context: VisitingContext
): KmValueParameter = KmValueParameter(
flags = valueParameterFlags(),
name = name.asString()
).also { parameter ->
annotations.mapTo(parameter.annotations) { it.buildAnnotation() }
parameter.type = returnType.buildType(context)
varargElementType?.let { varargElementType ->
parameter.varargElementType = varargElementType.buildType(context)
}
}
private fun List<CirTypeParameter>.buildTypeParameters(
context: VisitingContext,
output: MutableList<KmTypeParameter>
) {
mapIndexedTo(output) { index, cirTypeParameter ->
KmTypeParameter(
flags = cirTypeParameter.typeParameterFlags(),
name = cirTypeParameter.name.asString(),
id = context.typeParameterIndexOffset + index,
variance = cirTypeParameter.variance.buildVariance()
).also { parameter ->
cirTypeParameter.upperBounds.mapTo(parameter.upperBounds) { it.buildType(context) }
cirTypeParameter.annotations.mapTo(parameter.annotations) { it.buildAnnotation() }
}
}
}
private fun CirType.buildType(
context: VisitingContext,
expansion: TypeAliasExpansion = FOR_TOP_LEVEL_TYPE
): KmType = when (this) {
is CirClassType -> buildType(context, expansion)
is CirTypeAliasType -> buildType(context, expansion)
is CirTypeParameterType -> buildType()
is CirFlexibleType -> {
lowerBound.buildType(context, expansion).also {
it.flexibleTypeUpperBound = KmFlexibleTypeUpperBound(
type = upperBound.buildType(context, expansion),
typeFlexibilityId = DynamicTypeDeserializer.id
)
}
}
}
private fun CirTypeParameterType.buildType(): KmType =
KmType(typeFlags()).also { type ->
type.classifier = KmClassifier.TypeParameter(index)
}
private fun CirClassType.buildType(
context: VisitingContext,
expansion: TypeAliasExpansion
): KmType = KmType(typeFlags()).also { type ->
type.classifier = KmClassifier.Class(classifierId.asString())
arguments.mapTo(type.arguments) { it.buildArgument(context, expansion) }
outerType?.let { type.outerType = it.buildType(context, expansion) }
}
private fun CirTypeAliasType.buildType(
context: VisitingContext,
expansion: TypeAliasExpansion
): KmType = when (expansion) {
ONLY_ABBREVIATIONS -> buildAbbreviationType(context, expansion)
EXPANDED_WITHOUT_ABBREVIATIONS -> buildExpandedType(context, expansion)
FOR_TOP_LEVEL_TYPE -> buildExpandedType(context, EXPANDED_WITHOUT_ABBREVIATIONS).apply {
abbreviatedType = buildAbbreviationType(context, expansion)
}
FOR_NESTED_TYPE -> buildExpandedType(context, expansion).apply {
abbreviatedType = buildAbbreviationType(context, expansion)
}
}
private fun CirTypeAliasType.buildAbbreviationType(
context: VisitingContext,
expansion: TypeAliasExpansion
): KmType {
val abbreviationType = KmType(typeFlags())
abbreviationType.classifier = KmClassifier.TypeAlias(classifierId.asString())
arguments.mapTo(abbreviationType.arguments) { it.buildArgument(context, expansion) }
return abbreviationType
}
@Suppress("UnnecessaryVariable")
private fun CirTypeAliasType.buildExpandedType(
context: VisitingContext,
expansion: TypeAliasExpansion
): KmType {
val cirExpandedType = computeExpandedType(underlyingType)
val expandedType = cirExpandedType.buildType(context, expansion)
return expandedType
}
private fun CirTypeProjection.buildArgument(
context: VisitingContext,
expansion: TypeAliasExpansion
): KmTypeProjection {
val effectiveExpansion = if (expansion == FOR_TOP_LEVEL_TYPE) FOR_NESTED_TYPE else expansion
return when (this) {
CirStarTypeProjection -> KmTypeProjection.STAR
is CirTypeProjectionImpl -> KmTypeProjection(
variance = projectionKind.buildVariance(),
type = type.buildType(context, effectiveExpansion)
)
}
}
@Suppress("NOTHING_TO_INLINE")
private inline fun Variance.buildVariance() = when (this) {
Variance.INVARIANT -> KmVariance.INVARIANT
Variance.IN_VARIANCE -> KmVariance.IN
Variance.OUT_VARIANCE -> KmVariance.OUT
}
@Suppress("SpellCheckingInspection")
private enum class TypeAliasExpansion {
ONLY_ABBREVIATIONS,
EXPANDED_WITHOUT_ABBREVIATIONS,
FOR_TOP_LEVEL_TYPE,
FOR_NESTED_TYPE
}
private val SETTER_VALUE_NAME = Name.identifier("value")
@@ -0,0 +1,60 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.commonizer.metadata
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirNode
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirNode.Companion.indexOfCommon
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirNodeWithLiftingUp
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirRootNode
internal interface VisitingContext {
val targetIndex: Int
val target: CommonizerTarget
val isCommon: Boolean
val typeParameterIndexOffset: Int
val topLevelContext: VisitingContext
fun childContext(declarationWithTypeParameters: CirHasTypeParameters): VisitingContext {
val ownTypeParametersCount = declarationWithTypeParameters.typeParameters.size
return if (ownTypeParametersCount == 0) this else ChildVisitingContext(this, ownTypeParametersCount)
}
companion object {
fun newContext(rootNode: CirRootNode, targetIndex: Int): VisitingContext =
TopLevelVisitingContext(rootNode, targetIndex)
}
private class TopLevelVisitingContext(
rootNode: CirRootNode,
override val targetIndex: Int
) : VisitingContext {
override val isCommon = rootNode.indexOfCommon == targetIndex
override val target = get<CirRoot>(rootNode)!!.target
override val typeParameterIndexOffset get() = 0
override val topLevelContext: VisitingContext get() = this
}
private class ChildVisitingContext(
private val parent: VisitingContext,
typeParametersCount: Int
) : VisitingContext by parent {
override val typeParameterIndexOffset = parent.typeParameterIndexOffset + typeParametersCount
}
}
internal inline fun <reified T : CirDeclaration> VisitingContext.get(node: CirNodeWithLiftingUp<*, *>): T? {
return when {
isCommon -> node.commonDeclaration() as T?
node.isLiftedUp -> null
else -> node.targetDeclarations[targetIndex] as T?
}
}
internal inline fun <reified T : CirDeclaration> VisitingContext.get(node: CirNode<*, *>): T? {
return (if (isCommon) node.commonDeclaration() else node.targetDeclarations[targetIndex]) as T?
}
@@ -0,0 +1,179 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.commonizer.metadata
import kotlinx.metadata.Flag
import kotlinx.metadata.Flags
import kotlinx.metadata.flagsOf
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
import org.jetbrains.kotlin.resolve.constants.NullValue
internal const val NO_FLAGS: Flags = 0
internal fun CirFunction.functionFlags(isExpect: Boolean): Flags =
flagsOfNotNull(
hasAnnotationsFlag,
visibilityFlag,
modalityFlag,
memberKindFlag,
Flag.Function.HAS_NON_STABLE_PARAMETER_NAMES.takeIf { !hasStableParameterNames },
Flag.Function.IS_EXPECT.takeIf { isExpect }
) or modifiers.modifiersFlags
internal fun CirProperty.propertyFlags(isExpect: Boolean): Flags =
flagsOfNotNull(
hasAnnotationsFlag,
visibilityFlag,
modalityFlag,
memberKindFlag,
Flag.Property.HAS_GETTER.takeIf { getter != null },
Flag.Property.HAS_SETTER.takeIf { setter != null },
Flag.Property.IS_DELEGATED.takeIf { isDelegate },
Flag.Property.IS_EXPECT.takeIf { isExpect }
) or modifiersFlags
internal fun CirPropertyAccessor.propertyAccessorFlags(
visibilityHolder: CirHasVisibility,
modalityHolder: CirHasModality
): Flags {
return flagsOfNotNull(
hasAnnotationsFlag,
visibilityHolder.visibilityFlag,
modalityHolder.modalityFlag,
Flag.PropertyAccessor.IS_NOT_DEFAULT.takeIf { !isDefault },
Flag.PropertyAccessor.IS_EXTERNAL.takeIf { isExternal },
Flag.PropertyAccessor.IS_INLINE.takeIf { isInline }
)
}
internal fun CirClassConstructor.classConstructorFlags(): Flags =
flagsOfNotNull(
hasAnnotationsFlag,
visibilityFlag,
Flag.Constructor.IS_SECONDARY.takeIf { !isPrimary },
Flag.Constructor.HAS_NON_STABLE_PARAMETER_NAMES.takeIf { !hasStableParameterNames }
)
internal fun CirType.typeFlags(): Flags =
flagsOfNotNull(
nullableFlag,
//Flag.Type.IS_SUSPEND.takeIf { false }
)
internal fun CirTypeParameter.typeParameterFlags(): Flags =
flagsOfNotNull(
Flag.TypeParameter.IS_REIFIED.takeIf { isReified }
)
internal fun CirValueParameter.valueParameterFlags(): Flags =
flagsOfNotNull(
hasAnnotationsFlag,
Flag.ValueParameter.DECLARES_DEFAULT_VALUE.takeIf { declaresDefaultValue },
Flag.ValueParameter.IS_CROSSINLINE.takeIf { isCrossinline },
Flag.ValueParameter.IS_NOINLINE.takeIf { isNoinline }
)
internal fun CirClass.classFlags(isExpect: Boolean): Flags =
flagsOfNotNull(
hasAnnotationsFlag,
visibilityFlag,
modalityFlag,
classKindFlag,
Flag.Class.IS_COMPANION_OBJECT.takeIf { isCompanion },
Flag.Class.IS_INNER.takeIf { isInner },
Flag.Class.IS_DATA.takeIf { isData },
Flag.Class.IS_EXTERNAL.takeIf { isExternal },
Flag.Class.IS_EXPECT.takeIf { isExpect },
Flag.Class.IS_INLINE.takeIf { isInline },
//Flag.Class.IS_FUN.takeIf { false }
)
internal fun CirTypeAlias.typeAliasFlags(): Flags =
flagsOfNotNull(
hasAnnotationsFlag,
visibilityFlag
)
private inline val CirHasAnnotations.hasAnnotationsFlag: Flag?
get() = if (annotations.isNotEmpty()) Flag.Common.HAS_ANNOTATIONS else null
private inline val CirHasVisibility.visibilityFlag: Flag
get() = when (visibility) {
DescriptorVisibilities.PUBLIC -> Flag.Common.IS_PUBLIC
DescriptorVisibilities.PROTECTED -> Flag.Common.IS_PROTECTED
DescriptorVisibilities.INTERNAL -> Flag.Common.IS_INTERNAL
DescriptorVisibilities.PRIVATE -> Flag.Common.IS_PRIVATE
else -> error("Unexpected visibility: $this")
}
private inline val CirHasModality.modalityFlag: Flag
get() = when (modality) {
Modality.FINAL -> Flag.Common.IS_FINAL
Modality.ABSTRACT -> Flag.Common.IS_ABSTRACT
Modality.OPEN -> Flag.Common.IS_OPEN
Modality.SEALED -> Flag.Common.IS_SEALED
}
private inline val CirFunction.memberKindFlag: Flag
get() = when (kind) {
CallableMemberDescriptor.Kind.DECLARATION -> Flag.Function.IS_DECLARATION
CallableMemberDescriptor.Kind.FAKE_OVERRIDE -> Flag.Function.IS_FAKE_OVERRIDE
CallableMemberDescriptor.Kind.DELEGATION -> Flag.Function.IS_DELEGATION
CallableMemberDescriptor.Kind.SYNTHESIZED -> Flag.Function.IS_SYNTHESIZED
}
private inline val CirProperty.memberKindFlag: Flag
get() = when (kind) {
CallableMemberDescriptor.Kind.DECLARATION -> Flag.Property.IS_DECLARATION
CallableMemberDescriptor.Kind.FAKE_OVERRIDE -> Flag.Property.IS_FAKE_OVERRIDE
CallableMemberDescriptor.Kind.DELEGATION -> Flag.Property.IS_DELEGATION
CallableMemberDescriptor.Kind.SYNTHESIZED -> Flag.Property.IS_SYNTHESIZED
}
private inline val CirClass.classKindFlag: Flag
get() = when (kind) {
ClassKind.CLASS -> Flag.Class.IS_CLASS
ClassKind.INTERFACE -> Flag.Class.IS_INTERFACE
ClassKind.ENUM_CLASS -> Flag.Class.IS_ENUM_CLASS
ClassKind.ENUM_ENTRY -> Flag.Class.IS_ENUM_ENTRY
ClassKind.ANNOTATION_CLASS -> Flag.Class.IS_ANNOTATION_CLASS
ClassKind.OBJECT -> Flag.Class.IS_OBJECT
}
private inline val CirFunctionModifiers.modifiersFlags: Flags
get() = flagsOfNotNull(
Flag.Function.IS_OPERATOR.takeIf { isOperator },
Flag.Function.IS_INFIX.takeIf { isInfix },
Flag.Function.IS_INLINE.takeIf { isInline },
Flag.Function.IS_TAILREC.takeIf { isTailrec },
Flag.Function.IS_SUSPEND.takeIf { isSuspend },
Flag.Function.IS_EXTERNAL.takeIf { isExternal }
)
private inline val CirProperty.modifiersFlags: Flags
get() = flagsOfNotNull(
Flag.Property.IS_VAR.takeIf { isVar },
Flag.Property.IS_CONST.takeIf { isConst },
Flag.Property.HAS_CONSTANT.takeIf { compileTimeInitializer.takeIf { it !is NullValue } != null },
Flag.Property.IS_LATEINIT.takeIf { isLateInit },
Flag.Property.IS_EXTERNAL.takeIf { isExternal }
)
private inline val CirType.nullableFlag: Flag?
get() {
val isNullable = when (this) {
is CirSimpleType -> isMarkedNullable
is CirFlexibleType -> lowerBound.isMarkedNullable
}
return if (isNullable) Flag.Type.IS_NULLABLE else null
}
private fun flagsOfNotNull(vararg flags: Flag?): Flags = flagsOf(*listOfNotNull(*flags).toTypedArray())
@@ -0,0 +1,134 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.commonizer.metadata
import kotlinx.metadata.*
import kotlinx.metadata.klib.KlibModuleMetadata
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.*
import org.jetbrains.kotlin.utils.addToStdlib.cast
// TODO: add logging
@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
internal object MetadataBuilder {
fun build(node: CirRootNode, targetIndex: Int): Pair<CommonizerTarget, Collection<KlibModuleMetadata>> =
node.accept(MetadataBuildingVisitor(), VisitingContext.newContext(node, targetIndex)).cast()
private class MetadataBuildingVisitor : CirNodeVisitor<VisitingContext, Any?> {
private val classConsumer = ClassConsumer()
override fun visitRootNode(node: CirRootNode, context: VisitingContext): Pair<CommonizerTarget, Collection<KlibModuleMetadata>> {
val modules: Collection<KlibModuleMetadata> = buildMembers(context, node.modules)
return context.target to modules
}
override fun visitModuleNode(node: CirModuleNode, context: VisitingContext): KlibModuleMetadata? {
val cirModule = context.get<CirModule>(node) ?: return null
val fragments: MutableCollection<KmModuleFragment> = mutableListOf()
buildMembers(context, node.packages, destination = fragments)
addEmptyFragments(fragments)
return cirModule.buildModule(fragments)
}
override fun visitPackageNode(node: CirPackageNode, context: VisitingContext): KmModuleFragment? {
val cirPackage = context.get<CirPackage>(node) ?: return null
try {
buildMembers(context, node.classes, callback = classConsumer::consumeAll)
val topLevelTypeAliases = mutableListOf<KmTypeAlias>()
node.typeAliases.values.forEach { typeAliasNode ->
when (val classifier = typeAliasNode.accept(this, context)) {
null -> Unit
is KmClass -> classConsumer.consume(classifier)
is KmTypeAlias -> topLevelTypeAliases += classifier
else -> error("Unexpected classifier: ${classifier::class.java}, $classifier")
}
}
linkSealedClassesWithSubclasses(node.fqName, classConsumer)
val topLevelFunctions: Collection<KmFunction> = buildMembers(context, node.functions)
val topLevelProperties: Collection<KmProperty> = buildMembers(context, node.properties)
return cirPackage.buildModuleFragment(classConsumer.allClasses, topLevelTypeAliases, topLevelFunctions, topLevelProperties)
} finally {
// Important: clean-up class consumer every time when leaving package
classConsumer.reset()
}
}
override fun visitPropertyNode(node: CirPropertyNode, context: VisitingContext): KmProperty? {
return context.get<CirProperty>(node)?.buildProperty(context)
}
override fun visitFunctionNode(node: CirFunctionNode, context: VisitingContext): KmFunction? {
return context.get<CirFunction>(node)?.buildFunction(context)
}
override fun visitClassNode(node: CirClassNode, context: VisitingContext): KmClass? {
val cirClass = context.get<CirClass>(node) ?: return null
@Suppress("NAME_SHADOWING") val context = if (cirClass.isInner) context else context.topLevelContext
val classContext = context.childContext(cirClass)
val directNestedClasses = buildMembers(context = classContext, node.classes, callback = classConsumer::consumeAll)
val nestedConstructors: Collection<KmConstructor> = buildMembers(context = classContext, node.constructors)
val nestedFunctions: Collection<KmFunction> = buildMembers(context = classContext, node.functions)
val nestedProperties: Collection<KmProperty> = buildMembers(context = classContext, node.properties)
val className = node.classId.asString()
return cirClass.buildClass(context, className, directNestedClasses, nestedConstructors, nestedFunctions, nestedProperties)
}
override fun visitClassConstructorNode(node: CirClassConstructorNode, context: VisitingContext): KmConstructor? {
return context.get<CirClassConstructor>(node)?.buildClassConstructor(context)
}
override fun visitTypeAliasNode(node: CirTypeAliasNode, context: VisitingContext): Any? {
val cirClassifier = context.get<CirClassifier>(node) ?: return null
val className = node.classId.asString()
return when (cirClassifier) {
is CirTypeAlias -> cirClassifier.buildTypeAlias(context)
is CirClass -> cirClassifier.buildClass(context, className, emptyList(), emptyList(), emptyList(), emptyList())
else -> error("Unexpected CIR classifier: ${cirClassifier::class.java}, $cirClassifier")
}
}
private inline fun <reified N : CirNode<*, *>, reified M : Any> buildMembers(
context: VisitingContext,
cirMembersNodes: Map<*, N>,
destination: MutableCollection<M> = mutableListOf(),
callback: (Collection<M>) -> Unit = {}
): Collection<M> {
return cirMembersNodes.values.mapNotNullTo(destination) { it.accept(this, context) as M? }.also(callback)
}
}
}
internal class ClassConsumer {
private val _allClasses = mutableListOf<KmClass>()
private val _sealedClasses = mutableListOf<KmClass>()
val allClasses: Collection<KmClass> get() = _allClasses
val sealedClasses: Collection<KmClass> get() = _sealedClasses
fun consume(clazz: KmClass) {
_allClasses += clazz
if (Flag.Common.IS_SEALED(clazz.flags)) _sealedClasses += clazz
}
fun consumeAll(classes: Collection<KmClass>) = classes.forEach(::consume)
fun reset() {
_allClasses.clear()
_sealedClasses.clear()
}
}
@@ -16,6 +16,14 @@ import org.jetbrains.kotlin.serialization.konan.impl.ForwardDeclarationsFqNames
internal val DEPRECATED_ANNOTATION_FQN: FqName = FqName(Deprecated::class.java.name).intern()
internal val DEPRECATED_ANNOTATION_CID: ClassId = internedClassId(DEPRECATED_ANNOTATION_FQN)
internal val ANY_CID: ClassId = internedClassId(StandardNames.FqNames.any.toSafe().intern())
private val NOTHING_CID: ClassId = internedClassId(StandardNames.FqNames.nothing.toSafe().intern())
internal val SPECIAL_CLASS_WITHOUT_SUPERTYPES_CIDS = listOf(
ANY_CID,
NOTHING_CID
)
private val STANDARD_KOTLIN_PACKAGES = listOf(
StandardNames.BUILT_INS_PACKAGE_FQ_NAME.asString(),
"kotlinx"