Serialize and deserialize const val's properly for K2 klib

#KT-57312 Fixed
This commit is contained in:
Ivan Kylchik
2023-03-09 14:47:32 +01:00
committed by Space Team
parent 23b23d5a1e
commit 32297c0f21
17 changed files with 176 additions and 55 deletions
@@ -24,9 +24,7 @@ import org.jetbrains.kotlin.diagnostics.impl.PendingDiagnosticsCollectorWithSupp
import org.jetbrains.kotlin.fir.BinaryModuleData
import org.jetbrains.kotlin.fir.DependencyListForCliModule
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.backend.Fir2IrExtensions
import org.jetbrains.kotlin.fir.backend.Fir2IrVisibilityConverter
import org.jetbrains.kotlin.fir.backend.extractFirDeclarations
import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmKotlinMangler
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
@@ -192,7 +190,10 @@ fun serializeFirKlib(
session,
scopeSession,
actualizedExpectDeclarations,
FirKLibSerializerExtension(session, metadataVersion, FirElementAwareSerializableStringTable()),
FirKLibSerializerExtension(
session, metadataVersion, FirElementAwareSerializableStringTable(),
ConstValueProviderImpl(fir2IrActualizedResult.components),
),
moduleStructure.compilerConfiguration.languageVersionSettings,
)
}
@@ -39,7 +39,7 @@ import org.jetbrains.kotlin.fir.pipeline.resolveAndCheckFir
import org.jetbrains.kotlin.fir.serialization.FirElementAwareSerializableStringTable
import org.jetbrains.kotlin.fir.serialization.FirKLibSerializerExtension
import org.jetbrains.kotlin.fir.serialization.serializeSingleFirFile
import org.jetbrains.kotlin.library.*
import org.jetbrains.kotlin.library.SerializedMetadata
import org.jetbrains.kotlin.library.metadata.KlibMetadataHeaderFlags
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
import org.jetbrains.kotlin.modules.TargetId
@@ -167,8 +167,10 @@ internal class FirMetadataSerializer(
session,
scopeSession,
actualizedExpectDeclarations = null,
FirKLibSerializerExtension(session, metadataVersion, FirElementAwareSerializableStringTable()),
languageVersionSettings
FirKLibSerializerExtension(
session, metadataVersion, FirElementAwareSerializableStringTable(), constValueProvider = null
),
languageVersionSettings,
)
fragments.getOrPut(firFile.packageFqName.asString()) { mutableListOf() }.add(packageFragment.toByteArray())
}
@@ -8,8 +8,10 @@ package org.jetbrains.kotlin.fir.serialization
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.serialization.constant.ConstValueProvider
import org.jetbrains.kotlin.fir.types.ConeErrorType
import org.jetbrains.kotlin.fir.types.ConeFlexibleType
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
@@ -24,6 +26,8 @@ abstract class FirSerializerExtension {
val annotationSerializer by lazy { FirAnnotationSerializer(session, stringTable) }
abstract val constValueProvider: ConstValueProvider?
open fun shouldUseTypeTable(): Boolean = false
open fun shouldUseNormalizedVisibility(): Boolean = false
@@ -83,6 +87,11 @@ abstract class FirSerializerExtension {
throw IllegalStateException("Cannot serialize error type: $type")
}
protected fun serializeConstant(property: FirProperty, proto: ProtoBuf.Property.Builder) {
val constProtoBuf = constValueProvider?.buildValueProtoBufIfPropertyIsConst(property, annotationSerializer) ?: return
proto.setExtension(KlibMetadataProtoBuf.compileTimeValue, constProtoBuf)
}
open val customClassMembersProducer: ClassMembersProducer?
get() = null
@@ -0,0 +1,32 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.serialization.constant
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.serialization.FirAnnotationSerializer
import org.jetbrains.kotlin.metadata.ProtoBuf
abstract class ConstValueProvider {
abstract val session: FirSession
abstract fun getConstantValueForProperty(firProperty: FirProperty): FirConstExpression<*>?
fun buildValueProtoBufIfPropertyIsConst(
firProperty: FirProperty, annotationSerializer: FirAnnotationSerializer
): ProtoBuf.Annotation.Argument.Value? {
return getConstantValueForProperty(firProperty).toProtoBuf(annotationSerializer)
}
private fun FirConstExpression<*>?.toProtoBuf(
annotationSerializer: FirAnnotationSerializer
): ProtoBuf.Annotation.Argument.Value? {
val constantValue = this?.toConstantValue(session) ?: return null
return annotationSerializer.valueProto(constantValue).build()
}
}
@@ -49,11 +49,11 @@ internal object FirToConstantValueTransformer : FirDefaultVisitor<ConstantValue<
ConstantValueKind.UnsignedShort -> UShortValue((value as Number).toShort())
ConstantValueKind.Int -> IntValue((value as Number).toInt())
ConstantValueKind.UnsignedInt -> UIntValue((value as Number).toInt())
ConstantValueKind.Long -> LongValue(value as Long)
ConstantValueKind.UnsignedLong -> ULongValue(value as Long)
ConstantValueKind.Long -> LongValue((value as Number).toLong())
ConstantValueKind.UnsignedLong -> ULongValue((value as Number).toLong())
ConstantValueKind.String -> StringValue(value as String)
ConstantValueKind.Float -> FloatValue(value as Float)
ConstantValueKind.Double -> DoubleValue(value as Double)
ConstantValueKind.Float -> FloatValue((value as Number).toFloat())
ConstantValueKind.Double -> DoubleValue((value as Number).toDouble())
ConstantValueKind.Null -> NullValue
else -> null
}
@@ -99,24 +99,22 @@ internal object FirToConstantValueTransformer : FirDefaultVisitor<ConstantValue<
symbol is FirConstructorSymbol -> {
val constructorCall = qualifiedAccessExpression as FirFunctionCall
val constructedClassSymbol = symbol.containingClassLookupTag()?.toFirRegularClassSymbol(data) ?: return null
return if (constructedClassSymbol.classKind == ClassKind.ANNOTATION_CLASS) {
AnnotationValue(
buildAnnotationCall {
argumentMapping = buildAnnotationArgumentMapping {
constructorCall.resolvedArgumentMapping?.forEach { (firExpression, firValueParameter) ->
mapping[firValueParameter.name] = firExpression
}
}
annotationTypeRef = qualifiedAccessExpression.typeRef
calleeReference = buildSimpleNamedReference {
source = qualifiedAccessExpression.source
name = qualifiedAccessExpression.calleeReference.name
if (constructedClassSymbol.classKind != ClassKind.ANNOTATION_CLASS) return null
return AnnotationValue(
buildAnnotationCall {
argumentMapping = buildAnnotationArgumentMapping {
constructorCall.resolvedArgumentMapping?.forEach { (firExpression, firValueParameter) ->
mapping[firValueParameter.name] = firExpression
}
}
)
} else {
null
}
annotationTypeRef = qualifiedAccessExpression.typeRef
calleeReference = buildSimpleNamedReference {
source = qualifiedAccessExpression.source
name = qualifiedAccessExpression.calleeReference.name
}
}
)
}
symbol.callableId.packageName.asString() == "kotlin" -> {
@@ -13,8 +13,10 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.packageFqName
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.serialization.constant.ConstValueProvider
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.SerializableStringTable
@@ -66,8 +68,19 @@ fun serializeSingleFirFile(
open class FirKLibSerializerExtension(
override val session: FirSession,
override val metadataVersion: BinaryVersion,
override val stringTable: FirElementAwareSerializableStringTable
) : FirSerializerExtension()
override val stringTable: FirElementAwareSerializableStringTable,
override val constValueProvider: ConstValueProvider?
) : FirSerializerExtension() {
override fun serializeProperty(
property: FirProperty,
proto: ProtoBuf.Property.Builder,
versionRequirementTable: MutableVersionRequirementTable?,
childSerializer: FirElementSerializer
) {
super.serializeProperty(property, proto, versionRequirementTable, childSerializer)
serializeConstant(property, proto)
}
}
class FirElementAwareSerializableStringTable() : FirElementAwareStringTable, SerializableStringTable() {
override fun getLocalClassIdReplacement(firClass: FirClass): ClassId? = ClassId.topLevel(StandardNames.FqNames.any.toSafe())
+1 -1
View File
@@ -16,6 +16,7 @@ dependencies {
compileOnly(project(":compiler:ir.tree"))
compileOnly(project(":compiler:ir.backend.common"))
compileOnly(project(":compiler:ir.serialization.common"))
compileOnly(project(":compiler:fir:fir-serialization"))
compileOnly(intellijCore())
@@ -26,7 +27,6 @@ dependencies {
testApi(projectTests(":compiler:tests-compiler-utils"))
testApi(projectTests(":compiler:tests-common-new"))
testApi(projectTests(":compiler:fir:analysis-tests"))
testApi(project(":compiler:fir:fir-serialization"))
testApiJUnit5()
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.config.JvmDefaultMode
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.backend.ConstValueProviderImpl
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
import org.jetbrains.kotlin.fir.backend.FirMetadataSource
import org.jetbrains.kotlin.fir.declarations.*
@@ -23,9 +24,8 @@ import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
import org.jetbrains.kotlin.fir.serialization.FirElementAwareStringTable
import org.jetbrains.kotlin.fir.serialization.FirElementSerializer
import org.jetbrains.kotlin.fir.serialization.FirSerializerExtension
import org.jetbrains.kotlin.fir.serialization.*
import org.jetbrains.kotlin.fir.serialization.constant.ConstValueProvider
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.ir.declarations.MetadataSource
import org.jetbrains.kotlin.load.kotlin.NON_EXISTENT_CLASS_NAME
@@ -59,7 +59,8 @@ class FirJvmSerializerExtension(
private val unifiedNullChecks: Boolean,
override val metadataVersion: BinaryVersion,
private val jvmDefaultMode: JvmDefaultMode,
override val stringTable: FirElementAwareStringTable
override val stringTable: FirElementAwareStringTable,
override val constValueProvider: ConstValueProvider?
) : FirSerializerExtension() {
constructor(
@@ -75,7 +76,7 @@ class FirJvmSerializerExtension(
session, bindings, metadata, localDelegatedProperties, approximator, components.scopeSession,
state.globalSerializationBindings, state.useTypeTableInSerializer, state.moduleName, state.classBuilderMode,
state.isParamAssertionsDisabled, state.unifiedNullChecks, state.metadataVersion, state.jvmDefaultMode,
FirJvmElementAwareStringTable(typeMapper, components)
FirJvmElementAwareStringTable(typeMapper, components), ConstValueProviderImpl(components),
)
override fun shouldUseTypeTable(): Boolean = useTypeTable
@@ -26,11 +26,13 @@ import org.jetbrains.kotlin.fir.resolve.toFirRegularClass
import org.jetbrains.kotlin.fir.serialization.FirElementAwareStringTable
import org.jetbrains.kotlin.fir.serialization.FirElementSerializer
import org.jetbrains.kotlin.fir.serialization.TypeApproximatorForMetadataSerializer
import org.jetbrains.kotlin.fir.serialization.constant.*
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.MetadataSource
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.metadata.jvm.serialization.JvmStringTable
import org.jetbrains.kotlin.modules.TargetId
import org.jetbrains.kotlin.name.ClassId
@@ -65,7 +67,7 @@ fun makeFirMetadataSerializerForIrClass(
approximator,
makeElementSerializer(
irClass.metadata, components.session, components.scopeSession, firSerializerExtension, approximator, parent,
context.state.configuration.languageVersionSettings
context.state.configuration.languageVersionSettings,
),
irActualizationResult
)
@@ -102,7 +104,8 @@ fun makeLocalFirMetadataSerializerForMetadataSource(
!configuration.getBoolean(JVMConfigurationKeys.NO_UNIFIED_NULL_CHECKS),
configuration.metadataVersion(session.languageVersionSettings.languageVersion),
session.languageVersionSettings.getFlag(JvmAnalysisFlags.jvmDefaultMode),
stringTable
stringTable,
constValueProvider = null,
)
return FirMetadataSerializer(
globalSerializationBindings,
@@ -0,0 +1,64 @@
/*
* Copyright 2010-2023 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.backend
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression
import org.jetbrains.kotlin.fir.serialization.constant.ConstValueProvider
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.types.ConstantValueKind
class ConstValueProviderImpl(
private val components: Fir2IrComponents,
) : ConstValueProvider() {
override val session: FirSession = components.session
override fun getConstantValueForProperty(firProperty: FirProperty): FirConstExpression<*>? {
val irProperty: IrProperty = components.declarationStorage.getCachedIrProperty(firProperty) ?: return null
if (!irProperty.isConst) return null
val irConst = irProperty.backingField?.initializer?.expression as? IrConst<*> ?: return null
return irConst.toFirConst()
}
private fun IrConst<*>.getConstantKind(): ConstantValueKind<*>? {
if (this.kind == IrConstKind.Null) return ConstantValueKind.Null
val constType = this.type.makeNotNull().removeAnnotations()
return when (this.type.getPrimitiveType()) {
PrimitiveType.BOOLEAN -> ConstantValueKind.Boolean
PrimitiveType.CHAR -> ConstantValueKind.Char
PrimitiveType.BYTE -> ConstantValueKind.Byte
PrimitiveType.SHORT -> ConstantValueKind.Short
PrimitiveType.INT -> ConstantValueKind.Int
PrimitiveType.LONG -> ConstantValueKind.Long
PrimitiveType.FLOAT -> ConstantValueKind.Float
PrimitiveType.DOUBLE -> ConstantValueKind.Double
null -> when (constType.getUnsignedType()) {
UnsignedType.UBYTE -> ConstantValueKind.UnsignedByte
UnsignedType.USHORT -> ConstantValueKind.UnsignedShort
UnsignedType.UINT -> ConstantValueKind.UnsignedInt
UnsignedType.ULONG -> ConstantValueKind.UnsignedLong
null -> when {
constType.isString() -> ConstantValueKind.String
else -> null
}
}
}
}
private fun <T> IrConst<T>.toFirConst(): FirConstExpression<T>? {
@Suppress("UNCHECKED_CAST")
val kind = getConstantKind() as? ConstantValueKind<T> ?: return null
return buildConstExpression(null, kind, this.value)
}
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_K2: JS_IR, NATIVE
// MODULE: lib
// FILE: Typography.kt
object Typography {
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_K2: JS_IR, NATIVE
// ISSUE: KT-52057
// IGNORE_BACKEND_K2: NATIVE
// MODULE: lib
// FILE: Class.kt
@@ -1,5 +1,3 @@
// IGNORE_BACKEND_K2: JS_IR, NATIVE
// MODULE: lib1
// FILE: lib1.kt
object L1 {
@@ -1,5 +1,3 @@
// IGNORE_BACKEND_K2: NATIVE, JS_IR
// MODULE: lib
// FILE: lib.kt
const val four = 4
@@ -1,5 +1,3 @@
// IGNORE_BACKEND_K2: NATIVE, JS_IR
// MODULE: lib
// FILE: lib.kt
const val four = 2 + 2
@@ -123,7 +123,9 @@ class Fir2IrJsResultsConverter(
components.session,
components.scopeSession,
actualizedExpectDeclarations,
FirKLibSerializerExtension(components.session, metadataVersion, FirElementAwareSerializableStringTable()),
FirKLibSerializerExtension(
components.session, metadataVersion, FirElementAwareSerializableStringTable(), ConstValueProviderImpl(components),
),
configuration.languageVersionSettings,
)
}
@@ -14,14 +14,13 @@ import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.backend.ConstValueProviderImpl
import org.jetbrains.kotlin.fir.backend.extractFirDeclarations
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.serialization.FirElementAwareSerializableStringTable
import org.jetbrains.kotlin.fir.serialization.FirElementSerializer
import org.jetbrains.kotlin.fir.serialization.FirKLibSerializerExtension
import org.jetbrains.kotlin.fir.serialization.serializeSingleFirFile
import org.jetbrains.kotlin.fir.serialization.*
import org.jetbrains.kotlin.fir.serialization.constant.ConstValueProvider
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.IrMessageLogger
@@ -70,7 +69,9 @@ internal fun PhaseContext.firSerializer(
session,
scopeSession,
actualizedFirDeclarations,
FirNativeKLibSerializerExtension(session, metadataVersion, FirElementAwareSerializableStringTable()),
FirNativeKLibSerializerExtension(
session, metadataVersion, FirElementAwareSerializableStringTable(), ConstValueProviderImpl(input.components),
),
configuration.languageVersionSettings,
)
}
@@ -137,8 +138,9 @@ internal fun PhaseContext.serializeNativeModule(
class FirNativeKLibSerializerExtension(
override val session: FirSession,
override val metadataVersion: BinaryVersion,
override val stringTable: FirElementAwareSerializableStringTable
) : FirKLibSerializerExtension(session, metadataVersion, stringTable) {
override val stringTable: FirElementAwareSerializableStringTable,
override val constValueProvider: ConstValueProvider?
) : FirKLibSerializerExtension(session, metadataVersion, stringTable, constValueProvider) {
private fun declarationFileId(declaration: FirMemberDeclaration): Int? {
val fileName = declaration.source.psi?.containingFile?.name ?: return null
return stringTable.getStringIndex(fileName)
@@ -194,6 +196,9 @@ class FirNativeKLibSerializerExtension(
property.setter?.nonSourceAnnotations(session)?.forEach {
proto.addExtension(KlibMetadataProtoBuf.propertySetterAnnotation, annotationSerializer.serializeAnnotation(it))
}
serializeConstant(property, proto)
// TODO KT-56090 Serialize KDocString
super.serializeProperty(property, proto, versionRequirementTable, childSerializer)
}
@@ -242,5 +247,4 @@ class FirNativeKLibSerializerExtension(
}
super.serializeTypeParameter(typeParameter, proto)
}
}