Implement constant deserializer for fir

This deserializer is uniform loader, that is responsible for loading
all constants. For example, Math.E, UInt.MAX_VALUE or Float.MIN_VALUE.
This commit is contained in:
Ivan Kylchik
2020-06-22 13:55:45 +03:00
parent b62e22cb01
commit 6c6b7c8b84
5 changed files with 97 additions and 6 deletions
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.FirVariable
import org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl
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.diagnostics.ConeSimpleDiagnostic
@@ -112,6 +113,10 @@ class KotlinDeserializedJvmSymbolsProvider(
val (kotlinJvmBinaryClass, byteContent) =
kotlinClassFinder.findKotlinClassOrContent(classId) as? KotlinClassFinder.Result.KotlinClass ?: return@mapNotNull null
val facadeName = kotlinJvmBinaryClass.classHeader.multifileClassName?.takeIf { it.isNotEmpty() }
val facadeFqName = facadeName?.let { JvmClassName.byInternalName(it).fqNameForTopLevelClassMaybeWithDollars }
val facadeBinaryClass = facadeFqName?.let { kotlinClassFinder.findKotlinClass(ClassId.topLevel(it)) }
val header = kotlinJvmBinaryClass.classHeader
val data = header.data ?: header.incompatibleData ?: return@mapNotNull null
val strings = header.strings ?: return@mapNotNull null
@@ -127,6 +132,7 @@ class KotlinDeserializedJvmSymbolsProvider(
FirDeserializationContext.createForPackage(
packageFqName, packageProto, nameResolver, session,
JvmBinaryAnnotationDeserializer(session, kotlinJvmBinaryClass, byteContent),
FirConstDeserializer(session, kotlinJvmBinaryClass, facadeBinaryClass),
source
),
source,
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
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
@@ -81,6 +82,7 @@ fun deserializeClassToSymbol(
) ?: FirDeserializationContext.createForClass(
classId, classProto, nameResolver, session,
defaultAnnotationDeserializer ?: FirBuiltinAnnotationDeserializer(session),
FirConstDeserializer(session, (containerSource as? KotlinJvmBinarySourceElement)?.binaryClass),
containerSource
)
buildRegularClass {
@@ -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)
}
}
@@ -40,6 +40,7 @@ class FirDeserializationContext(
val relativeClassName: FqName?,
val typeDeserializer: FirTypeDeserializer,
val annotationDeserializer: AbstractAnnotationDeserializer,
val constDeserializer: FirConstDeserializer,
val containerSource: DeserializedContainerSource?,
outerTypeParameters: List<FirTypeParameterSymbol>,
val components: FirDeserializationComponents
@@ -58,7 +59,8 @@ class FirDeserializationContext(
FirTypeDeserializer(
session, nameResolver, typeTable, typeParameterProtos, typeDeserializer
),
annotationDeserializer, containerSource, if (capturesTypeParameters) allTypeParameters else emptyList(), components
annotationDeserializer, constDeserializer, containerSource,
if (capturesTypeParameters) allTypeParameters else emptyList(), components
)
val memberDeserializer: FirMemberDeserializer = FirMemberDeserializer(this)
@@ -70,12 +72,14 @@ class FirDeserializationContext(
nameResolver: NameResolver,
session: FirSession,
annotationDeserializer: AbstractAnnotationDeserializer,
constDeserializer: FirConstDeserializer,
containerSource: DeserializedContainerSource?
) = createRootContext(
nameResolver,
TypeTable(packageProto.typeTable),
session,
annotationDeserializer,
constDeserializer,
fqName,
relativeClassName = null,
typeParameterProtos = emptyList(),
@@ -88,12 +92,14 @@ class FirDeserializationContext(
nameResolver: NameResolver,
session: FirSession,
annotationDeserializer: AbstractAnnotationDeserializer,
constDeserializer: FirConstDeserializer,
containerSource: DeserializedContainerSource?
) = createRootContext(
nameResolver,
TypeTable(classProto.typeTable),
session,
annotationDeserializer,
constDeserializer,
classId.packageFqName,
classId.relativeClassName,
classProto.typeParameterList,
@@ -105,6 +111,7 @@ class FirDeserializationContext(
typeTable: TypeTable,
session: FirSession,
annotationDeserializer: AbstractAnnotationDeserializer,
constDeserializer: FirConstDeserializer,
packageFqName: FqName,
relativeClassName: FqName?,
typeParameterProtos: List<ProtoBuf.TypeParameter>,
@@ -124,6 +131,7 @@ class FirDeserializationContext(
null
),
annotationDeserializer,
constDeserializer,
containerSource,
emptyList(),
FirDeserializationComponents()
@@ -272,11 +280,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
this.getter = getter
this.setter = setter
this.containerSource = c.containerSource
this.initializer = if (Flags.HAS_CONSTANT.get(flags)) {
proto.getExtensionOrNull(BuiltInSerializerProtocol.compileTimeValue)?.let {
c.annotationDeserializer.resolveValue(returnTypeRef, it, c.nameResolver)
}
} else null
this.initializer = c.constDeserializer.loadConstant(proto, symbol.callableId, c.nameResolver)
}
}
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.declarations.builder.buildTypeParameter
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
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
@@ -78,6 +79,7 @@ class FirBuiltinSymbolProvider(val session: FirSession, val kotlinScopeProvider:
FirDeserializationContext.createForPackage(
fqName, packageProto.`package`, nameResolver, session,
FirBuiltinAnnotationDeserializer(session),
FirConstDeserializer(session),
containerSource = null
).memberDeserializer
}