[Commonizer] Introduce metadata builder
This commit is contained in:
+10
@@ -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>()
|
||||
|
||||
+10
-5
@@ -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)) }
|
||||
)
|
||||
|
||||
+1
-8
@@ -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>() {
|
||||
|
||||
+7
@@ -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
|
||||
|
||||
+14
@@ -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
|
||||
}
|
||||
+1
-1
@@ -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)
|
||||
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+357
@@ -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())
|
||||
+134
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user