[FIR] Move deserialization files to module :compiler:fir:fir-deserialization

This commit is contained in:
Dmitriy Novozhilov
2020-08-28 12:08:17 +03:00
parent ca031f7ace
commit ed4c6a38b6
17 changed files with 38 additions and 11 deletions
@@ -0,0 +1,21 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
implementation(project(":core:descriptors"))
implementation(project(":core:descriptors.jvm"))
implementation(project(":core:deserialization"))
api(project(":compiler:fir:cones"))
api(project(":compiler:fir:tree"))
api(project(":compiler:fir:resolve"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core", rootProject = rootProject) }
}
sourceSets {
"main" { projectDefault() }
"test" { none() }
}
@@ -0,0 +1,266 @@
/*
* 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.deserialization
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.collectEnumEntries
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.references.impl.FirReferencePlaceholderForResolvedAnnotations
import org.jetbrains.kotlin.fir.resolve.constructType
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedSymbolError
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.constructType
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf.Annotation.Argument.Value.Type.*
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
import org.jetbrains.kotlin.serialization.deserialization.getClassId
import org.jetbrains.kotlin.serialization.deserialization.getName
abstract class AbstractAnnotationDeserializer(
private val session: FirSession
) {
protected val protocol = BuiltInSerializerProtocol
open fun inheritAnnotationInfo(parent: AbstractAnnotationDeserializer) {
}
enum class CallableKind {
PROPERTY,
PROPERTY_GETTER,
PROPERTY_SETTER,
OTHERS
}
fun loadClassAnnotations(classProto: ProtoBuf.Class, nameResolver: NameResolver): List<FirAnnotationCall> {
if (!Flags.HAS_ANNOTATIONS.get(classProto.flags)) return emptyList()
val annotations = classProto.getExtension(protocol.classAnnotation).orEmpty()
return annotations.map { deserializeAnnotation(it, nameResolver) }
}
open fun loadFunctionAnnotations(
containerSource: DeserializedContainerSource?,
functionProto: ProtoBuf.Function,
nameResolver: NameResolver,
typeTable: TypeTable
): List<FirAnnotationCall> {
if (!Flags.HAS_ANNOTATIONS.get(functionProto.flags)) return emptyList()
val annotations = functionProto.getExtension(protocol.functionAnnotation).orEmpty()
return annotations.map { deserializeAnnotation(it, nameResolver) }
}
open fun loadPropertyAnnotations(
containerSource: DeserializedContainerSource?,
propertyProto: ProtoBuf.Property,
nameResolver: NameResolver,
typeTable: TypeTable
): List<FirAnnotationCall> {
if (!Flags.HAS_ANNOTATIONS.get(propertyProto.flags)) return emptyList()
val annotations = propertyProto.getExtension(protocol.propertyAnnotation).orEmpty()
return annotations.map { deserializeAnnotation(it, nameResolver, AnnotationUseSiteTarget.PROPERTY) }
}
open fun loadPropertyBackingFieldAnnotations(
containerSource: DeserializedContainerSource?,
propertyProto: ProtoBuf.Property,
nameResolver: NameResolver,
typeTable: TypeTable
): List<FirAnnotationCall> {
return emptyList()
}
open fun loadPropertyDelegatedFieldAnnotations(
containerSource: DeserializedContainerSource?,
propertyProto: ProtoBuf.Property,
nameResolver: NameResolver,
typeTable: TypeTable
): List<FirAnnotationCall> {
return emptyList()
}
open fun loadPropertyGetterAnnotations(
containerSource: DeserializedContainerSource?,
propertyProto: ProtoBuf.Property,
nameResolver: NameResolver,
typeTable: TypeTable,
getterFlags: Int
): List<FirAnnotationCall> {
if (!Flags.HAS_ANNOTATIONS.get(getterFlags)) return emptyList()
val annotations = propertyProto.getExtension(protocol.propertyGetterAnnotation).orEmpty()
return annotations.map { deserializeAnnotation(it, nameResolver, AnnotationUseSiteTarget.PROPERTY_GETTER) }
}
open fun loadPropertySetterAnnotations(
containerSource: DeserializedContainerSource?,
propertyProto: ProtoBuf.Property,
nameResolver: NameResolver,
typeTable: TypeTable,
setterFlags: Int
): List<FirAnnotationCall> {
if (!Flags.HAS_ANNOTATIONS.get(setterFlags)) return emptyList()
val annotations = propertyProto.getExtension(protocol.propertySetterAnnotation).orEmpty()
return annotations.map { deserializeAnnotation(it, nameResolver, AnnotationUseSiteTarget.PROPERTY_SETTER) }
}
open fun loadConstructorAnnotations(
containerSource: DeserializedContainerSource?,
constructorProto: ProtoBuf.Constructor,
nameResolver: NameResolver,
typeTable: TypeTable
): List<FirAnnotationCall> {
if (!Flags.HAS_ANNOTATIONS.get(constructorProto.flags)) return emptyList()
val annotations = constructorProto.getExtension(protocol.constructorAnnotation).orEmpty()
return annotations.map { deserializeAnnotation(it, nameResolver) }
}
open fun loadValueParameterAnnotations(
containerSource: DeserializedContainerSource?,
callableProto: MessageLite,
valueParameterProto: ProtoBuf.ValueParameter,
classProto: ProtoBuf.Class?,
nameResolver: NameResolver,
typeTable: TypeTable,
kind: CallableKind,
parameterIndex: Int
): List<FirAnnotationCall> {
if (!Flags.HAS_ANNOTATIONS.get(valueParameterProto.flags)) return emptyList()
val annotations = valueParameterProto.getExtension(protocol.parameterAnnotation).orEmpty()
return annotations.map { deserializeAnnotation(it, nameResolver) }
}
open fun loadExtensionReceiverParameterAnnotations(
containerSource: DeserializedContainerSource?,
callableProto: MessageLite,
nameResolver: NameResolver,
typeTable: TypeTable,
kind: CallableKind
): List<FirAnnotationCall> {
return emptyList()
}
abstract fun loadTypeAnnotations(typeProto: ProtoBuf.Type, nameResolver: NameResolver): List<FirAnnotationCall>
fun deserializeAnnotation(
proto: ProtoBuf.Annotation,
nameResolver: NameResolver,
useSiteTarget: AnnotationUseSiteTarget? = null
): FirAnnotationCall {
val classId = nameResolver.getClassId(proto.id)
val lookupTag = ConeClassLikeLookupTagImpl(classId)
val symbol = lookupTag.toSymbol(session)
val firAnnotationClass = (symbol as? FirRegularClassSymbol)?.fir
var arguments = emptyList<FirExpression>()
if (proto.argumentCount != 0 && firAnnotationClass?.classKind == ClassKind.ANNOTATION_CLASS) {
val constructor = firAnnotationClass.declarations.firstOrNull { it is FirConstructor }
if (constructor is FirConstructor) {
val parameterByName = constructor.valueParameters.associateBy { it.name }
arguments = proto.argumentList.mapNotNull {
val name = nameResolver.getName(it.nameId)
val parameter = parameterByName[name] ?: return@mapNotNull null
val value = resolveValue(parameter.returnTypeRef, it.value, nameResolver) ?: return@mapNotNull null
buildNamedArgumentExpression {
expression = value
isSpread = false
this.name = name
}
}
}
}
return buildAnnotationCall {
annotationTypeRef = symbol?.let {
buildResolvedTypeRef {
type = it.constructType(emptyArray(), isNullable = false)
}
} ?: buildErrorTypeRef { diagnostic = ConeUnresolvedSymbolError(classId) }
argumentList = buildArgumentList {
this.arguments += arguments
}
useSiteTarget?.let {
this.useSiteTarget = it
}
calleeReference = FirReferencePlaceholderForResolvedAnnotations
}
}
fun resolveValue(
expectedType: FirTypeRef, value: ProtoBuf.Annotation.Argument.Value, nameResolver: NameResolver
): FirExpression? {
// TODO: val isUnsigned = Flags.IS_UNSIGNED.get(value.flags)
val result: FirExpression = when (value.type) {
BYTE -> const(FirConstKind.Byte, value.intValue.toByte())
CHAR -> const(FirConstKind.Char, value.intValue.toChar())
SHORT -> const(FirConstKind.Short, value.intValue.toShort())
INT -> const(FirConstKind.Int, value.intValue.toInt())
LONG -> const(FirConstKind.Long, value.intValue)
FLOAT -> const(FirConstKind.Float, value.floatValue)
DOUBLE -> const(FirConstKind.Double, value.doubleValue)
BOOLEAN -> const(FirConstKind.Boolean, (value.intValue != 0L))
STRING -> const(FirConstKind.String, nameResolver.getString(value.stringValue))
ANNOTATION -> deserializeAnnotation(value.annotation, nameResolver)
CLASS -> buildGetClassCall {
val classId = nameResolver.getClassId(value.classId)
val lookupTag = ConeClassLikeLookupTagImpl(classId)
val referencedType = lookupTag.constructType(emptyArray(), isNullable = false)
argumentList = buildUnaryArgumentList(
buildClassReferenceExpression {
classTypeRef = buildResolvedTypeRef {
type = referencedType
}
}
)
}
ENUM -> buildFunctionCall {
val classId = nameResolver.getClassId(value.classId)
val entryName = nameResolver.getName(value.enumValueId)
val enumLookupTag = ConeClassLikeLookupTagImpl(classId)
val enumSymbol = enumLookupTag.toSymbol(this@AbstractAnnotationDeserializer.session)
val firClass = enumSymbol?.fir as? FirRegularClass
val enumEntries = firClass?.collectEnumEntries() ?: emptyList()
val enumEntrySymbol = enumEntries.find { it.name == entryName }
this.calleeReference = enumEntrySymbol?.let {
buildResolvedNamedReference {
name = entryName
resolvedSymbol = it.symbol
}
} ?: buildErrorNamedReference {
diagnostic = ConeSimpleDiagnostic("Strange deserialized enum value: $classId.$entryName", DiagnosticKind.DeserializationError)
}
}
// ARRAY -> {
// TODO: see AnnotationDeserializer
// }
// else -> error("Unsupported annotation argument type: ${value.type} (expected $expectedType)")
else -> return null
}
return result
}
private fun <T> const(kind: FirConstKind<T>, value: T) = buildConstExpression(null, kind, value)
}
@@ -0,0 +1,248 @@
/*
* 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.deserialization
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltInsSettings
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.*
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirCloneableSymbolProvider.Companion.CLONE
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirCloneableSymbolProvider.Companion.CLONEABLE_CLASS_ID
import org.jetbrains.kotlin.fir.resolve.transformers.sealedInheritors
import org.jetbrains.kotlin.fir.scopes.FirScopeProvider
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.types.ConeAttributes
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
import org.jetbrains.kotlin.metadata.deserialization.supertypes
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.ProtoEnumFlags
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
import org.jetbrains.kotlin.serialization.deserialization.getName
fun deserializeClassToSymbol(
classId: ClassId,
classProto: ProtoBuf.Class,
symbol: FirRegularClassSymbol,
nameResolver: NameResolver,
session: FirSession,
defaultAnnotationDeserializer: AbstractAnnotationDeserializer?,
scopeProvider: FirScopeProvider,
parentContext: FirDeserializationContext? = null,
containerSource: DeserializedContainerSource? = null,
deserializeNestedClass: (ClassId, FirDeserializationContext) -> FirRegularClassSymbol?
) {
val flags = classProto.flags
val kind = Flags.CLASS_KIND.get(flags)
val modality = ProtoEnumFlags.modality(Flags.MODALITY.get(flags))
val status = FirResolvedDeclarationStatusImpl(
FirProtoEnumFlags.visibility(Flags.VISIBILITY.get(flags)),
modality
).apply {
isExpect = Flags.IS_EXPECT_CLASS.get(flags)
isActual = false
isCompanion = kind == ProtoBuf.Class.Kind.COMPANION_OBJECT
isInner = Flags.IS_INNER.get(flags)
isData = Flags.IS_DATA.get(classProto.flags)
isInline = Flags.IS_INLINE_CLASS.get(classProto.flags)
}
val isSealed = modality == Modality.SEALED
val annotationDeserializer = defaultAnnotationDeserializer ?: FirBuiltinAnnotationDeserializer(session)
val context =
parentContext?.childContext(
classProto.typeParameterList,
nameResolver,
TypeTable(classProto.typeTable),
classId.relativeClassName,
containerSource,
annotationDeserializer,
status.isInner
) ?: FirDeserializationContext.createForClass(
classId, classProto, nameResolver, session,
annotationDeserializer,
FirConstDeserializer(session, (containerSource as? KotlinJvmBinarySourceElement)?.binaryClass),
containerSource
)
if (status.isCompanion) {
parentContext?.let {
context.annotationDeserializer.inheritAnnotationInfo(it.annotationDeserializer)
}
}
buildRegularClass {
this.session = session
origin = FirDeclarationOrigin.Library
name = classId.shortClassName
this.status = status
classKind = ProtoEnumFlags.classKind(kind)
this.scopeProvider = scopeProvider
this.symbol = symbol
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
typeParameters += context.typeDeserializer.ownTypeParameters.map { it.fir }
if (status.isInner)
typeParameters += parentContext?.allTypeParameters?.map { buildOuterClassTypeParameterRef { this.symbol = it } }.orEmpty()
val typeDeserializer = context.typeDeserializer
val classDeserializer = context.memberDeserializer
val superTypesDeserialized = classProto.supertypes(context.typeTable).map { supertypeProto ->
typeDeserializer.simpleType(supertypeProto, ConeAttributes.Empty)
}// TODO: + c.components.additionalClassPartsProvider.getSupertypes(this@DeserializedClassDescriptor)
superTypesDeserialized.mapNotNullTo(superTypeRefs) {
if (it == null) return@mapNotNullTo null
buildResolvedTypeRef { type = it }
}
addDeclarations(
classProto.functionList.map {
classDeserializer.loadFunction(it, classProto)
}
)
addDeclarations(
classProto.propertyList.map {
classDeserializer.loadProperty(it, classProto)
}
)
addDeclarations(
classProto.constructorList.map {
classDeserializer.loadConstructor(it, classProto, this)
}
)
addDeclarations(
classProto.nestedClassNameList.mapNotNull { nestedNameId ->
val nestedClassId = classId.createNestedClassId(Name.identifier(nameResolver.getString(nestedNameId)))
deserializeNestedClass(nestedClassId, context)?.fir
}
)
addDeclarations(
classProto.enumEntryList.mapNotNull { enumEntryProto ->
val enumEntryName = nameResolver.getName(enumEntryProto.name)
val enumType = ConeClassLikeTypeImpl(symbol.toLookupTag(), emptyArray(), false)
val property = buildEnumEntry {
this.session = session
origin = FirDeclarationOrigin.Library
returnTypeRef = buildResolvedTypeRef { type = enumType }
name = enumEntryName
this.symbol = FirVariableSymbol(CallableId(classId, enumEntryName))
this.status = FirResolvedDeclarationStatusImpl(
Visibilities.Public,
Modality.FINAL
).apply {
isStatic = true
}
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
}
property
}
)
if (classKind == ClassKind.ENUM_CLASS) {
generateValuesFunction(session, classId.packageFqName, classId.relativeClassName)
generateValueOfFunction(session, classId.packageFqName, classId.relativeClassName)
}
addCloneForArrayIfNeeded(classId)
addSerializableIfNeeded(classId)
}.also {
if (isSealed) {
it.sealedInheritors = classProto.sealedSubclassFqNameList.map { nameIndex ->
ClassId.fromString(nameResolver.getQualifiedClassName(nameIndex))
}
}
(it.annotations as MutableList<FirAnnotationCall>) +=
context.annotationDeserializer.loadClassAnnotations(classProto, context.nameResolver)
}
}
private val ARRAY = Name.identifier("Array")
private val ARRAY_CLASSES: Set<Name> = setOf(
ARRAY,
Name.identifier("ByteArray"),
Name.identifier("CharArray"),
Name.identifier("ShortArray"),
Name.identifier("IntArray"),
Name.identifier("LongArray"),
Name.identifier("FloatArray"),
Name.identifier("DoubleArray"),
Name.identifier("BooleanArray"),
)
private val JAVA_IO_SERIALIZABLE = ClassId.topLevel(FqName("java.io.Serializable"))
private fun FirRegularClassBuilder.addSerializableIfNeeded(classId: ClassId) {
if (!JvmBuiltInsSettings.isSerializableInJava(classId.asSingleFqName().toUnsafe())) return
superTypeRefs += buildResolvedTypeRef {
type = ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(JAVA_IO_SERIALIZABLE),
typeArguments = emptyArray(),
isNullable = false
)
}
}
private fun FirRegularClassBuilder.addCloneForArrayIfNeeded(classId: ClassId) {
if (classId.packageFqName != StandardNames.BUILT_INS_PACKAGE_FQ_NAME) return
if (classId.shortClassName !in ARRAY_CLASSES) return
superTypeRefs += buildResolvedTypeRef {
type = ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(CLONEABLE_CLASS_ID),
typeArguments = emptyArray(),
isNullable = false
)
}
declarations += buildSimpleFunction {
session = this@addCloneForArrayIfNeeded.session
origin = FirDeclarationOrigin.Library
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
returnTypeRef = buildResolvedTypeRef {
val typeArguments = if (classId.shortClassName == ARRAY) {
arrayOf(
ConeTypeParameterTypeImpl(
ConeTypeParameterLookupTag(this@addCloneForArrayIfNeeded.typeParameters.first().symbol), isNullable = false
)
)
} else {
emptyArray()
}
type = ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(classId),
typeArguments = typeArguments,
isNullable = false
)
}
status = FirResolvedDeclarationStatusImpl(Visibilities.Public, Modality.FINAL).apply {
isOverride = true
}
name = CLONE
symbol = FirNamedFunctionSymbol(CallableId(classId, CLONE))
}
}
@@ -0,0 +1,23 @@
/*
* 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.deserialization
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
class FirBuiltinAnnotationDeserializer(
session: FirSession
) : AbstractAnnotationDeserializer(session) {
override fun loadTypeAnnotations(typeProto: ProtoBuf.Type, nameResolver: NameResolver): List<FirAnnotationCall> {
if (!Flags.HAS_ANNOTATIONS.get(typeProto.flags)) return emptyList()
val annotations = typeProto.getExtension(protocol.typeAnnotation).orEmpty()
return annotations.map { deserializeAnnotation(it, nameResolver) }
}
}
@@ -0,0 +1,77 @@
/*
* 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.deserialization
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.expressions.FirConstKind
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
class FirConstDeserializer(
val session: FirSession,
private val partSource: KotlinJvmBinaryClass? = null,
private val facadeSource: KotlinJvmBinaryClass? = null
) {
companion object {
private val constantCache = mutableMapOf<CallableId, FirExpression>()
}
fun loadConstant(propertyProto: ProtoBuf.Property, callableId: CallableId, nameResolver: NameResolver): FirExpression? {
if (!Flags.HAS_CONSTANT.get(propertyProto.flags)) return null
constantCache[callableId]?.let { return it }
if (facadeSource == null && partSource == null) {
val value = propertyProto.getExtensionOrNull(BuiltInSerializerProtocol.compileTimeValue) ?: return null
return buildFirConstant(value, null, value.type.name, nameResolver)?.apply { constantCache[callableId] = this }
}
(facadeSource ?: partSource)!!.visitMembers(object : KotlinJvmBinaryClass.MemberVisitor {
override fun visitMethod(name: Name, desc: String): KotlinJvmBinaryClass.MethodAnnotationVisitor? = null
override fun visitField(name: Name, desc: String, initializer: Any?): KotlinJvmBinaryClass.AnnotationVisitor? {
if (initializer != null) {
val constant = buildFirConstant(null, initializer, desc, nameResolver)
constant?.let { constantCache[callableId.replaceName(name)] = it }
}
return null
}
}, null)
return constantCache[callableId]
}
private fun buildFirConstant(
protoValue: ProtoBuf.Annotation.Argument.Value?, sourceValue: Any?, constKind: String, nameResolver: NameResolver
): FirExpression? {
return when (constKind) {
"BYTE", "B" -> buildConstExpression(null, FirConstKind.Byte, ((protoValue?.intValue ?: sourceValue) as Number).toByte())
"CHAR", "C" -> buildConstExpression(null, FirConstKind.Char, ((protoValue?.intValue ?: sourceValue) as Number).toChar())
"SHORT", "S" -> buildConstExpression(null, FirConstKind.Short, ((protoValue?.intValue ?: sourceValue) as Number).toShort())
"INT", "I" -> buildConstExpression(null, FirConstKind.Int, protoValue?.intValue?.toInt() ?: sourceValue as Int)
"LONG", "J" -> buildConstExpression(null, FirConstKind.Long, (protoValue?.intValue ?: sourceValue) as Long)
"FLOAT", "F" -> buildConstExpression(null, FirConstKind.Float, (protoValue?.floatValue ?: sourceValue) as Float)
"DOUBLE", "D" -> buildConstExpression(null, FirConstKind.Double, (protoValue?.doubleValue ?: sourceValue) as Double)
"BOOLEAN", "Z" -> buildConstExpression(null, FirConstKind.Boolean, (protoValue?.intValue?.toInt() ?: sourceValue) != 0)
"STRING", "Ljava/lang/String" -> buildConstExpression(
null, FirConstKind.String, protoValue?.stringValue?.let { nameResolver.getString(it) } ?: sourceValue as String
)
else -> null
}
}
private fun CallableId.replaceName(newName: Name): CallableId {
return CallableId(this.packageName, this.className, newName)
}
}
@@ -0,0 +1,229 @@
/*
* 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.deserialization
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration
import org.jetbrains.kotlin.fir.contracts.builder.buildEffectDeclaration
import org.jetbrains.kotlin.fir.contracts.builder.buildResolvedContractDescription
import org.jetbrains.kotlin.fir.contracts.description.*
import org.jetbrains.kotlin.fir.contracts.toFirEffectDeclaration
import org.jetbrains.kotlin.fir.declarations.FirContractDescriptionOwner
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.expressions.LogicOperationKind
import org.jetbrains.kotlin.fir.types.ConeAttributes
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.isBoolean
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.deserialization.isInstanceType
import org.jetbrains.kotlin.utils.addIfNotNull
class FirContractDeserializer(private val c: FirDeserializationContext) {
fun loadContract(proto: ProtoBuf.Contract, owner: FirContractDescriptionOwner): FirContractDescription? {
val effects = proto.effectList.map { loadPossiblyConditionalEffect(it, owner) ?: return null }
return buildResolvedContractDescription {
this.effects += effects.map { it.toFirEffectDeclaration() }
}
}
private fun loadPossiblyConditionalEffect(
proto: ProtoBuf.Effect,
owner: FirContractDescriptionOwner
): ConeEffectDeclaration? {
if (proto.hasConclusionOfConditionalEffect()) {
val conclusion = loadExpression(proto.conclusionOfConditionalEffect, owner) ?: return null
val effect = loadSimpleEffect(proto, owner) ?: return null
return ConeConditionalEffectDeclaration(effect, conclusion)
}
return loadSimpleEffect(proto, owner)
}
private fun loadSimpleEffect(proto: ProtoBuf.Effect, owner: FirContractDescriptionOwner): ConeEffectDeclaration? {
val type: ProtoBuf.Effect.EffectType = if (proto.hasEffectType()) proto.effectType else return null
return when(type) {
ProtoBuf.Effect.EffectType.RETURNS_CONSTANT -> {
val argument = proto.effectConstructorArgumentList.firstOrNull()
val returnValue = if (argument == null) {
ConeConstantReference.WILDCARD
} else {
loadExpression(argument, owner) as? ConeConstantReference ?: return null
}
ConeReturnsEffectDeclaration(returnValue)
}
ProtoBuf.Effect.EffectType.RETURNS_NOT_NULL -> {
ConeReturnsEffectDeclaration(ConeConstantReference.NOT_NULL)
}
ProtoBuf.Effect.EffectType.CALLS -> {
val argument = proto.effectConstructorArgumentList.firstOrNull() ?: return null
val callable = extractVariable(argument, owner) ?: return null
val invocationKind = if (proto.hasKind())
proto.kind.toDescriptorInvocationKind() ?: return null
else
EventOccurrencesRange.UNKNOWN
ConeCallsEffectDeclaration(callable, invocationKind)
}
}
}
private fun loadExpression(proto: ProtoBuf.Expression, owner: FirContractDescriptionOwner): ConeBooleanExpression? {
val primitiveType = getPrimitiveType(proto)
val primitiveExpression = extractPrimitiveExpression(proto, primitiveType, owner)
val complexType = getComplexType(proto)
val childs: MutableList<ConeBooleanExpression> = mutableListOf()
childs.addIfNotNull(primitiveExpression)
return when (complexType) {
ComplexExpressionType.AND_SEQUENCE -> {
proto.andArgumentList.mapTo(childs) { loadExpression(it, owner) ?: return null }
childs.reduce { acc, booleanExpression -> ConeBinaryLogicExpression(acc, booleanExpression, LogicOperationKind.AND) }
}
ComplexExpressionType.OR_SEQUENCE -> {
proto.orArgumentList.mapTo(childs) { loadExpression(it, owner) ?: return null }
childs.reduce { acc, booleanExpression -> ConeBinaryLogicExpression(acc, booleanExpression, LogicOperationKind.OR) }
}
null -> primitiveExpression
}
}
private fun extractPrimitiveExpression(proto: ProtoBuf.Expression, primitiveType: PrimitiveExpressionType?, owner: FirContractDescriptionOwner): ConeBooleanExpression? {
val isInverted = Flags.IS_NEGATED.get(proto.flags)
return when (primitiveType) {
PrimitiveExpressionType.VALUE_PARAMETER_REFERENCE, PrimitiveExpressionType.RECEIVER_REFERENCE -> {
(extractVariable(proto, owner) as? ConeBooleanValueParameterReference?)?.invertIfNecessary(isInverted)
}
PrimitiveExpressionType.CONSTANT ->
(loadConstant(proto.constantValue) as? ConeBooleanConstantReference)?.invertIfNecessary(isInverted)
PrimitiveExpressionType.INSTANCE_CHECK -> {
val variable = extractVariable(proto, owner) ?: return null
val type = extractType(proto) ?: return null
ConeIsInstancePredicate(variable, type, isInverted)
}
PrimitiveExpressionType.NULLABILITY_CHECK -> {
val variable = extractVariable(proto, owner) ?: return null
ConeIsNullPredicate(variable, isInverted)
}
null -> null
}
}
private fun ConeBooleanExpression.invertIfNecessary(shouldInvert: Boolean): ConeBooleanExpression =
if (shouldInvert) ConeLogicalNot(this) else this
private fun extractVariable(proto: ProtoBuf.Expression, owner: FirContractDescriptionOwner): ConeValueParameterReference? {
if (!proto.hasValueParameterReference()) return null
val ownerFunction = owner as FirSimpleFunction
val valueParameterIndex = proto.valueParameterReference - 1
val name: String
val typeRef = if (valueParameterIndex < 0) {
name = "this"
ownerFunction.receiverTypeRef
} else {
val parameter = ownerFunction.valueParameters.getOrNull(valueParameterIndex) ?: return null
name = parameter.name.asString()
parameter.returnTypeRef
} ?: return null
return if (!typeRef.isBoolean)
ConeValueParameterReference(valueParameterIndex, name)
else
ConeBooleanValueParameterReference(valueParameterIndex, name)
}
private fun ProtoBuf.Effect.InvocationKind.toDescriptorInvocationKind(): EventOccurrencesRange? = when (this) {
ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE -> EventOccurrencesRange.AT_MOST_ONCE
ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE -> EventOccurrencesRange.EXACTLY_ONCE
ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE -> EventOccurrencesRange.AT_LEAST_ONCE
}
private fun extractType(proto: ProtoBuf.Expression): ConeKotlinType? {
return c.typeDeserializer.type(proto.isInstanceType(c.typeTable) ?: return null, ConeAttributes.Empty)
}
private fun loadConstant(value: ProtoBuf.Expression.ConstantValue): ConeConstantReference? = when (value) {
ProtoBuf.Expression.ConstantValue.TRUE -> ConeBooleanConstantReference.TRUE
ProtoBuf.Expression.ConstantValue.FALSE -> ConeBooleanConstantReference.FALSE
ProtoBuf.Expression.ConstantValue.NULL -> ConeConstantReference.NULL
}
private fun getComplexType(proto: ProtoBuf.Expression): ComplexExpressionType? {
val isOrSequence = proto.orArgumentCount != 0
val isAndSequence = proto.andArgumentCount != 0
return when {
isOrSequence && isAndSequence -> null
isOrSequence -> ComplexExpressionType.OR_SEQUENCE
isAndSequence -> ComplexExpressionType.AND_SEQUENCE
else -> null
}
}
private fun getPrimitiveType(proto: ProtoBuf.Expression): PrimitiveExpressionType? {
// Expected to be one element, but can be empty (unknown expression) or contain several elements (invalid data)
val expressionTypes: MutableList<PrimitiveExpressionType> = mutableListOf()
// Check for predicates
when {
proto.hasValueParameterReference() && proto.hasType() ->
expressionTypes.add(PrimitiveExpressionType.INSTANCE_CHECK)
proto.hasValueParameterReference() && Flags.IS_NULL_CHECK_PREDICATE.get(proto.flags) ->
expressionTypes.add(PrimitiveExpressionType.NULLABILITY_CHECK)
}
// If message contains correct predicate, then predicate's type overrides type of value,
// even is message has one
if (expressionTypes.isNotEmpty()) {
return expressionTypes.singleOrNull()
}
// Otherwise, check if it is a value
when {
proto.hasValueParameterReference() && proto.valueParameterReference > 0 ->
expressionTypes.add(PrimitiveExpressionType.VALUE_PARAMETER_REFERENCE)
proto.hasValueParameterReference() && proto.valueParameterReference == 0 ->
expressionTypes.add(PrimitiveExpressionType.RECEIVER_REFERENCE)
proto.hasConstantValue() -> expressionTypes.add(PrimitiveExpressionType.CONSTANT)
}
return expressionTypes.singleOrNull()
}
private fun ProtoBuf.Expression.hasType(): Boolean = this.hasIsInstanceType() || this.hasIsInstanceTypeId()
// Arguments of expressions with such types are never other expressions
private enum class PrimitiveExpressionType {
VALUE_PARAMETER_REFERENCE,
RECEIVER_REFERENCE,
CONSTANT,
INSTANCE_CHECK,
NULLABILITY_CHECK
}
// Expressions with such type can take other expressions as arguments.
// Additionally, for performance reasons, "complex expression" and "primitive expression"
// can co-exist in the one and the same message. If "primitive expression" is present
// in the current message, it is treated as the first argument of "complex expression".
private enum class ComplexExpressionType {
AND_SEQUENCE,
OR_SEQUENCE
}
}
@@ -0,0 +1,491 @@
/*
* 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.deserialization
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.*
import org.jetbrains.kotlin.fir.declarations.impl.*
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.builder.buildExpressionStub
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeAttributes
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.computeTypeAttributes
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.fir.types.impl.FirImplicitUnitTypeRef
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.serialization.deserialization.ProtoEnumFlags
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
import org.jetbrains.kotlin.serialization.deserialization.getName
class FirDeserializationContext(
val nameResolver: NameResolver,
val typeTable: TypeTable,
val versionRequirementTable: VersionRequirementTable,
val session: FirSession,
val packageFqName: FqName,
val relativeClassName: FqName?,
val typeDeserializer: FirTypeDeserializer,
val annotationDeserializer: AbstractAnnotationDeserializer,
val constDeserializer: FirConstDeserializer,
val containerSource: DeserializedContainerSource?,
outerTypeParameters: List<FirTypeParameterSymbol>,
val components: FirDeserializationComponents
) {
val allTypeParameters: List<FirTypeParameterSymbol> =
typeDeserializer.ownTypeParameters + outerTypeParameters
fun childContext(
typeParameterProtos: List<ProtoBuf.TypeParameter>,
nameResolver: NameResolver = this.nameResolver,
typeTable: TypeTable = this.typeTable,
relativeClassName: FqName? = this.relativeClassName,
containerSource: DeserializedContainerSource? = this.containerSource,
annotationDeserializer: AbstractAnnotationDeserializer = this.annotationDeserializer,
capturesTypeParameters: Boolean = true
): FirDeserializationContext = FirDeserializationContext(
nameResolver, typeTable, versionRequirementTable, session, packageFqName, relativeClassName,
FirTypeDeserializer(
session, nameResolver, typeTable, typeParameterProtos, typeDeserializer
),
annotationDeserializer, constDeserializer, containerSource,
if (capturesTypeParameters) allTypeParameters else emptyList(), components
)
val memberDeserializer: FirMemberDeserializer = FirMemberDeserializer(this)
companion object {
fun createForPackage(
fqName: FqName,
packageProto: ProtoBuf.Package,
nameResolver: NameResolver,
session: FirSession,
annotationDeserializer: AbstractAnnotationDeserializer,
constDeserializer: FirConstDeserializer,
containerSource: DeserializedContainerSource?
) = createRootContext(
nameResolver,
TypeTable(packageProto.typeTable),
session,
annotationDeserializer,
constDeserializer,
fqName,
relativeClassName = null,
typeParameterProtos = emptyList(),
containerSource
)
fun createForClass(
classId: ClassId,
classProto: ProtoBuf.Class,
nameResolver: NameResolver,
session: FirSession,
annotationDeserializer: AbstractAnnotationDeserializer,
constDeserializer: FirConstDeserializer,
containerSource: DeserializedContainerSource?
) = createRootContext(
nameResolver,
TypeTable(classProto.typeTable),
session,
annotationDeserializer,
constDeserializer,
classId.packageFqName,
classId.relativeClassName,
classProto.typeParameterList,
containerSource
)
private fun createRootContext(
nameResolver: NameResolver,
typeTable: TypeTable,
session: FirSession,
annotationDeserializer: AbstractAnnotationDeserializer,
constDeserializer: FirConstDeserializer,
packageFqName: FqName,
relativeClassName: FqName?,
typeParameterProtos: List<ProtoBuf.TypeParameter>,
containerSource: DeserializedContainerSource?
): FirDeserializationContext {
return FirDeserializationContext(
nameResolver, typeTable,
VersionRequirementTable.EMPTY, // TODO:
session,
packageFqName,
relativeClassName,
FirTypeDeserializer(
session,
nameResolver,
typeTable,
typeParameterProtos,
null
),
annotationDeserializer,
constDeserializer,
containerSource,
emptyList(),
FirDeserializationComponents()
)
}
}
}
// TODO: Move something here
class FirDeserializationComponents {
}
class FirMemberDeserializer(private val c: FirDeserializationContext) {
private val contractDeserializer = FirContractDeserializer(c)
private fun loadOldFlags(oldFlags: Int): Int {
val lowSixBits = oldFlags and 0x3f
val rest = (oldFlags shr 8) shl 6
return lowSixBits + rest
}
fun loadTypeAlias(proto: ProtoBuf.TypeAlias): FirTypeAlias {
val flags = proto.flags
val name = c.nameResolver.getName(proto.name)
val local = c.childContext(proto.typeParameterList)
val classId = ClassId(c.packageFqName, name)
return buildTypeAlias {
session = c.session
origin = FirDeclarationOrigin.Library
this.name = name
status = FirResolvedDeclarationStatusImpl(
FirProtoEnumFlags.visibility(Flags.VISIBILITY.get(flags)),
Modality.FINAL
).apply {
isExpect = Flags.IS_EXPECT_CLASS.get(flags)
isActual = false
}
symbol = FirTypeAliasSymbol(classId)
expandedTypeRef = buildResolvedTypeRef {
type = local.typeDeserializer.type(proto.underlyingType(c.typeTable), ConeAttributes.Empty)
}
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
typeParameters += local.typeDeserializer.ownTypeParameters.map { it.fir }
}
}
fun loadProperty(
proto: ProtoBuf.Property,
classProto: ProtoBuf.Class? = null
): FirProperty {
val flags = if (proto.hasFlags()) proto.flags else loadOldFlags(proto.oldFlags)
val callableName = c.nameResolver.getName(proto.name)
val callableId = CallableId(c.packageFqName, c.relativeClassName, callableName)
val symbol = FirPropertySymbol(callableId)
val local = c.childContext(proto.typeParameterList)
// Per documentation on Property.getter_flags in metadata.proto, if an accessor flags field is absent, its value should be computed
// by taking hasAnnotations/visibility/modality from property flags, and using false for the rest
val defaultAccessorFlags = Flags.getAccessorFlags(
Flags.HAS_ANNOTATIONS.get(flags),
Flags.VISIBILITY.get(flags),
Flags.MODALITY.get(flags),
false, false, false
)
val returnTypeRef = proto.returnType(c.typeTable).toTypeRef(local)
val hasGetter = Flags.HAS_GETTER.get(flags)
val receiverAnnotations = if (hasGetter && proto.hasReceiver()) {
c.annotationDeserializer.loadExtensionReceiverParameterAnnotations(
c.containerSource, proto, local.nameResolver, local.typeTable, AbstractAnnotationDeserializer.CallableKind.PROPERTY_GETTER
)
} else {
emptyList()
}
val getter = if (hasGetter) {
val getterFlags = if (proto.hasGetterFlags()) proto.getterFlags else defaultAccessorFlags
val visibility = FirProtoEnumFlags.visibility(Flags.VISIBILITY.get(getterFlags))
val modality = ProtoEnumFlags.modality(Flags.MODALITY.get(getterFlags))
if (Flags.IS_NOT_DEFAULT.get(getterFlags)) {
buildPropertyAccessor {
session = c.session
origin = FirDeclarationOrigin.Library
this.returnTypeRef = returnTypeRef
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
isGetter = true
status = FirResolvedDeclarationStatusImpl(visibility, modality)
annotations +=
c.annotationDeserializer.loadPropertyGetterAnnotations(
c.containerSource, proto, local.nameResolver, local.typeTable, getterFlags
)
this.symbol = FirPropertyAccessorSymbol()
}
} else {
FirDefaultPropertyGetter(null, c.session, FirDeclarationOrigin.Library, returnTypeRef, visibility)
}
} else {
null
}
val setter = if (Flags.HAS_SETTER.get(flags)) {
val setterFlags = if (proto.hasSetterFlags()) proto.setterFlags else defaultAccessorFlags
val visibility = FirProtoEnumFlags.visibility(Flags.VISIBILITY.get(setterFlags))
val modality = ProtoEnumFlags.modality(Flags.MODALITY.get(setterFlags))
if (Flags.IS_NOT_DEFAULT.get(setterFlags)) {
buildPropertyAccessor {
session = c.session
origin = FirDeclarationOrigin.Library
this.returnTypeRef = FirImplicitUnitTypeRef(source)
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
isGetter = false
status = FirResolvedDeclarationStatusImpl(visibility, modality)
annotations +=
c.annotationDeserializer.loadPropertySetterAnnotations(
c.containerSource, proto, local.nameResolver, local.typeTable, setterFlags
)
this.symbol = FirPropertyAccessorSymbol()
valueParameters += local.memberDeserializer.valueParameters(
listOf(proto.setterValueParameter),
proto,
AbstractAnnotationDeserializer.CallableKind.PROPERTY_SETTER,
classProto
)
}
} else {
FirDefaultPropertySetter(null, c.session, FirDeclarationOrigin.Library, returnTypeRef, visibility)
}
} else {
null
}
val isVar = Flags.IS_VAR.get(flags)
return buildProperty {
session = c.session
origin = FirDeclarationOrigin.Library
this.returnTypeRef = returnTypeRef
receiverTypeRef = proto.receiverType(c.typeTable)?.toTypeRef(local).apply {
annotations += receiverAnnotations
}
name = callableName
this.isVar = isVar
this.symbol = symbol
isLocal = false
status = FirResolvedDeclarationStatusImpl(
FirProtoEnumFlags.visibility(Flags.VISIBILITY.get(flags)),
ProtoEnumFlags.modality(Flags.MODALITY.get(flags))
).apply {
isExpect = Flags.IS_EXPECT_PROPERTY.get(flags)
isActual = false
isOverride = false
isConst = Flags.IS_CONST.get(flags)
isLateInit = Flags.IS_LATEINIT.get(flags)
}
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
typeParameters += local.typeDeserializer.ownTypeParameters.map { it.fir }
annotations +=
c.annotationDeserializer.loadPropertyAnnotations(c.containerSource, proto, local.nameResolver, local.typeTable)
annotations +=
c.annotationDeserializer.loadPropertyBackingFieldAnnotations(
c.containerSource, proto, local.nameResolver, local.typeTable
)
annotations +=
c.annotationDeserializer.loadPropertyDelegatedFieldAnnotations(
c.containerSource, proto, local.nameResolver, local.typeTable
)
this.getter = getter
this.setter = setter
this.containerSource = c.containerSource
this.initializer = c.constDeserializer.loadConstant(proto, symbol.callableId, c.nameResolver)
}
}
fun loadFunction(
proto: ProtoBuf.Function,
classProto: ProtoBuf.Class? = null
): FirSimpleFunction {
val flags = if (proto.hasFlags()) proto.flags else loadOldFlags(proto.oldFlags)
val receiverAnnotations = if (proto.hasReceiver()) {
c.annotationDeserializer.loadExtensionReceiverParameterAnnotations(
c.containerSource, proto, c.nameResolver, c.typeTable, AbstractAnnotationDeserializer.CallableKind.OTHERS
)
} else {
emptyList()
}
val versionRequirementTable =
// TODO: Support case for KOTLIN_SUSPEND_BUILT_IN_FUNCTION_FQ_NAME
c.versionRequirementTable
val callableName = c.nameResolver.getName(proto.name)
val callableId = CallableId(c.packageFqName, c.relativeClassName, callableName)
val symbol = FirNamedFunctionSymbol(callableId)
val local = c.childContext(proto.typeParameterList)
// TODO: support contracts
val simpleFunction = buildSimpleFunction {
session = c.session
origin = FirDeclarationOrigin.Library
returnTypeRef = proto.returnType(local.typeTable).toTypeRef(local)
receiverTypeRef = proto.receiverType(local.typeTable)?.toTypeRef(local).apply {
annotations += receiverAnnotations
}
name = callableName
status = FirResolvedDeclarationStatusImpl(
FirProtoEnumFlags.visibility(Flags.VISIBILITY.get(flags)),
ProtoEnumFlags.modality(Flags.MODALITY.get(flags))
).apply {
isExpect = Flags.IS_EXPECT_FUNCTION.get(flags)
isActual = false
isOverride = false
isOperator = Flags.IS_OPERATOR.get(flags)
isInfix = Flags.IS_INFIX.get(flags)
isInline = Flags.IS_INLINE.get(flags)
isTailRec = Flags.IS_TAILREC.get(flags)
isExternal = Flags.IS_EXTERNAL_FUNCTION.get(flags)
isSuspend = Flags.IS_SUSPEND.get(flags)
}
this.symbol = symbol
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
typeParameters += local.typeDeserializer.ownTypeParameters.map { it.fir }
valueParameters += local.memberDeserializer.valueParameters(
proto.valueParameterList,
proto,
AbstractAnnotationDeserializer.CallableKind.OTHERS,
classProto
)
annotations +=
c.annotationDeserializer.loadFunctionAnnotations(c.containerSource, proto, local.nameResolver, local.typeTable)
this.containerSource = c.containerSource
}
if (proto.hasContract()) {
val contractDescription = contractDeserializer.loadContract(proto.contract, simpleFunction)
if (contractDescription != null) {
simpleFunction.replaceContractDescription(contractDescription)
}
}
return simpleFunction
}
fun loadConstructor(
proto: ProtoBuf.Constructor,
classProto: ProtoBuf.Class,
classBuilder: FirRegularClassBuilder
): FirConstructor {
val flags = proto.flags
val relativeClassName = c.relativeClassName!!
val callableId = CallableId(c.packageFqName, relativeClassName, relativeClassName.shortName())
val symbol = FirConstructorSymbol(callableId)
val local = c.childContext(emptyList())
val isPrimary = !Flags.IS_SECONDARY.get(flags)
val typeParameters = classBuilder.typeParameters
val delegatedSelfType = buildResolvedTypeRef {
type = ConeClassLikeTypeImpl(
classBuilder.symbol.toLookupTag(),
typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) }.toTypedArray(),
false
)
}
return if (isPrimary) {
FirPrimaryConstructorBuilder()
} else {
FirConstructorBuilder()
}.apply {
session = c.session
origin = FirDeclarationOrigin.Library
returnTypeRef = delegatedSelfType
val visibility = FirProtoEnumFlags.visibility(Flags.VISIBILITY.get(flags))
status = FirResolvedDeclarationStatusImpl(
visibility,
Modality.FINAL
).apply {
isExpect = Flags.IS_EXPECT_FUNCTION.get(flags)
isActual = false
isOverride = false
isInner = classBuilder.status.isInner
}
this.symbol = symbol
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
this.typeParameters +=
typeParameters.filterIsInstance<FirTypeParameter>()
.map { buildConstructedClassTypeParameterRef { this.symbol = it.symbol } }
valueParameters += local.memberDeserializer.valueParameters(
proto.valueParameterList,
proto,
AbstractAnnotationDeserializer.CallableKind.OTHERS,
classProto,
addDefaultValue = classBuilder.symbol.classId == StandardClassIds.Enum
)
annotations +=
c.annotationDeserializer.loadConstructorAnnotations(c.containerSource, proto, local.nameResolver, local.typeTable)
}.build()
}
private fun defaultValue(flags: Int): FirExpression? {
if (Flags.DECLARES_DEFAULT_VALUE.get(flags)) {
return buildExpressionStub()
}
return null
}
private fun valueParameters(
valueParameters: List<ProtoBuf.ValueParameter>,
callableProto: MessageLite,
callableKind: AbstractAnnotationDeserializer.CallableKind,
classProto: ProtoBuf.Class?,
addDefaultValue: Boolean = false
): List<FirValueParameter> {
return valueParameters.mapIndexed { index, proto ->
val flags = if (proto.hasFlags()) proto.flags else 0
val name = c.nameResolver.getName(proto.name)
buildValueParameter {
session = c.session
origin = FirDeclarationOrigin.Library
returnTypeRef = proto.type(c.typeTable).toTypeRef(c)
this.name = name
symbol = FirVariableSymbol(name)
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
defaultValue = defaultValue(flags)
if (addDefaultValue) {
defaultValue = buildExpressionStub()
}
isCrossinline = Flags.IS_CROSSINLINE.get(flags)
isNoinline = Flags.IS_NOINLINE.get(flags)
isVararg = proto.varargElementType(c.typeTable) != null
annotations += c.annotationDeserializer.loadValueParameterAnnotations(
c.containerSource,
callableProto,
proto,
classProto,
c.nameResolver,
c.typeTable,
callableKind,
index,
)
}
}.toList()
}
private fun ProtoBuf.Type.toTypeRef(context: FirDeserializationContext): FirTypeRef {
return buildResolvedTypeRef {
annotations += context.annotationDeserializer.loadTypeAnnotations(this@toTypeRef, context.nameResolver)
val attributes = annotations.computeTypeAttributes()
type = context.typeDeserializer.type(this@toTypeRef, attributes)
}
}
}
@@ -0,0 +1,32 @@
/*
* 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.deserialization
import org.jetbrains.kotlin.fir.Visibilities
import org.jetbrains.kotlin.fir.Visibility
import org.jetbrains.kotlin.metadata.ProtoBuf
object FirProtoEnumFlags {
fun visibility(visibility: ProtoBuf.Visibility?): Visibility = when (visibility) {
ProtoBuf.Visibility.INTERNAL -> Visibilities.Internal
ProtoBuf.Visibility.PRIVATE -> Visibilities.Private
ProtoBuf.Visibility.PRIVATE_TO_THIS -> Visibilities.PrivateToThis
ProtoBuf.Visibility.PROTECTED -> Visibilities.Protected
ProtoBuf.Visibility.PUBLIC -> Visibilities.Public
ProtoBuf.Visibility.LOCAL -> Visibilities.Local
else -> Visibilities.Private
}
fun visibility(visibility: Visibility): ProtoBuf.Visibility = when (visibility) {
Visibilities.Internal -> ProtoBuf.Visibility.INTERNAL
Visibilities.Public -> ProtoBuf.Visibility.PUBLIC
Visibilities.Private -> ProtoBuf.Visibility.PRIVATE
Visibilities.PrivateToThis -> ProtoBuf.Visibility.PRIVATE_TO_THIS
Visibilities.Protected -> ProtoBuf.Visibility.PROTECTED
Visibilities.Local -> ProtoBuf.Visibility.LOCAL
else -> throw IllegalArgumentException("Unknown visibility: $visibility")
}
}
@@ -0,0 +1,244 @@
/*
* 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.deserialization
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRefsOwner
import org.jetbrains.kotlin.fir.declarations.addDefaultBoundIfNecessary
import org.jetbrains.kotlin.fir.declarations.builder.FirTypeParameterBuilder
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.firUnsafe
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.deserialization.ProtoEnumFlags
import org.jetbrains.kotlin.serialization.deserialization.getClassId
import org.jetbrains.kotlin.serialization.deserialization.getName
import org.jetbrains.kotlin.types.Variance
import java.util.*
class FirTypeDeserializer(
val session: FirSession,
val nameResolver: NameResolver,
val typeTable: TypeTable,
typeParameterProtos: List<ProtoBuf.TypeParameter>,
val parent: FirTypeDeserializer?
) {
private val typeParameterDescriptors: Map<Int, FirTypeParameterSymbol> = if (typeParameterProtos.isNotEmpty()) {
LinkedHashMap<Int, FirTypeParameterSymbol>()
} else {
mapOf()
}
private val typeParameterNames: Map<String, FirTypeParameterSymbol>
val ownTypeParameters: List<FirTypeParameterSymbol>
get() = typeParameterDescriptors.values.toList()
init {
if (typeParameterProtos.isNotEmpty()) {
typeParameterNames = mutableMapOf()
val result = typeParameterDescriptors as LinkedHashMap<Int, FirTypeParameterSymbol>
val builders = mutableListOf<FirTypeParameterBuilder>()
for (proto in typeParameterProtos) {
if (!proto.hasId()) continue
val name = nameResolver.getName(proto.name)
val symbol = FirTypeParameterSymbol().also {
typeParameterNames[name.asString()] = it
}
builders += FirTypeParameterBuilder().apply {
session = this@FirTypeDeserializer.session
origin = FirDeclarationOrigin.Library
this.name = name
this.symbol = symbol
variance = proto.variance.convertVariance()
isReified = proto.reified
}
result[proto.id] = symbol
}
for ((index, proto) in typeParameterProtos.withIndex()) {
val builder = builders[index]
builder.apply {
proto.upperBoundList.mapTo(bounds) {
buildResolvedTypeRef { type = type(it, ConeAttributes.Empty) }
}
addDefaultBoundIfNecessary()
}.build()
}
} else {
typeParameterNames = emptyMap()
}
}
private fun computeClassifier(fqNameIndex: Int): ConeClassLikeLookupTag? {
try {
val id = nameResolver.getClassId(fqNameIndex)
return ConeClassLikeLookupTagImpl(id)
} catch (e: Throwable) {
throw RuntimeException("Looking up for ${nameResolver.getClassId(fqNameIndex)}", e)
}
}
fun type(proto: ProtoBuf.Type, attributes: ConeAttributes): ConeKotlinType {
if (proto.hasFlexibleTypeCapabilitiesId()) {
val lowerBound = simpleType(proto, attributes)
val upperBound = simpleType(proto.flexibleUpperBound(typeTable)!!, attributes)
return ConeFlexibleType(lowerBound!!, upperBound!!)
//c.components.flexibleTypeDeserializer.create(proto, id, lowerBound, upperBound)
}
return simpleType(proto, attributes) ?: ConeKotlinErrorType(ConeSimpleDiagnostic("?!id:0", DiagnosticKind.DeserializationError))
}
private fun typeParameterSymbol(typeParameterId: Int): ConeTypeParameterLookupTag? =
typeParameterDescriptors[typeParameterId]?.toLookupTag() ?: parent?.typeParameterSymbol(typeParameterId)
private fun ProtoBuf.TypeParameter.Variance.convertVariance(): Variance {
return when (this) {
ProtoBuf.TypeParameter.Variance.IN -> Variance.IN_VARIANCE
ProtoBuf.TypeParameter.Variance.OUT -> Variance.OUT_VARIANCE
ProtoBuf.TypeParameter.Variance.INV -> Variance.INVARIANT
}
}
fun FirClassLikeSymbol<*>.typeParameters(): List<FirTypeParameterSymbol> =
(fir as? FirTypeParameterRefsOwner)?.typeParameters?.map { it.symbol }.orEmpty()
fun simpleType(proto: ProtoBuf.Type, attributes: ConeAttributes): ConeLookupTagBasedType? {
val constructor = typeSymbol(proto) ?: return null
if (constructor is ConeTypeParameterLookupTag) return ConeTypeParameterTypeImpl(constructor, isNullable = proto.nullable)
if (constructor !is ConeClassLikeLookupTag) return null
fun ProtoBuf.Type.collectAllArguments(): List<ProtoBuf.Type.Argument> =
argumentList + outerType(typeTable)?.collectAllArguments().orEmpty()
val arguments = proto.collectAllArguments().map(this::typeArgument).toTypedArray()
val simpleType = if (Flags.SUSPEND_TYPE.get(proto.flags)) {
createSuspendFunctionType(constructor, arguments, isNullable = proto.nullable, attributes)
} else {
ConeClassLikeTypeImpl(constructor, arguments, isNullable = proto.nullable, attributes)
}
val abbreviatedTypeProto = proto.abbreviatedType(typeTable) ?: return simpleType
return simpleType(abbreviatedTypeProto, attributes)
}
private fun createSuspendFunctionTypeForBasicCase(
//annotations: Annotations, TODO?,
functionTypeConstructor: ConeClassLikeLookupTag,
arguments: Array<ConeTypeProjection>,
isNullable: Boolean,
attributes: ConeAttributes
): ConeClassLikeType? {
fun ConeClassLikeType.isContinuation(): Boolean {
if (this.typeArguments.size != 1) return false
if (this.lookupTag.classId != CONTINUATION_INTERFACE_CLASS_ID) return false
return true
}
val returnType = arguments.lastOrNull()
val continuationType = arguments.getOrNull(arguments.lastIndex - 1) as? ConeClassLikeType ?: return null
if (!continuationType.isContinuation()) return ConeClassLikeTypeImpl(functionTypeConstructor, arguments, isNullable, attributes)
val suspendReturnType = continuationType.typeArguments.single() as ConeKotlinTypeProjection
val valueParameters = arguments.dropLast(2)
val kind = FunctionClassKind.SuspendFunction
return ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(ClassId(kind.packageFqName, kind.numberedClassName(valueParameters.size))),
(valueParameters + suspendReturnType).toTypedArray(),
isNullable, attributes
)
}
private fun createSuspendFunctionType(
//annotations: Annotations, TODO?
functionTypeConstructor: ConeClassLikeLookupTag,
arguments: Array<ConeTypeProjection>,
isNullable: Boolean,
attributes: ConeAttributes
): ConeClassLikeType {
val result =
when (functionTypeConstructor.toSymbol(session)!!.firUnsafe<FirTypeParameterRefsOwner>().typeParameters.size - arguments.size) {
0 -> createSuspendFunctionTypeForBasicCase(/* annotations, */ functionTypeConstructor, arguments, isNullable, attributes)
// This case for types written by eap compiler 1.1
1 -> {
val arity = arguments.size - 1
if (arity >= 0) {
val kind = FunctionClassKind.SuspendFunction
ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(ClassId(kind.packageFqName, kind.numberedClassName(arity))),
arguments,
isNullable,
attributes
)
} else {
null
}
}
else -> null
}
return result ?: ConeClassErrorType(
ConeSimpleDiagnostic(
"Bad suspend function in metadata with constructor: $functionTypeConstructor",
DiagnosticKind.DeserializationError
)
)
}
private fun typeSymbol(proto: ProtoBuf.Type): ConeClassifierLookupTag? {
return when {
proto.hasClassName() -> computeClassifier(proto.className)
proto.hasTypeAliasName() -> computeClassifier(proto.typeAliasName)
proto.hasTypeParameter() -> typeParameterSymbol(proto.typeParameter)
proto.hasTypeParameterName() -> {
val name = nameResolver.getString(proto.typeParameterName)
typeParameterNames[name]?.toLookupTag()
}
else -> null
}
}
private fun typeArgument(typeArgumentProto: ProtoBuf.Type.Argument): ConeTypeProjection {
if (typeArgumentProto.projection == ProtoBuf.Type.Argument.Projection.STAR) {
return ConeStarProjection
}
val variance = ProtoEnumFlags.variance(typeArgumentProto.projection)
val type = typeArgumentProto.type(typeTable)
?: return ConeKotlinErrorType(ConeSimpleDiagnostic("No type recorded", DiagnosticKind.DeserializationError))
// TODO: check that here we don't have any attributes
val coneType = type(type, ConeAttributes.Empty)
return coneType.toTypeProjection(variance)
}
}
@@ -0,0 +1,12 @@
/*
* 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.deserialization
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.name.ClassId
val CONTINUATION_INTERFACE_CLASS_ID = ClassId.topLevel(StandardNames.CONTINUATION_INTERFACE_FQ_NAME_RELEASE)
@@ -0,0 +1,324 @@
/*
* 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.resolve.providers.impl
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildRegularClass
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction
import org.jetbrains.kotlin.fir.declarations.builder.buildTypeParameter
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.deserialization.FirBuiltinAnnotationDeserializer
import org.jetbrains.kotlin.fir.deserialization.FirConstDeserializer
import org.jetbrains.kotlin.fir.deserialization.FirDeserializationContext
import org.jetbrains.kotlin.fir.deserialization.deserializeClassToSymbol
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
import org.jetbrains.kotlin.fir.scopes.KotlinScopeProvider
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.constructClassType
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.builtins.BuiltInsBinaryVersion
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.ProtoBasedClassDataFinder
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.serialization.deserialization.getName
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import org.jetbrains.kotlin.utils.addToStdlib.getOrPut
import java.io.InputStream
class FirBuiltinSymbolProvider(session: FirSession, val kotlinScopeProvider: KotlinScopeProvider) : FirSymbolProvider(session) {
private data class SyntheticFunctionalInterfaceSymbolKey(val kind: FunctionClassKind, val arity: Int)
private val allPackageFragments = loadBuiltIns().groupBy { it.fqName }
private val syntheticFunctionalInterfaceSymbols = mutableMapOf<SyntheticFunctionalInterfaceSymbolKey, FirRegularClassSymbol>()
private fun loadBuiltIns(): List<BuiltInsPackageFragment> {
val classLoader = this::class.java.classLoader
val streamProvider = { path: String -> classLoader?.getResourceAsStream(path) ?: ClassLoader.getSystemResourceAsStream(path) }
val packageFqNames = StandardNames.BUILT_INS_PACKAGE_FQ_NAMES
return packageFqNames.map { fqName ->
val resourcePath = BuiltInSerializerProtocol.getBuiltInsFilePath(fqName)
val inputStream = streamProvider(resourcePath) ?: throw IllegalStateException("Resource not found in classpath: $resourcePath")
BuiltInsPackageFragment(inputStream, fqName, session, kotlinScopeProvider)
}
}
override fun getPackage(fqName: FqName): FqName? {
if (allPackageFragments.containsKey(fqName)) return fqName
return null
}
override fun getClassLikeSymbolByFqName(classId: ClassId): FirRegularClassSymbol? {
return allPackageFragments[classId.packageFqName]?.firstNotNullResult {
it.getClassLikeSymbolByFqName(classId)
} ?: trySyntheticFunctionalInterface(classId)
}
private fun trySyntheticFunctionalInterface(classId: ClassId): FirRegularClassSymbol? {
return with(classId) {
val className = relativeClassName.asString()
val kind = FunctionClassKind.byClassNamePrefix(packageFqName, className) ?: return@with null
val prefix = kind.classNamePrefix
val arity = className.substring(prefix.length).toIntOrNull() ?: return null
syntheticFunctionalInterfaceSymbols.getOrPut(SyntheticFunctionalInterfaceSymbolKey(kind, arity)) {
FirRegularClassSymbol(this).apply symbol@{
buildRegularClass klass@{
session = this@FirBuiltinSymbolProvider.session
origin = FirDeclarationOrigin.Synthetic
name = relativeClassName.shortName()
status = FirResolvedDeclarationStatusImpl(
Visibilities.Public,
Modality.ABSTRACT
).apply {
isExpect = false
isActual = false
isInner = false
isCompanion = false
isData = false
isInline = false
}
classKind = ClassKind.INTERFACE
scopeProvider = kotlinScopeProvider
symbol = this@symbol
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
typeParameters.addAll(
(1..arity).map {
buildTypeParameter {
session = this@FirBuiltinSymbolProvider.session
origin = FirDeclarationOrigin.Synthetic
name = Name.identifier("P$it")
symbol = FirTypeParameterSymbol()
variance = Variance.IN_VARIANCE
isReified = false
bounds += session.builtinTypes.nullableAnyType
}
},
)
typeParameters.add(
buildTypeParameter {
session = this@FirBuiltinSymbolProvider.session
origin = FirDeclarationOrigin.Synthetic
name = Name.identifier("R")
symbol = FirTypeParameterSymbol()
variance = Variance.OUT_VARIANCE
isReified = false
bounds += session.builtinTypes.nullableAnyType
},
)
val name = OperatorNameConventions.INVOKE
val functionStatus = FirResolvedDeclarationStatusImpl(
Visibilities.Public,
Modality.ABSTRACT
).apply {
isExpect = false
isActual = false
isOverride = false
isOperator = true
isInfix = false
isInline = false
isTailRec = false
isExternal = false
isSuspend =
kind == FunctionClassKind.SuspendFunction ||
kind == FunctionClassKind.KSuspendFunction
}
val typeArguments = typeParameters.map {
buildResolvedTypeRef {
type = ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false)
}
}
val superKind: FunctionClassKind? = when (kind) {
FunctionClassKind.KFunction -> FunctionClassKind.Function
FunctionClassKind.KSuspendFunction -> FunctionClassKind.SuspendFunction
else -> null
}
fun createSuperType(
kind: FunctionClassKind,
): FirResolvedTypeRef {
return buildResolvedTypeRef {
type = ConeClassLikeLookupTagImpl(kind.classId(arity))
.constructClassType(typeArguments.map { it.type }.toTypedArray(), isNullable = false)
}
}
superTypeRefs += when (kind) {
FunctionClassKind.Function -> listOf(
buildResolvedTypeRef {
type = ConeClassLikeLookupTagImpl(StandardClassIds.Function)
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
}
)
FunctionClassKind.SuspendFunction -> listOf(
buildResolvedTypeRef {
type = ConeClassLikeLookupTagImpl(StandardClassIds.Function)
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
}
)
FunctionClassKind.KFunction -> listOf(
buildResolvedTypeRef {
type = ConeClassLikeLookupTagImpl(StandardClassIds.KFunction)
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
},
createSuperType(FunctionClassKind.Function)
)
FunctionClassKind.KSuspendFunction -> listOf(
buildResolvedTypeRef {
type = ConeClassLikeLookupTagImpl(StandardClassIds.KFunction)
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
},
createSuperType(FunctionClassKind.SuspendFunction)
)
}
addDeclaration(
buildSimpleFunction {
session = this@FirBuiltinSymbolProvider.session
origin = FirDeclarationOrigin.Synthetic
returnTypeRef = typeArguments.last()
this.name = name
status = functionStatus
symbol = FirNamedFunctionSymbol(
CallableId(packageFqName, relativeClassName, name),
// set overriddenSymbol for "invoke" of KFunction/KSuspendFunction
superKind != null, superKind?.getInvoke(arity)
)
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
valueParameters += typeArguments.dropLast(1).mapIndexed { index, typeArgument ->
val parameterName = Name.identifier("p${index + 1}")
buildValueParameter {
session = this@FirBuiltinSymbolProvider.session
origin = FirDeclarationOrigin.Synthetic
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
returnTypeRef = typeArgument
this.name = parameterName
symbol = FirVariableSymbol(parameterName)
defaultValue = null
isCrossinline = false
isNoinline = false
isVararg = false
}
}
}
)
}
}
}
}
}
// Find the symbol for "invoke" in the function class
private fun FunctionClassKind.getInvoke(arity: Int): FirNamedFunctionSymbol? {
val functionClass = getClassLikeSymbolByFqName(classId(arity)) ?: return null
val invoke =
functionClass.fir.declarations.find { it is FirSimpleFunction && it.name == OperatorNameConventions.INVOKE } ?: return null
return (invoke as FirSimpleFunction).symbol as? FirNamedFunctionSymbol
}
private fun FunctionClassKind.classId(arity: Int) = ClassId(packageFqName, numberedClassName(arity))
@FirSymbolProviderInternals
override fun getTopLevelCallableSymbolsTo(destination: MutableList<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) {
allPackageFragments[packageFqName]?.flatMapTo(destination) {
it.getTopLevelCallableSymbols(name)
}
}
private class BuiltInsPackageFragment(
stream: InputStream, val fqName: FqName, val session: FirSession,
val kotlinScopeProvider: KotlinScopeProvider,
) {
lateinit var version: BuiltInsBinaryVersion
val packageProto: ProtoBuf.PackageFragment = run {
version = BuiltInsBinaryVersion.readFrom(stream)
if (!version.isCompatible()) {
// TODO: report a proper diagnostic
throw UnsupportedOperationException(
"Kotlin built-in definition format version is not supported: " +
"expected ${BuiltInsBinaryVersion.INSTANCE}, actual $version. " +
"Please update Kotlin",
)
}
ProtoBuf.PackageFragment.parseFrom(stream, BuiltInSerializerProtocol.extensionRegistry)
}
private val nameResolver = NameResolverImpl(packageProto.strings, packageProto.qualifiedNames)
val classDataFinder = ProtoBasedClassDataFinder(packageProto, nameResolver, version) { SourceElement.NO_SOURCE }
private val memberDeserializer by lazy {
FirDeserializationContext.createForPackage(
fqName, packageProto.`package`, nameResolver, session,
FirBuiltinAnnotationDeserializer(session),
FirConstDeserializer(session),
containerSource = null
).memberDeserializer
}
private val lookup = mutableMapOf<ClassId, FirRegularClassSymbol>()
fun getClassLikeSymbolByFqName(classId: ClassId): FirRegularClassSymbol? =
findAndDeserializeClass(classId)
private fun findAndDeserializeClass(
classId: ClassId,
parentContext: FirDeserializationContext? = null,
): FirRegularClassSymbol? {
val classIdExists = classId in classDataFinder.allClassIds
if (!classIdExists) return null
return lookup.getOrPut(classId, { FirRegularClassSymbol(classId) }) { symbol ->
val classData = classDataFinder.findClassData(classId)!!
val classProto = classData.classProto
deserializeClassToSymbol(
classId, classProto, symbol, nameResolver, session,
null, kotlinScopeProvider, parentContext,
null,
this::findAndDeserializeClass,
)
}
}
fun getTopLevelCallableSymbols(name: Name): List<FirCallableSymbol<*>> {
return packageProto.`package`.functionList.filter { nameResolver.getName(it.name) == name }.map {
memberDeserializer.loadFunction(it).symbol
}
}
fun getAllCallableNames(): Set<Name> {
return packageProto.`package`.functionList.mapTo(mutableSetOf()) { nameResolver.getName(it.name) }
}
fun getAllClassNames(): Set<Name> {
return classDataFinder.allClassIds.mapTo(mutableSetOf()) { it.shortClassName }
}
}
}