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.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.FirVariable import org.jetbrains.kotlin.fir.declarations.FirVariable
import org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl 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.FirDeserializationContext
import org.jetbrains.kotlin.fir.deserialization.deserializeClassToSymbol import org.jetbrains.kotlin.fir.deserialization.deserializeClassToSymbol
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
@@ -112,6 +113,10 @@ class KotlinDeserializedJvmSymbolsProvider(
val (kotlinJvmBinaryClass, byteContent) = val (kotlinJvmBinaryClass, byteContent) =
kotlinClassFinder.findKotlinClassOrContent(classId) as? KotlinClassFinder.Result.KotlinClass ?: return@mapNotNull null 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 header = kotlinJvmBinaryClass.classHeader
val data = header.data ?: header.incompatibleData ?: return@mapNotNull null val data = header.data ?: header.incompatibleData ?: return@mapNotNull null
val strings = header.strings ?: return@mapNotNull null val strings = header.strings ?: return@mapNotNull null
@@ -127,6 +132,7 @@ class KotlinDeserializedJvmSymbolsProvider(
FirDeserializationContext.createForPackage( FirDeserializationContext.createForPackage(
packageFqName, packageProto, nameResolver, session, packageFqName, packageProto, nameResolver, session,
JvmBinaryAnnotationDeserializer(session, kotlinJvmBinaryClass, byteContent), JvmBinaryAnnotationDeserializer(session, kotlinJvmBinaryClass, byteContent),
FirConstDeserializer(session, kotlinJvmBinaryClass, facadeBinaryClass),
source source
), ),
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.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl 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.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.Flags import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.deserialization.NameResolver import org.jetbrains.kotlin.metadata.deserialization.NameResolver
@@ -81,6 +82,7 @@ fun deserializeClassToSymbol(
) ?: FirDeserializationContext.createForClass( ) ?: FirDeserializationContext.createForClass(
classId, classProto, nameResolver, session, classId, classProto, nameResolver, session,
defaultAnnotationDeserializer ?: FirBuiltinAnnotationDeserializer(session), defaultAnnotationDeserializer ?: FirBuiltinAnnotationDeserializer(session),
FirConstDeserializer(session, (containerSource as? KotlinJvmBinarySourceElement)?.binaryClass),
containerSource containerSource
) )
buildRegularClass { 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 relativeClassName: FqName?,
val typeDeserializer: FirTypeDeserializer, val typeDeserializer: FirTypeDeserializer,
val annotationDeserializer: AbstractAnnotationDeserializer, val annotationDeserializer: AbstractAnnotationDeserializer,
val constDeserializer: FirConstDeserializer,
val containerSource: DeserializedContainerSource?, val containerSource: DeserializedContainerSource?,
outerTypeParameters: List<FirTypeParameterSymbol>, outerTypeParameters: List<FirTypeParameterSymbol>,
val components: FirDeserializationComponents val components: FirDeserializationComponents
@@ -58,7 +59,8 @@ class FirDeserializationContext(
FirTypeDeserializer( FirTypeDeserializer(
session, nameResolver, typeTable, typeParameterProtos, typeDeserializer 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) val memberDeserializer: FirMemberDeserializer = FirMemberDeserializer(this)
@@ -70,12 +72,14 @@ class FirDeserializationContext(
nameResolver: NameResolver, nameResolver: NameResolver,
session: FirSession, session: FirSession,
annotationDeserializer: AbstractAnnotationDeserializer, annotationDeserializer: AbstractAnnotationDeserializer,
constDeserializer: FirConstDeserializer,
containerSource: DeserializedContainerSource? containerSource: DeserializedContainerSource?
) = createRootContext( ) = createRootContext(
nameResolver, nameResolver,
TypeTable(packageProto.typeTable), TypeTable(packageProto.typeTable),
session, session,
annotationDeserializer, annotationDeserializer,
constDeserializer,
fqName, fqName,
relativeClassName = null, relativeClassName = null,
typeParameterProtos = emptyList(), typeParameterProtos = emptyList(),
@@ -88,12 +92,14 @@ class FirDeserializationContext(
nameResolver: NameResolver, nameResolver: NameResolver,
session: FirSession, session: FirSession,
annotationDeserializer: AbstractAnnotationDeserializer, annotationDeserializer: AbstractAnnotationDeserializer,
constDeserializer: FirConstDeserializer,
containerSource: DeserializedContainerSource? containerSource: DeserializedContainerSource?
) = createRootContext( ) = createRootContext(
nameResolver, nameResolver,
TypeTable(classProto.typeTable), TypeTable(classProto.typeTable),
session, session,
annotationDeserializer, annotationDeserializer,
constDeserializer,
classId.packageFqName, classId.packageFqName,
classId.relativeClassName, classId.relativeClassName,
classProto.typeParameterList, classProto.typeParameterList,
@@ -105,6 +111,7 @@ class FirDeserializationContext(
typeTable: TypeTable, typeTable: TypeTable,
session: FirSession, session: FirSession,
annotationDeserializer: AbstractAnnotationDeserializer, annotationDeserializer: AbstractAnnotationDeserializer,
constDeserializer: FirConstDeserializer,
packageFqName: FqName, packageFqName: FqName,
relativeClassName: FqName?, relativeClassName: FqName?,
typeParameterProtos: List<ProtoBuf.TypeParameter>, typeParameterProtos: List<ProtoBuf.TypeParameter>,
@@ -124,6 +131,7 @@ class FirDeserializationContext(
null null
), ),
annotationDeserializer, annotationDeserializer,
constDeserializer,
containerSource, containerSource,
emptyList(), emptyList(),
FirDeserializationComponents() FirDeserializationComponents()
@@ -272,11 +280,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
this.getter = getter this.getter = getter
this.setter = setter this.setter = setter
this.containerSource = c.containerSource this.containerSource = c.containerSource
this.initializer = if (Flags.HAS_CONSTANT.get(flags)) { this.initializer = c.constDeserializer.loadConstant(proto, symbol.callableId, c.nameResolver)
proto.getExtensionOrNull(BuiltInSerializerProtocol.compileTimeValue)?.let {
c.annotationDeserializer.resolveValue(returnTypeRef, it, c.nameResolver)
}
} else null
} }
} }
@@ -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.builder.buildValueParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.deserialization.FirBuiltinAnnotationDeserializer 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.FirDeserializationContext
import org.jetbrains.kotlin.fir.deserialization.deserializeClassToSymbol import org.jetbrains.kotlin.fir.deserialization.deserializeClassToSymbol
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
@@ -78,6 +79,7 @@ class FirBuiltinSymbolProvider(val session: FirSession, val kotlinScopeProvider:
FirDeserializationContext.createForPackage( FirDeserializationContext.createForPackage(
fqName, packageProto.`package`, nameResolver, session, fqName, packageProto.`package`, nameResolver, session,
FirBuiltinAnnotationDeserializer(session), FirBuiltinAnnotationDeserializer(session),
FirConstDeserializer(session),
containerSource = null containerSource = null
).memberDeserializer ).memberDeserializer
} }