Introduce FIR serializer (isn't in use yet, KT-38156)

This commit is contained in:
Mikhail Glukhikh
2020-04-13 18:23:03 +03:00
parent 2c63a15af2
commit 2aae735a8e
11 changed files with 1392 additions and 1 deletions
+1
View File
@@ -263,6 +263,7 @@ extra["compilerModules"] = arrayOf(
":core:type-system",
":compiler:fir:cones",
":compiler:fir:resolve",
":compiler:fir:fir-serialization",
":compiler:fir:tree",
":compiler:fir:raw-fir:fir-common",
":compiler:fir:raw-fir:psi2fir",
@@ -0,0 +1,18 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compile(project(":core:descriptors"))
compile(project(":compiler:fir:cones"))
compile(project(":compiler:fir:tree"))
compile(project(":compiler:fir:resolve"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core", rootProject = rootProject) }
}
sourceSets {
"main" { projectDefault() }
"test" { none() }
}
@@ -0,0 +1,167 @@
/*
* 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.fir.serialization
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.FirNamedArgumentExpression
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.resolve.constants.*
class FirAnnotationSerializer(private val session: FirSession, private val stringTable: FirElementAwareStringTable) {
fun serializeAnnotation(annotation: FirAnnotationCall): ProtoBuf.Annotation = ProtoBuf.Annotation.newBuilder().apply {
val annotationSymbol = annotation.typeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag?.toSymbol(session)
val annotationClass = annotationSymbol?.fir ?: error("Annotation type is not a class: ${annotationSymbol?.fir}")
id = stringTable.getFqNameIndex(annotationClass)
for (argumentExpression in annotation.argumentList.arguments) {
if (argumentExpression !is FirNamedArgumentExpression) continue
val argument = ProtoBuf.Annotation.Argument.newBuilder()
argument.nameId = stringTable.getStringIndex(argumentExpression.name.asString())
val constant = argumentExpression.expression as? FirConstExpression<*> ?: continue
argument.setValue(valueProto(constant.value as? ConstantValue<*> ?: continue))
addArgument(argument)
}
}.build()
fun valueProto(constant: ConstantValue<*>): ProtoBuf.Annotation.Argument.Value.Builder =
ProtoBuf.Annotation.Argument.Value.newBuilder().apply {
constant.accept(object : AnnotationArgumentVisitor<Unit, Unit> {
override fun visitAnnotationValue(value: AnnotationValue, data: Unit) {
type = ProtoBuf.Annotation.Argument.Value.Type.ANNOTATION
// TODO: annotation = serializeAnnotation(value.value)
}
override fun visitArrayValue(value: ArrayValue, data: Unit) {
type = ProtoBuf.Annotation.Argument.Value.Type.ARRAY
for (element in value.value) {
addArrayElement(valueProto(element).build())
}
}
override fun visitBooleanValue(value: BooleanValue, data: Unit) {
type = ProtoBuf.Annotation.Argument.Value.Type.BOOLEAN
intValue = if (value.value) 1 else 0
}
override fun visitByteValue(value: ByteValue, data: Unit) {
type = ProtoBuf.Annotation.Argument.Value.Type.BYTE
intValue = value.value.toLong()
}
override fun visitCharValue(value: CharValue, data: Unit) {
type = ProtoBuf.Annotation.Argument.Value.Type.CHAR
intValue = value.value.toLong()
}
override fun visitDoubleValue(value: DoubleValue, data: Unit) {
type = ProtoBuf.Annotation.Argument.Value.Type.DOUBLE
doubleValue = value.value
}
override fun visitEnumValue(value: EnumValue, data: Unit) {
type = ProtoBuf.Annotation.Argument.Value.Type.ENUM
classId = stringTable.getQualifiedClassNameIndex(value.enumClassId)
enumValueId = stringTable.getStringIndex(value.enumEntryName.asString())
}
override fun visitErrorValue(value: ErrorValue, data: Unit) {
throw UnsupportedOperationException("Error value: $value")
}
override fun visitFloatValue(value: FloatValue, data: Unit) {
type = ProtoBuf.Annotation.Argument.Value.Type.FLOAT
floatValue = value.value
}
override fun visitIntValue(value: IntValue, data: Unit) {
type = ProtoBuf.Annotation.Argument.Value.Type.INT
intValue = value.value.toLong()
}
override fun visitKClassValue(value: KClassValue, data: Unit) {
type = ProtoBuf.Annotation.Argument.Value.Type.CLASS
when (val classValue = value.value) {
is KClassValue.Value.NormalClass -> {
classId = stringTable.getQualifiedClassNameIndex(classValue.classId)
if (classValue.arrayDimensions > 0) {
arrayDimensionCount = classValue.arrayDimensions
}
}
is KClassValue.Value.LocalClass -> {
var arrayDimensions = 0
var type = classValue.type
while (KotlinBuiltIns.isArray(type)) {
arrayDimensions++
type = type.arguments.single().type
}
//val descriptor = type.constructor.declarationDescriptor as? ClassDescriptor
// ?: error("Type parameters are not allowed in class literal annotation arguments: $classValue")
// TODO: classId = stringTable.getFqNameIndex(descriptor)
if (arrayDimensions > 0) {
arrayDimensionCount = arrayDimensions
}
}
}
}
override fun visitLongValue(value: LongValue, data: Unit) {
type = ProtoBuf.Annotation.Argument.Value.Type.LONG
intValue = value.value
}
override fun visitNullValue(value: NullValue, data: Unit) {
throw UnsupportedOperationException("Null should not appear in annotation arguments")
}
override fun visitShortValue(value: ShortValue, data: Unit) {
type = ProtoBuf.Annotation.Argument.Value.Type.SHORT
intValue = value.value.toLong()
}
override fun visitStringValue(value: StringValue, data: Unit) {
type = ProtoBuf.Annotation.Argument.Value.Type.STRING
stringValue = stringTable.getStringIndex(value.value)
}
override fun visitUByteValue(value: UByteValue, data: Unit?) {
type = ProtoBuf.Annotation.Argument.Value.Type.BYTE
intValue = value.value.toLong()
flags = Flags.IS_UNSIGNED.toFlags(true)
}
override fun visitUShortValue(value: UShortValue, data: Unit?) {
type = ProtoBuf.Annotation.Argument.Value.Type.SHORT
intValue = value.value.toLong()
flags = Flags.IS_UNSIGNED.toFlags(true)
}
override fun visitUIntValue(value: UIntValue, data: Unit?) {
type = ProtoBuf.Annotation.Argument.Value.Type.INT
intValue = value.value.toLong()
flags = Flags.IS_UNSIGNED.toFlags(true)
}
override fun visitULongValue(value: ULongValue, data: Unit?) {
type = ProtoBuf.Annotation.Argument.Value.Type.LONG
intValue = value.value
flags = Flags.IS_UNSIGNED.toFlags(true)
}
}, Unit)
}
}
@@ -0,0 +1,216 @@
/*
* 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.fir.serialization
import org.jetbrains.kotlin.contracts.description.*
import org.jetbrains.kotlin.contracts.description.expressions.*
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
import org.jetbrains.kotlin.fir.contracts.description.*
import org.jetbrains.kotlin.fir.contracts.effects
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.expressions.LogicOperationKind
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.Flags
class FirContractSerializer {
fun serializeContractOfFunctionIfAny(
function: FirFunction<*>,
proto: ProtoBuf.Function.Builder,
parentSerializer: FirElementSerializer
) {
val contractDescription = (function as? FirSimpleFunction)?.contractDescription
if (contractDescription == null || contractDescription.effects.isNullOrEmpty()) {
return
}
val worker = ContractSerializerWorker(parentSerializer)
proto.setContract(worker.contractProto(contractDescription))
}
private class ContractSerializerWorker(private val parentSerializer: FirElementSerializer) {
fun contractProto(contractDescription: FirContractDescription): ProtoBuf.Contract.Builder {
return ProtoBuf.Contract.newBuilder().apply {
contractDescription.effects?.forEach { addEffect(effectProto(it, contractDescription)) }
}
}
private fun effectProto(
effectDeclaration: ConeEffectDeclaration, contractDescription: FirContractDescription
): ProtoBuf.Effect.Builder {
return ProtoBuf.Effect.newBuilder().apply {
fillEffectProto(this, effectDeclaration, contractDescription)
}
}
private fun fillEffectProto(
builder: ProtoBuf.Effect.Builder,
effectDeclaration: ConeEffectDeclaration,
contractDescription: FirContractDescription
) {
when (effectDeclaration) {
is ConeConditionalEffectDeclaration -> {
builder.setConclusionOfConditionalEffect(contractExpressionProto(effectDeclaration.condition, contractDescription))
fillEffectProto(builder, effectDeclaration.effect, contractDescription)
}
is ConeReturnsEffectDeclaration -> {
when (effectDeclaration.value) {
ConstantReference.NOT_NULL ->
builder.effectType = ProtoBuf.Effect.EffectType.RETURNS_NOT_NULL
ConstantReference.WILDCARD ->
builder.effectType = ProtoBuf.Effect.EffectType.RETURNS_CONSTANT
else -> {
builder.effectType = ProtoBuf.Effect.EffectType.RETURNS_CONSTANT
builder.addEffectConstructorArgument(contractExpressionProto(effectDeclaration.value, contractDescription))
}
}
}
is ConeCallsEffectDeclaration -> {
builder.effectType = ProtoBuf.Effect.EffectType.CALLS
builder.addEffectConstructorArgument(
contractExpressionProto(effectDeclaration.valueParameterReference, contractDescription)
)
val invocationKindProtobufEnum = invocationKindProtobufEnum(effectDeclaration.kind)
if (invocationKindProtobufEnum != null) {
builder.kind = invocationKindProtobufEnum
}
}
else -> {
throw IllegalStateException("Unsupported effect type: ${effectDeclaration::class.simpleName}")
}
}
}
private fun contractExpressionProto(
contractDescriptionElement: ConeContractDescriptionElement,
contractDescription: FirContractDescription
): ProtoBuf.Expression.Builder {
return contractDescriptionElement.accept(object : ConeContractDescriptionVisitor<ProtoBuf.Expression.Builder, Unit>() {
override fun visitLogicalBinaryOperationContractExpression(
binaryLogicExpression: ConeBinaryLogicExpression,
data: Unit
): ProtoBuf.Expression.Builder {
return if (binaryLogicExpression.kind == LogicOperationKind.AND) {
visitLogicalAnd(binaryLogicExpression, data)
} else {
visitLogicalOr(binaryLogicExpression, data)
}
}
private fun visitLogicalOr(logicalOr: ConeBinaryLogicExpression, data: Unit): ProtoBuf.Expression.Builder {
val leftBuilder = logicalOr.left.accept(this, data)
return if (leftBuilder.andArgumentCount != 0) {
// can't flatten and re-use left builder
ProtoBuf.Expression.newBuilder().apply {
addOrArgument(leftBuilder)
addOrArgument(contractExpressionProto(logicalOr.right, contractDescription))
}
} else {
// we can save some space by re-using left builder instead of nesting new one
leftBuilder.apply { addOrArgument(contractExpressionProto(logicalOr.right, contractDescription)) }
}
}
private fun visitLogicalAnd(logicalAnd: ConeBinaryLogicExpression, data: Unit): ProtoBuf.Expression.Builder {
val leftBuilder = logicalAnd.left.accept(this, data)
return if (leftBuilder.orArgumentCount != 0) {
// leftBuilder is already a sequence of Or-operators, so we can't re-use it
ProtoBuf.Expression.newBuilder().apply {
addAndArgument(leftBuilder)
addAndArgument(contractExpressionProto(logicalAnd.right, contractDescription))
}
} else {
// we can save some space by re-using left builder instead of nesting new one
leftBuilder.apply { addAndArgument(contractExpressionProto(logicalAnd.right, contractDescription)) }
}
}
override fun visitLogicalNot(logicalNot: ConeLogicalNot, data: Unit): ProtoBuf.Expression.Builder =
logicalNot.arg.accept(this, data).apply {
writeFlags(Flags.IS_NEGATED.invert(flags))
}
override fun visitIsInstancePredicate(
isInstancePredicate: ConeIsInstancePredicate, data: Unit
): ProtoBuf.Expression.Builder {
// write variable
val builder = visitValueParameterReference(isInstancePredicate.arg, data)
// write rhs type
builder.isInstanceTypeId = parentSerializer.typeId(isInstancePredicate.type)
// set flags
builder.writeFlags(Flags.getContractExpressionFlags(isInstancePredicate.isNegated, false))
return builder
}
override fun visitIsNullPredicate(isNullPredicate: ConeIsNullPredicate, data: Unit): ProtoBuf.Expression.Builder {
// get builder with variable embedded into it
val builder = visitValueParameterReference(isNullPredicate.arg, data)
// set flags
builder.writeFlags(Flags.getContractExpressionFlags(isNullPredicate.isNegated, true))
return builder
}
override fun visitConstantDescriptor(constantReference: ConeConstantReference, data: Unit): ProtoBuf.Expression.Builder {
val builder = ProtoBuf.Expression.newBuilder()
// write constant value
val constantValueProtobufEnum = constantValueProtobufEnum(constantReference)
if (constantValueProtobufEnum != null) {
builder.constantValue = constantValueProtobufEnum
}
return builder
}
override fun visitValueParameterReference(
valueParameterReference: ConeValueParameterReference, data: Unit
): ProtoBuf.Expression.Builder {
val builder = ProtoBuf.Expression.newBuilder()
val indexOfParameter = valueParameterReference.parameterIndex
builder.valueParameterReference = indexOfParameter
return builder
}
}, Unit)
}
private fun ProtoBuf.Expression.Builder.writeFlags(newFlagsValue: Int) {
if (flags != newFlagsValue) {
flags = newFlagsValue
}
}
private fun invocationKindProtobufEnum(kind: InvocationKind): ProtoBuf.Effect.InvocationKind? = when (kind) {
InvocationKind.AT_MOST_ONCE -> ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE
InvocationKind.EXACTLY_ONCE -> ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE
InvocationKind.AT_LEAST_ONCE -> ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE
InvocationKind.UNKNOWN -> null
}
private fun constantValueProtobufEnum(constantReference: ConeConstantReference): ProtoBuf.Expression.ConstantValue? =
when (constantReference) {
ConeBooleanConstantReference.TRUE -> ProtoBuf.Expression.ConstantValue.TRUE
ConeBooleanConstantReference.FALSE -> ProtoBuf.Expression.ConstantValue.FALSE
ConeConstantReference.NULL -> ProtoBuf.Expression.ConstantValue.NULL
ConeConstantReference.NOT_NULL -> throw IllegalStateException(
"Internal error during serialization of function contract: NOT_NULL constant isn't denotable in protobuf format. " +
"Its serialization should be handled at higher level"
)
ConeConstantReference.WILDCARD -> null
else -> throw IllegalArgumentException("Unknown constant: $constantReference")
}
}
}
@@ -0,0 +1,26 @@
/*
* 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.fir.serialization
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.metadata.serialization.StringTable
import org.jetbrains.kotlin.name.ClassId
interface FirElementAwareStringTable : StringTable {
fun getQualifiedClassNameIndex(classId: ClassId): Int =
getQualifiedClassNameIndex(classId.asString(), classId.isLocal)
fun getFqNameIndex(classLikeDeclaration: FirClassLikeDeclaration<*>): Int {
val classId = classLikeDeclaration.symbol.classId.takeIf { !it.isLocal }
?: getLocalClassIdReplacement(classLikeDeclaration)
?: throw IllegalStateException("Cannot get FQ name of local class: ${classLikeDeclaration.render()}")
return getQualifiedClassNameIndex(classId)
}
fun getLocalClassIdReplacement(classLikeDeclaration: FirClassLikeDeclaration<*>): ClassId? = null
}
@@ -0,0 +1,863 @@
/*
* 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.fir.serialization
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirArgumentList
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.FirNamedArgumentExpression
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.calls.varargElementType
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.inference.isSuspendFunctionType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.FirImplicitNullableAnyTypeRef
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
import org.jetbrains.kotlin.metadata.deserialization.isKotlin1Dot4OrLater
import org.jetbrains.kotlin.metadata.serialization.Interner
import org.jetbrains.kotlin.metadata.serialization.MutableTypeTable
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.RequireKotlinConstants
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.EnumValue
import org.jetbrains.kotlin.resolve.constants.IntValue
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.serialization.deserialization.ProtoEnumFlags
import org.jetbrains.kotlin.types.Variance
class FirElementSerializer private constructor(
private val session: FirSession,
private val containingDeclaration: FirDeclaration?,
private val typeParameters: Interner<FirTypeParameter>,
private val extension: FirSerializerExtension,
val typeTable: MutableTypeTable,
private val versionRequirementTable: MutableVersionRequirementTable?,
private val serializeTypeTableToFunction: Boolean,
) {
private val contractSerializer = FirContractSerializer()
fun classProto(klass: FirClass<*>): ProtoBuf.Class.Builder {
val builder = ProtoBuf.Class.newBuilder()
val regularClass = klass as? FirRegularClass
val modality = regularClass?.modality ?: Modality.FINAL
val flags = Flags.getClassFlags(
klass.annotations.isNotEmpty(),
ProtoEnumFlags.visibility(regularClass?.let { normalizeVisibility(it) } ?: Visibilities.LOCAL),
ProtoEnumFlags.modality(modality),
ProtoEnumFlags.classKind(klass.classKind, regularClass?.isCompanion == true),
regularClass?.isInner == true,
regularClass?.isData == true,
regularClass?.isExternal == true,
regularClass?.isExpect == true,
regularClass?.isInline == true,
false // TODO: klass.isFun not supported yet
)
if (flags != builder.flags) {
builder.flags = flags
}
builder.fqName = getClassifierId(klass)
for (typeParameter in klass.typeParameters) {
if (typeParameter !is FirTypeParameter) continue
builder.addTypeParameter(typeParameterProto(typeParameter))
}
val classId = klass.symbol.classId
if (classId != StandardClassIds.Any && classId != StandardClassIds.Nothing) {
// Special classes (Any, Nothing) have no supertypes
for (superTypeRef in klass.superTypeRefs) {
if (useTypeTable()) {
builder.addSupertypeId(typeId(superTypeRef))
} else {
builder.addSupertype(typeProto(superTypeRef))
}
}
}
if (regularClass != null && regularClass.classKind != ClassKind.ENUM_ENTRY) {
for (constructor in regularClass.declarations.filterIsInstance<FirConstructor>()) {
builder.addConstructor(constructorProto(constructor))
}
}
// TODO: member sorting, see KT-20980
val callableMembers =
extension.customClassMembersProducer?.getCallableMembers(klass)
?: klass.declarations.filterIsInstance<FirCallableMemberDeclaration<*>>()
for (declaration in callableMembers) {
when (declaration) {
is FirProperty -> propertyProto(declaration)?.let { builder.addProperty(it) }
is FirSimpleFunction -> functionProto(declaration)?.let { builder.addFunction(it) }
is FirEnumEntry -> enumEntryProto(declaration).let { builder.addEnumEntry(it) }
}
}
val nestedClassifiers = klass.declarations.filterIsInstance<FirClassLikeDeclaration<*>>()
for (nestedClassifier in nestedClassifiers) {
if (nestedClassifier is FirTypeAlias) {
typeAliasProto(nestedClassifier)?.let { builder.addTypeAlias(it) }
} else if (nestedClassifier is FirRegularClass) {
if (!extension.shouldSerializeNestedClass(nestedClassifier)) {
continue
}
builder.addNestedClassName(getSimpleNameIndex(nestedClassifier.name))
}
}
if (klass is FirSealedClass) {
for (inheritorId in klass.inheritors) {
builder.addSealedSubclassFqName(stringTable.getQualifiedClassNameIndex(inheritorId))
}
}
val companionObject = regularClass?.companionObject
if (companionObject != null) {
builder.companionObjectName = getSimpleNameIndex(companionObject.name)
}
val typeTableProto = typeTable.serialize()
if (typeTableProto != null) {
builder.typeTable = typeTableProto
}
if (versionRequirementTable == null) error("Version requirements must be serialized for classes: ${klass.render()}")
builder.addAllVersionRequirement(versionRequirementTable.serializeVersionRequirements(klass))
extension.serializeClass(klass, builder, versionRequirementTable, this)
writeVersionRequirementForInlineClasses(klass, builder, versionRequirementTable)
val versionRequirementTableProto = versionRequirementTable.serialize()
if (versionRequirementTableProto != null) {
builder.versionRequirementTable = versionRequirementTableProto
}
return builder
}
fun propertyProto(property: FirProperty): ProtoBuf.Property.Builder? {
if (!extension.shouldSerializeProperty(property)) return null
val builder = ProtoBuf.Property.newBuilder()
val local = createChildSerializer(property)
var hasGetter = false
var hasSetter = false
//val compileTimeConstant = property.compileTimeInitializer
val hasConstant = false // TODO: compileTimeConstant != null && compileTimeConstant !is NullValue
val hasAnnotations = property.annotations.isNotEmpty()
// TODO: hasAnnotations(descriptor) || hasAnnotations(descriptor.backingField) || hasAnnotations(descriptor.delegateField)
val modality = property.modality!!
val defaultAccessorFlags = Flags.getAccessorFlags(
hasAnnotations,
ProtoEnumFlags.visibility(normalizeVisibility(property)),
ProtoEnumFlags.modality(modality),
false, false, false
)
val getter = property.getter
if (getter != null) {
hasGetter = true
val accessorFlags = getAccessorFlags(getter, property)
if (accessorFlags != defaultAccessorFlags) {
builder.getterFlags = accessorFlags
}
}
val setter = property.setter
if (setter != null) {
hasSetter = true
val accessorFlags = getAccessorFlags(setter, property)
if (accessorFlags != defaultAccessorFlags) {
builder.setterFlags = accessorFlags
}
if (setter !is FirDefaultPropertyAccessor ||
setter.annotations.isNotEmpty() ||
setter.visibility != property.visibility
) {
val setterLocal = local.createChildSerializer(setter)
for (valueParameterDescriptor in setter.valueParameters) {
builder.setSetterValueParameter(setterLocal.valueParameterProto(valueParameterDescriptor))
}
}
}
val flags = Flags.getPropertyFlags(
hasAnnotations,
ProtoEnumFlags.visibility(normalizeVisibility(property)),
ProtoEnumFlags.modality(modality),
ProtoEnumFlags.memberKind(CallableMemberDescriptor.Kind.DECLARATION),
property.isVar, hasGetter, hasSetter, hasConstant, property.isConst, property.isLateInit,
property.isExternal, property.delegateFieldSymbol != null, property.isExpect
)
if (flags != builder.flags) {
builder.flags = flags
}
builder.name = getSimpleNameIndex(property.name)
if (useTypeTable()) {
builder.returnTypeId = local.typeId(property.returnTypeRef)
} else {
builder.setReturnType(local.typeProto(property.returnTypeRef))
}
for (typeParameter in property.typeParameters) {
builder.addTypeParameter(local.typeParameterProto(typeParameter))
}
val receiverTypeRef = property.receiverTypeRef
if (receiverTypeRef != null) {
if (useTypeTable()) {
builder.receiverTypeId = local.typeId(receiverTypeRef)
} else {
builder.setReceiverType(local.typeProto(receiverTypeRef))
}
}
versionRequirementTable?.run {
builder.addAllVersionRequirement(serializeVersionRequirements(property))
if (property.isSuspendOrHasSuspendTypesInSignature()) {
builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion())
}
if (property.hasInlineClassTypesInSignature()) {
builder.addVersionRequirement(writeVersionRequirement(LanguageFeature.InlineClasses))
}
}
extension.serializeProperty(property, builder, versionRequirementTable, local)
return builder
}
fun functionProto(function: FirFunction<*>): ProtoBuf.Function.Builder? {
if (!extension.shouldSerializeFunction(function)) return null
val builder = ProtoBuf.Function.newBuilder()
val simpleFunction = function as? FirSimpleFunction
val local = createChildSerializer(function)
val flags = Flags.getFunctionFlags(
function.annotations.isNotEmpty(),
ProtoEnumFlags.visibility(simpleFunction?.let { normalizeVisibility(it) } ?: Visibilities.LOCAL),
ProtoEnumFlags.modality(simpleFunction?.modality ?: Modality.FINAL),
ProtoEnumFlags.memberKind(CallableMemberDescriptor.Kind.DECLARATION),
simpleFunction?.isOperator == true,
simpleFunction?.isInfix == true,
simpleFunction?.isInline == true,
simpleFunction?.isTailRec == true,
simpleFunction?.isExternal == true,
simpleFunction?.isSuspend == true,
simpleFunction?.isExpect == true
)
if (flags != builder.flags) {
builder.flags = flags
}
val name = when (function) {
is FirSimpleFunction -> {
function.name
}
is FirAnonymousFunction -> {
if (function.isLambda) Name.special("<anonymous>") else Name.special("<no name provided>")
}
else -> throw AssertionError("Unsupported function: ${function.render()}")
}
builder.name = getSimpleNameIndex(name)
if (useTypeTable()) {
builder.returnTypeId = local.typeId(function.returnTypeRef)
} else {
builder.setReturnType(local.typeProto(function.returnTypeRef))
}
for (typeParameter in function.typeParameters) {
if (typeParameter !is FirTypeParameter) continue
builder.addTypeParameter(local.typeParameterProto(typeParameter))
}
val receiverTypeRef = function.receiverTypeRef
if (receiverTypeRef != null) {
if (useTypeTable()) {
builder.receiverTypeId = local.typeId(receiverTypeRef)
} else {
builder.setReceiverType(local.typeProto(receiverTypeRef))
}
}
for (valueParameter in function.valueParameters) {
builder.addValueParameter(local.valueParameterProto(valueParameter))
}
if (serializeTypeTableToFunction) {
val typeTableProto = typeTable.serialize()
if (typeTableProto != null) {
builder.typeTable = typeTableProto
}
}
versionRequirementTable?.run {
builder.addAllVersionRequirement(serializeVersionRequirements(function))
if (function.isSuspendOrHasSuspendTypesInSignature()) {
builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion())
}
if (function.hasInlineClassTypesInSignature()) {
builder.addVersionRequirement(writeVersionRequirement(LanguageFeature.InlineClasses))
}
}
contractSerializer.serializeContractOfFunctionIfAny(function, builder, this)
extension.serializeFunction(function, builder, versionRequirementTable, local)
return builder
}
private fun typeAliasProto(typeAlias: FirTypeAlias): ProtoBuf.TypeAlias.Builder? {
if (!extension.shouldSerializeTypeAlias(typeAlias)) return null
val builder = ProtoBuf.TypeAlias.newBuilder()
val local = createChildSerializer(typeAlias)
val flags = Flags.getTypeAliasFlags(
typeAlias.annotations.isNotEmpty(),
ProtoEnumFlags.visibility(normalizeVisibility(typeAlias))
)
if (flags != builder.flags) {
builder.flags = flags
}
builder.name = getSimpleNameIndex(typeAlias.name)
for (typeParameter in typeAlias.typeParameters) {
builder.addTypeParameter(local.typeParameterProto(typeParameter))
}
val underlyingType = typeAlias.expandedConeType!!
if (useTypeTable()) {
builder.underlyingTypeId = local.typeId(underlyingType)
} else {
builder.setUnderlyingType(local.typeProto(underlyingType))
}
val expandedType = underlyingType.fullyExpandedType(session)
if (useTypeTable()) {
builder.expandedTypeId = local.typeId(expandedType)
} else {
builder.setExpandedType(local.typeProto(expandedType))
}
versionRequirementTable?.run {
builder.addAllVersionRequirement(serializeVersionRequirements(typeAlias))
}
for (annotation in typeAlias.annotations) {
builder.addAnnotation(extension.annotationSerializer.serializeAnnotation(annotation))
}
extension.serializeTypeAlias(typeAlias, builder)
return builder
}
private fun enumEntryProto(enumEntry: FirEnumEntry): ProtoBuf.EnumEntry.Builder {
val builder = ProtoBuf.EnumEntry.newBuilder()
builder.name = getSimpleNameIndex(enumEntry.name)
extension.serializeEnumEntry(enumEntry, builder)
return builder
}
private fun constructorProto(constructor: FirConstructor): ProtoBuf.Constructor.Builder {
val builder = ProtoBuf.Constructor.newBuilder()
val local = createChildSerializer(constructor)
val flags = Flags.getConstructorFlags(
constructor.annotations.isNotEmpty(),
ProtoEnumFlags.visibility(normalizeVisibility(constructor)),
!constructor.isPrimary
)
if (flags != builder.flags) {
builder.flags = flags
}
for (valueParameter in constructor.valueParameters) {
builder.addValueParameter(local.valueParameterProto(valueParameter))
}
versionRequirementTable?.run {
builder.addAllVersionRequirement(serializeVersionRequirements(constructor))
if (constructor.isSuspendOrHasSuspendTypesInSignature()) {
builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion())
}
if (constructor.hasInlineClassTypesInSignature()) {
builder.addVersionRequirement(writeVersionRequirement(LanguageFeature.InlineClasses))
}
}
extension.serializeConstructor(constructor, builder, local)
return builder
}
private fun valueParameterProto(parameter: FirValueParameter): ProtoBuf.ValueParameter.Builder {
val builder = ProtoBuf.ValueParameter.newBuilder()
val declaresDefaultValue = parameter.defaultValue != null // TODO: || parameter.isActualParameterWithAnyExpectedDefault
val flags = Flags.getValueParameterFlags(
parameter.annotations.isNotEmpty(), declaresDefaultValue,
parameter.isCrossinline, parameter.isNoinline
)
if (flags != builder.flags) {
builder.flags = flags
}
builder.name = getSimpleNameIndex(parameter.name)
if (useTypeTable()) {
builder.typeId = typeId(parameter.returnTypeRef)
} else {
builder.setType(typeProto(parameter.returnTypeRef))
}
if (parameter.isVararg) {
val varargElementType = parameter.returnTypeRef.coneTypeSafe<ConeKotlinType>()?.varargElementType(session)
if (varargElementType != null) {
if (useTypeTable()) {
builder.varargElementTypeId = typeId(varargElementType)
} else {
builder.setVarargElementType(typeProto(varargElementType))
}
}
}
extension.serializeValueParameter(parameter, builder)
return builder
}
private fun typeParameterProto(typeParameter: FirTypeParameter): ProtoBuf.TypeParameter.Builder {
val builder = ProtoBuf.TypeParameter.newBuilder()
builder.id = getTypeParameterId(typeParameter)
builder.name = getSimpleNameIndex(typeParameter.name)
if (typeParameter.isReified != builder.reified) {
builder.reified = typeParameter.isReified
}
val variance = variance(typeParameter.variance)
if (variance != builder.variance) {
builder.variance = variance
}
extension.serializeTypeParameter(typeParameter, builder)
val upperBounds = typeParameter.bounds
if (upperBounds.size == 1 && upperBounds.single() is FirImplicitNullableAnyTypeRef) return builder
for (upperBound in upperBounds) {
if (useTypeTable()) {
builder.addUpperBoundId(typeId(upperBound))
} else {
builder.addUpperBound(typeProto(upperBound))
}
}
return builder
}
fun typeId(typeRef: FirTypeRef): Int {
if (typeRef !is FirResolvedTypeRef) {
return -1 // TODO: serializeErrorType?
}
return typeId(typeRef.type)
}
fun typeId(type: ConeKotlinType): Int = typeTable[typeProto(type)]
internal fun typeProto(typeRef: FirTypeRef): ProtoBuf.Type.Builder {
return typeProto((typeRef as FirResolvedTypeRef).type)
}
internal fun typeProto(type: ConeKotlinType): ProtoBuf.Type.Builder {
val builder = ProtoBuf.Type.newBuilder()
if (type is ConeKotlinErrorType) {
extension.serializeErrorType(type, builder)
return builder
}
if (type is ConeFlexibleType) {
val lowerBound = typeProto(type.lowerBound)
val upperBound = typeProto(type.upperBound)
extension.serializeFlexibleType(type, lowerBound, upperBound)
if (useTypeTable()) {
lowerBound.flexibleUpperBoundId = typeTable[upperBound]
} else {
lowerBound.setFlexibleUpperBound(upperBound)
}
return lowerBound
}
if (type is ConeClassLikeType && type.isSuspendFunctionType(session)) {
// TODO: suspend function type
// val functionType = typeProto(transformSuspendFunctionToRuntimeFunctionType(type, extension.releaseCoroutines()))
// functionType.flags = Flags.getTypeFlags(true)
// return functionType
}
when (type) {
is ConeClassLikeType -> {
fillFromPossiblyInnerType(builder, type)
}
is ConeTypeParameterType -> {
// TODO: type parameter containing declaration?
if (false /*descriptor.containingDeclaration === containingDeclaration*/) {
//builder.typeParameterName = getSimpleNameIndex(descriptor.name)
} else {
builder.typeParameter = getTypeParameterId(type.lookupTag.typeParameterSymbol.fir)
}
}
}
if (type.isMarkedNullable != builder.nullable) {
builder.nullable = type.isMarkedNullable
}
// TODO: abbreviated type
// val abbreviation = type.getAbbreviatedType()?.abbreviation
// if (abbreviation != null) {
// if (useTypeTable()) {
// builder.abbreviatedTypeId = typeId(abbreviation)
// } else {
// builder.setAbbreviatedType(typeProto(abbreviation))
// }
// }
extension.serializeType(type, builder)
return builder
}
private fun fillFromPossiblyInnerType(builder: ProtoBuf.Type.Builder, type: ConeClassLikeType) {
val classifierSymbol = type.lookupTag.toSymbol(session)!!
val classifier = classifierSymbol.fir
val classifierId = getClassifierId(classifier)
builder.className = classifierId
for (projection in type.typeArguments) {
builder.addArgument(typeArgument(projection))
}
// TODO: outer type
// if (type.outerType != null) {
// val outerBuilder = ProtoBuf.Type.newBuilder()
// fillFromPossiblyInnerType(outerBuilder, type.outerType!!)
// if (useTypeTable()) {
// builder.outerTypeId = typeTable[outerBuilder]
// } else {
// builder.setOuterType(outerBuilder)
// }
// }
}
private fun typeArgument(typeProjection: ConeTypeProjection): ProtoBuf.Type.Argument.Builder {
val builder = ProtoBuf.Type.Argument.newBuilder()
if (typeProjection is ConeStarProjection) {
builder.projection = ProtoBuf.Type.Argument.Projection.STAR
} else if (typeProjection is ConeKotlinTypeProjection) {
val projection = projection(typeProjection.kind)
if (projection != builder.projection) {
builder.projection = projection
}
if (useTypeTable()) {
builder.typeId = typeId(typeProjection.type)
} else {
builder.setType(typeProto(typeProjection.type))
}
}
return builder
}
private fun getAccessorFlags(accessor: FirPropertyAccessor, property: FirProperty): Int {
val isDefault = accessor is FirDefaultPropertyAccessor &&
accessor.annotations.isEmpty() && accessor.visibility == property.visibility
return Flags.getAccessorFlags(
accessor.annotations.isNotEmpty(),
ProtoEnumFlags.visibility(normalizeVisibility(accessor)),
ProtoEnumFlags.modality(accessor.modality!!),
!isDefault,
accessor.status.isExternal,
accessor.status.isInline
)
}
private fun createChildSerializer(declaration: FirDeclaration): FirElementSerializer =
FirElementSerializer(
session, declaration, Interner(typeParameters), extension,
typeTable, versionRequirementTable, serializeTypeTableToFunction = false
)
private val stringTable: FirElementAwareStringTable
get() = extension.stringTable
private fun useTypeTable(): Boolean = extension.shouldUseTypeTable()
private fun FirDeclaration.hasInlineClassTypesInSignature(): Boolean {
// TODO
return false
}
private fun FirCallableDeclaration<*>.isSuspendOrHasSuspendTypesInSignature(): Boolean {
// TODO
return false
}
private fun writeVersionRequirementForInlineClasses(
klass: FirClass<*>,
builder: ProtoBuf.Class.Builder,
versionRequirementTable: MutableVersionRequirementTable
) {
if (klass !is FirRegularClass || !klass.isInline && !klass.hasInlineClassTypesInSignature()) return
builder.addVersionRequirement(
writeLanguageVersionRequirement(LanguageFeature.InlineClasses, versionRequirementTable)
)
}
private fun MutableVersionRequirementTable.serializeVersionRequirements(container: FirAnnotationContainer): List<Int> =
serializeVersionRequirements(container.annotations)
private fun MutableVersionRequirementTable.serializeVersionRequirements(annotations: List<FirAnnotationCall>): List<Int> =
annotations
.filter {
val annotationConeType = it.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()
annotationConeType?.lookupTag?.classId?.asSingleFqName() == RequireKotlinConstants.FQ_NAME
}
.mapNotNull(::serializeVersionRequirementFromRequireKotlin)
.map(::get)
private fun MutableVersionRequirementTable.writeVersionRequirement(languageFeature: LanguageFeature): Int {
return writeLanguageVersionRequirement(languageFeature, this)
}
private fun MutableVersionRequirementTable.writeVersionRequirementDependingOnCoroutinesVersion(): Int =
writeVersionRequirement(LanguageFeature.ReleaseCoroutines)
private operator fun FirArgumentList.get(name: Name): ConstantValue<*>? {
// TODO: constant evaluation
val expression = arguments.filterIsInstance<FirNamedArgumentExpression>().find {
name == name
}?.expression
if (expression !is FirConstExpression<*>) {
return null
}
return expression.value as? ConstantValue<*>
}
private fun serializeVersionRequirementFromRequireKotlin(annotation: FirAnnotationCall): ProtoBuf.VersionRequirement.Builder? {
val args = annotation.argumentList
val versionString = (args[RequireKotlinConstants.VERSION] as? StringValue)?.value ?: return null
val matchResult = RequireKotlinConstants.VERSION_REGEX.matchEntire(versionString) ?: return null
val major = matchResult.groupValues.getOrNull(1)?.toIntOrNull() ?: return null
val minor = matchResult.groupValues.getOrNull(2)?.toIntOrNull() ?: 0
val patch = matchResult.groupValues.getOrNull(4)?.toIntOrNull() ?: 0
val proto = ProtoBuf.VersionRequirement.newBuilder()
VersionRequirement.Version(major, minor, patch).encode(
writeVersion = { proto.version = it },
writeVersionFull = { proto.versionFull = it }
)
val message = (args[RequireKotlinConstants.MESSAGE] as? StringValue)?.value
if (message != null) {
proto.message = stringTable.getStringIndex(message)
}
when ((args[RequireKotlinConstants.LEVEL] as? EnumValue)?.enumEntryName?.asString()) {
DeprecationLevel.ERROR.name -> {
// ERROR is the default level
}
DeprecationLevel.WARNING.name -> proto.level = ProtoBuf.VersionRequirement.Level.WARNING
DeprecationLevel.HIDDEN.name -> proto.level = ProtoBuf.VersionRequirement.Level.HIDDEN
}
when ((args[RequireKotlinConstants.VERSION_KIND] as? EnumValue)?.enumEntryName?.asString()) {
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION.name -> {
// LANGUAGE_VERSION is the default kind
}
ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION.name ->
proto.versionKind = ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION
ProtoBuf.VersionRequirement.VersionKind.API_VERSION.name ->
proto.versionKind = ProtoBuf.VersionRequirement.VersionKind.API_VERSION
}
val errorCode = (args[RequireKotlinConstants.ERROR_CODE] as? IntValue)?.value
if (errorCode != null && errorCode != -1) {
proto.errorCode = errorCode
}
return proto
}
private fun normalizeVisibility(declaration: FirMemberDeclaration): Visibility {
// It can be necessary for Java classes serialization having package-private visibility
return if (extension.shouldUseNormalizedVisibility()) declaration.visibility.normalize()
else declaration.visibility
}
private fun normalizeVisibility(declaration: FirPropertyAccessor): Visibility {
// It can be necessary for Java classes serialization having package-private visibility
return if (extension.shouldUseNormalizedVisibility()) declaration.visibility.normalize()
else declaration.visibility
}
private fun getClassifierId(declaration: FirClassLikeDeclaration<*>): Int =
stringTable.getFqNameIndex(declaration)
private fun getSimpleNameIndex(name: Name): Int =
stringTable.getStringIndex(name.asString())
private fun getTypeParameterId(typeParameter: FirTypeParameter): Int =
typeParameters.intern(typeParameter)
companion object {
@JvmStatic
fun createTopLevel(session: FirSession, extension: FirSerializerExtension): FirElementSerializer =
FirElementSerializer(
session, null,
Interner(), extension, MutableTypeTable(), MutableVersionRequirementTable(),
serializeTypeTableToFunction = false
)
@JvmStatic
fun createForLambda(session: FirSession, extension: FirSerializerExtension): FirElementSerializer =
FirElementSerializer(
session, null,
Interner(), extension, MutableTypeTable(),
versionRequirementTable = null, serializeTypeTableToFunction = true
)
@JvmStatic
fun create(
klass: FirClass<*>,
extension: FirSerializerExtension,
parentSerializer: FirElementSerializer?
): FirElementSerializer {
val parentClassId = klass.symbol.classId.outerClassId
val parent = if (parentClassId != null && !parentClassId.isLocal) {
val parentClass = klass.session.firSymbolProvider.getClassLikeSymbolByFqName(parentClassId)!!.fir as FirRegularClass
parentSerializer ?: create(parentClass, extension, null)
} else {
createTopLevel(klass.session, extension)
}
// Calculate type parameter ids for the outer class beforehand, as it would've had happened if we were always
// serializing outer classes before nested classes.
// Otherwise our interner can get wrong ids because we may serialize classes in any order.
val serializer = FirElementSerializer(
klass.session,
klass,
Interner(parent.typeParameters),
extension,
MutableTypeTable(),
if (parentClassId != null && !isKotlin1Dot4OrLater(extension.metadataVersion)) {
parent.versionRequirementTable
} else {
MutableVersionRequirementTable()
},
serializeTypeTableToFunction = false
)
for (typeParameter in klass.typeParameters) {
if (typeParameter !is FirTypeParameter) continue
serializer.typeParameters.intern(typeParameter)
}
return serializer
}
fun writeLanguageVersionRequirement(
languageFeature: LanguageFeature,
versionRequirementTable: MutableVersionRequirementTable
): Int {
val languageVersion = languageFeature.sinceVersion!!
return writeVersionRequirement(
languageVersion.major, languageVersion.minor, 0,
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION,
versionRequirementTable
)
}
fun writeVersionRequirement(
major: Int,
minor: Int,
patch: Int,
versionKind: ProtoBuf.VersionRequirement.VersionKind,
versionRequirementTable: MutableVersionRequirementTable
): Int {
val requirement = ProtoBuf.VersionRequirement.newBuilder().apply {
VersionRequirement.Version(major, minor, patch).encode(
writeVersion = { version = it },
writeVersionFull = { versionFull = it }
)
if (versionKind != defaultInstanceForType.versionKind) {
this.versionKind = versionKind
}
}
return versionRequirementTable[requirement]
}
private fun variance(variance: Variance): ProtoBuf.TypeParameter.Variance = when (variance) {
Variance.INVARIANT -> ProtoBuf.TypeParameter.Variance.INV
Variance.IN_VARIANCE -> ProtoBuf.TypeParameter.Variance.IN
Variance.OUT_VARIANCE -> ProtoBuf.TypeParameter.Variance.OUT
}
private fun projection(projectionKind: ProjectionKind): ProtoBuf.Type.Argument.Projection = when (projectionKind) {
ProjectionKind.INVARIANT -> ProtoBuf.Type.Argument.Projection.INV
ProjectionKind.IN -> ProtoBuf.Type.Argument.Projection.IN
ProjectionKind.OUT -> ProtoBuf.Type.Argument.Projection.OUT
ProjectionKind.STAR -> throw AssertionError("Should not be here")
}
}
}
@@ -0,0 +1,97 @@
/*
* 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.fir.serialization
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.types.ConeFlexibleType
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
import org.jetbrains.kotlin.name.FqName
abstract class FirSerializerExtension {
abstract val session: FirSession
abstract val stringTable: FirElementAwareStringTable
abstract val metadataVersion: BinaryVersion
val annotationSerializer by lazy { FirAnnotationSerializer(session, stringTable) }
open fun shouldSerializeNestedClass(nestedClass: FirRegularClass): Boolean = true
open fun shouldSerializeTypeAlias(typeAlias: FirTypeAlias): Boolean = true
open fun shouldUseTypeTable(): Boolean = false
open fun shouldUseNormalizedVisibility(): Boolean = false
open fun shouldSerializeFunction(function: FirFunction<*>): Boolean = false
open fun shouldSerializeProperty(property: FirProperty): Boolean = false
open fun serializePackage(packageFqName: FqName, proto: ProtoBuf.Package.Builder) {
}
open fun serializeClass(
klass: FirClass<*>,
proto: ProtoBuf.Class.Builder,
versionRequirementTable: MutableVersionRequirementTable,
childSerializer: FirElementSerializer
) {
}
open fun serializeConstructor(
constructor: FirConstructor,
proto: ProtoBuf.Constructor.Builder,
childSerializer: FirElementSerializer
) {
}
open fun serializeFunction(
function: FirFunction<*>,
proto: ProtoBuf.Function.Builder,
versionRequirementTable: MutableVersionRequirementTable?,
childSerializer: FirElementSerializer
) {
}
open fun serializeProperty(
property: FirProperty,
proto: ProtoBuf.Property.Builder,
versionRequirementTable: MutableVersionRequirementTable?,
childSerializer: FirElementSerializer
) {
}
open fun serializeEnumEntry(enumEntry: FirEnumEntry, proto: ProtoBuf.EnumEntry.Builder) {
}
open fun serializeValueParameter(parameter: FirValueParameter, proto: ProtoBuf.ValueParameter.Builder) {
}
open fun serializeFlexibleType(type: ConeFlexibleType, lowerProto: ProtoBuf.Type.Builder, upperProto: ProtoBuf.Type.Builder) {
}
open fun serializeType(type: ConeKotlinType, proto: ProtoBuf.Type.Builder) {
}
open fun serializeTypeParameter(typeParameter: FirTypeParameter, proto: ProtoBuf.TypeParameter.Builder) {
}
open fun serializeTypeAlias(typeAlias: FirTypeAlias, proto: ProtoBuf.TypeAlias.Builder) {
}
open fun serializeErrorType(type: ConeKotlinErrorType, builder: ProtoBuf.Type.Builder) {
throw IllegalStateException("Cannot serialize error type: $type")
}
open val customClassMembersProducer: ClassMembersProducer?
get() = null
interface ClassMembersProducer {
fun getCallableMembers(klass: FirClass<*>): Collection<FirCallableMemberDeclaration<*>>
}
}
+1
View File
@@ -7,6 +7,7 @@ dependencies {
compileOnly(project(":core:descriptors"))
compileOnly(project(":compiler:fir:cones"))
compileOnly(project(":compiler:fir:resolve"))
compileOnly(project(":compiler:fir:fir-serialization"))
compileOnly(project(":compiler:fir:tree"))
compileOnly(project(":compiler:ir.tree"))
compileOnly(project(":compiler:ir.psi2ir"))
@@ -341,7 +341,7 @@ internal fun FirExpression.getExpectedType(
}
private fun ConeKotlinType.varargElementType(session: FirSession): ConeKotlinType {
fun ConeKotlinType.varargElementType(session: FirSession): ConeKotlinType {
return this.arrayElementType(session) ?: error("Failed to extract! ${this.render()}!")
}
+1
View File
@@ -43,6 +43,7 @@ val projectsToShadow by extra(listOf(
":compiler:fir:cones",
":compiler:fir:checkers",
":compiler:fir:resolve",
":compiler:fir:fir-serialization",
":compiler:fir:tree",
":compiler:fir:java",
":compiler:fir:jvm",
+1
View File
@@ -89,6 +89,7 @@ include ":kotlin-build-common",
":compiler:fir:fir2ir",
":compiler:fir:fir2ir:jvm-backend",
":compiler:fir:resolve",
":compiler:fir:fir-serialization",
":compiler:fir:java",
":compiler:fir:modularized-tests",
":compiler:fir:dump",