[K2] Properly serialize constant values
#KT-56190 Fixed
This commit is contained in:
@@ -14,6 +14,7 @@ dependencies {
|
||||
api(project(":compiler:fir:tree"))
|
||||
api(project(":compiler:fir:providers"))
|
||||
api(project(":compiler:fir:semantics"))
|
||||
api(project(":compiler:fir:resolve"))
|
||||
|
||||
compileOnly(intellijCore())
|
||||
}
|
||||
|
||||
+3
-1
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.fir.extensions.typeAttributeExtensions
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||
import org.jetbrains.kotlin.fir.scopes.*
|
||||
import org.jetbrains.kotlin.fir.serialization.constant.*
|
||||
import org.jetbrains.kotlin.fir.serialization.constant.EnumValue
|
||||
import org.jetbrains.kotlin.fir.serialization.constant.IntValue
|
||||
import org.jetbrains.kotlin.fir.serialization.constant.StringValue
|
||||
@@ -375,12 +376,13 @@ class FirElementSerializer private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
val hasConstant = (!property.isVar && property.initializer.hasConstantValue(session)) || property.isConst
|
||||
val flags = Flags.getPropertyFlags(
|
||||
hasAnnotations,
|
||||
ProtoEnumFlags.visibility(normalizeVisibility(property)),
|
||||
ProtoEnumFlags.modality(modality),
|
||||
ProtoBuf.MemberKind.DECLARATION,
|
||||
property.isVar, hasGetter, hasSetter, property.isConst, property.isConst, property.isLateInit,
|
||||
property.isVar, hasGetter, hasSetter, hasConstant, property.isConst, property.isLateInit,
|
||||
property.isExternal, property.delegateFieldSymbol != null, property.isExpect
|
||||
)
|
||||
if (flags != builder.flags) {
|
||||
|
||||
+2
@@ -9,10 +9,12 @@ 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.serialization.constant.buildValueProtoBufIfPropertyHasConst
|
||||
import org.jetbrains.kotlin.fir.types.ConeErrorType
|
||||
import org.jetbrains.kotlin.fir.types.ConeFlexibleType
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
||||
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
|
||||
+4
-4
@@ -9,10 +9,9 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||
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.serialization.constant.buildValueProtoBufIfPropertyIsConst
|
||||
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
|
||||
import org.jetbrains.kotlin.fir.serialization.constant.buildValueProtoBufIfPropertyHasConst
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
||||
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.protobuf.GeneratedMessageLite
|
||||
@@ -81,7 +80,8 @@ abstract class FirSerializerExtensionBase(
|
||||
property.setter?.serializeAnnotations(proto, protocol.propertySetterAnnotation)
|
||||
property.receiverParameter?.serializeAnnotations(proto, protocol.propertyExtensionReceiverAnnotation, property)
|
||||
|
||||
constValueProvider?.buildValueProtoBufIfPropertyIsConst(property, annotationSerializer)?.let { constProtoBuf ->
|
||||
if (!Flags.HAS_CONSTANT.get(proto.flags)) return
|
||||
constValueProvider?.buildValueProtoBufIfPropertyHasConst(property, annotationSerializer)?.let { constProtoBuf ->
|
||||
proto.setExtension(protocol.compileTimeValue, constProtoBuf)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -12,14 +12,14 @@ import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
|
||||
import org.jetbrains.kotlin.fir.declarations.FirReceiverParameter
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
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<*>?
|
||||
abstract fun getConstantValueForProperty(firProperty: FirProperty): FirExpression?
|
||||
|
||||
abstract fun getNewFirAnnotationWithConstantValues(
|
||||
firAnnotationContainer: FirAnnotationContainer,
|
||||
@@ -44,13 +44,13 @@ abstract class ConstValueProvider {
|
||||
firAnnotation: FirAnnotation,
|
||||
): FirAnnotation
|
||||
|
||||
fun FirConstExpression<*>?.toProtoBuf(annotationSerializer: FirAnnotationSerializer): ProtoBuf.Annotation.Argument.Value? {
|
||||
fun FirExpression?.toProtoBuf(annotationSerializer: FirAnnotationSerializer): ProtoBuf.Annotation.Argument.Value? {
|
||||
val constantValue = this?.toConstantValue(session) ?: return null
|
||||
return annotationSerializer.valueProto(constantValue).build()
|
||||
}
|
||||
}
|
||||
|
||||
fun ConstValueProvider.buildValueProtoBufIfPropertyIsConst(
|
||||
fun ConstValueProvider.buildValueProtoBufIfPropertyHasConst(
|
||||
firProperty: FirProperty, annotationSerializer: FirAnnotationSerializer
|
||||
): ProtoBuf.Annotation.Argument.Value? {
|
||||
return getConstantValueForProperty(firProperty).toProtoBuf(annotationSerializer)
|
||||
|
||||
+82
-4
@@ -6,16 +6,15 @@
|
||||
package org.jetbrains.kotlin.fir.serialization.constant
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.containingClassLookupTag
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.FirEnumEntry
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationArgumentMapping
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildSimpleNamedReference
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirArrayOfCallTransformer
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirArrayOfCallTransformer.Companion.isArrayOfCall
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.classId
|
||||
@@ -28,6 +27,10 @@ internal fun FirExpression.toConstantValue(session: FirSession): ConstantValue<*
|
||||
return accept(FirToConstantValueTransformerUnsafe, session)
|
||||
}
|
||||
|
||||
internal fun FirExpression?.hasConstantValue(session: FirSession): Boolean {
|
||||
return this?.accept(FirToConstantValueChecker, session) == true
|
||||
}
|
||||
|
||||
private object FirToConstantValueTransformerSafe : FirToConstantValueTransformer(failOnNonConst = false)
|
||||
private object FirToConstantValueTransformerUnsafe : FirToConstantValueTransformer(failOnNonConst = true)
|
||||
|
||||
@@ -162,6 +165,9 @@ private abstract class FirToConstantValueTransformer(
|
||||
functionCall: FirFunctionCall,
|
||||
data: FirSession
|
||||
): ConstantValue<*>? {
|
||||
if (functionCall.isArrayOfCall) {
|
||||
return FirArrayOfCallTransformer().transformFunctionCall(functionCall, null).accept(this, data)
|
||||
}
|
||||
return visitQualifiedAccessExpression(functionCall, data)
|
||||
}
|
||||
|
||||
@@ -176,3 +182,75 @@ private abstract class FirToConstantValueTransformer(
|
||||
return namedArgumentExpression.expression.accept(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
internal object FirToConstantValueChecker : FirDefaultVisitor<Boolean, FirSession>() {
|
||||
// `null` value is not treated as a const
|
||||
private val supportedConstKinds = setOf<ConstantValueKind<*>>(
|
||||
ConstantValueKind.Boolean, ConstantValueKind.Char, ConstantValueKind.String, ConstantValueKind.Float, ConstantValueKind.Double,
|
||||
ConstantValueKind.Byte, ConstantValueKind.UnsignedByte, ConstantValueKind.Short, ConstantValueKind.UnsignedShort,
|
||||
ConstantValueKind.Int, ConstantValueKind.UnsignedInt, ConstantValueKind.Long, ConstantValueKind.UnsignedLong,
|
||||
)
|
||||
|
||||
override fun visitElement(element: FirElement, data: FirSession): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun <T> visitConstExpression(
|
||||
constExpression: FirConstExpression<T>,
|
||||
data: FirSession
|
||||
): Boolean {
|
||||
return constExpression.kind in supportedConstKinds
|
||||
}
|
||||
|
||||
override fun visitArrayOfCall(arrayOfCall: FirArrayOfCall, data: FirSession): Boolean {
|
||||
return arrayOfCall.arguments.all { it.accept(this, data) }
|
||||
}
|
||||
|
||||
override fun visitAnnotation(annotation: FirAnnotation, data: FirSession): Boolean = true
|
||||
|
||||
override fun visitAnnotationCall(annotationCall: FirAnnotationCall, data: FirSession): Boolean = true
|
||||
|
||||
override fun visitGetClassCall(getClassCall: FirGetClassCall, data: FirSession): Boolean {
|
||||
return KClassValue.create(getClassCall.argument.typeRef.coneTypeUnsafe()) != null
|
||||
}
|
||||
|
||||
override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: FirSession): Boolean {
|
||||
val symbol = qualifiedAccessExpression.toResolvedCallableSymbol() ?: return false
|
||||
|
||||
return when {
|
||||
symbol.fir is FirEnumEntry -> symbol.fir.returnTypeRef.coneTypeSafe<ConeClassLikeType>()?.classId != null
|
||||
|
||||
symbol is FirConstructorSymbol -> {
|
||||
symbol.containingClassLookupTag()?.toFirRegularClassSymbol(data)?.classKind == ClassKind.ANNOTATION_CLASS
|
||||
}
|
||||
|
||||
symbol.callableId.packageName.asString() == "kotlin" -> {
|
||||
val dispatchReceiver = qualifiedAccessExpression.dispatchReceiver
|
||||
when (symbol.callableId.callableName.asString()) {
|
||||
in setOf("toByte", "toLong", "toShort", "toFloat", "toDouble", "toChar") -> true
|
||||
"unaryMinus" -> dispatchReceiver.accept(this, data)
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression, data: FirSession): Boolean {
|
||||
return visitQualifiedAccessExpression(propertyAccessExpression, data)
|
||||
}
|
||||
|
||||
override fun visitFunctionCall(functionCall: FirFunctionCall, data: FirSession): Boolean {
|
||||
if (functionCall.isArrayOfCall) return functionCall.arguments.all { it.accept(this, data) }
|
||||
return visitQualifiedAccessExpression(functionCall, data)
|
||||
}
|
||||
|
||||
override fun visitVarargArgumentsExpression(varargArgumentsExpression: FirVarargArgumentsExpression, data: FirSession): Boolean {
|
||||
return varargArgumentsExpression.arguments.all { it.accept(this, data) }
|
||||
}
|
||||
|
||||
override fun visitNamedArgumentExpression(namedArgumentExpression: FirNamedArgumentExpression, data: FirSession): Boolean {
|
||||
return namedArgumentExpression.expression.accept(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user