[K2] Return from toConstantValue only if expected type match

There was a bug with early return from `toConstantValue`
method when we found any const value in `ConstValueProvider`.
Actually we should return only if expected type match. This error can
occur if annotation and constant inside it are fakes and
have the same offset.

#KT-57812
This commit is contained in:
Ivan Kylchik
2023-04-21 16:53:21 +02:00
committed by Space Team
parent 01749a910b
commit 846ad95c9e
5 changed files with 20 additions and 16 deletions
@@ -25,7 +25,7 @@ class FirAnnotationSerializer(
) {
fun serializeAnnotation(annotation: FirAnnotation): ProtoBuf.Annotation {
// TODO this logic can be significantly simplified if we will find the way to convert `IrAnnotation` to `AnnotationValue`
val annotationValue = annotation.toConstantValue(session, constValueProvider) as? AnnotationValue
val annotationValue = annotation.toConstantValue<AnnotationValue>(session, constValueProvider)
?: error("Cannot serialize annotation ${annotation.render()}")
return serializeAnnotation(annotationValue)
}
@@ -1091,8 +1091,7 @@ class FirElementSerializer private constructor(
private fun serializeVersionRequirementFromRequireKotlin(annotation: FirAnnotation): ProtoBuf.VersionRequirement.Builder? {
val argumentMapping = annotation.argumentMapping.mapping
val versionString =
(argumentMapping[RequireKotlinConstants.VERSION]?.toConstantValue(session) as? StringValue)?.value ?: return null
val versionString = argumentMapping[RequireKotlinConstants.VERSION]?.toConstantValue<StringValue>(session)?.value ?: return null
val matchResult = RequireKotlinConstants.VERSION_REGEX.matchEntire(versionString) ?: return null
val major = matchResult.groupValues.getOrNull(1)?.toIntOrNull() ?: return null
@@ -1105,12 +1104,12 @@ class FirElementSerializer private constructor(
writeVersionFull = { proto.versionFull = it }
)
val message = (argumentMapping[RequireKotlinConstants.MESSAGE]?.toConstantValue(session) as? StringValue)?.value
val message = argumentMapping[RequireKotlinConstants.MESSAGE]?.toConstantValue<StringValue>(session)?.value
if (message != null) {
proto.message = stringTable.getStringIndex(message)
}
when ((argumentMapping[RequireKotlinConstants.LEVEL]?.toConstantValue(session) as? EnumValue)?.enumEntryName?.asString()) {
when (argumentMapping[RequireKotlinConstants.LEVEL]?.toConstantValue<EnumValue>(session)?.enumEntryName?.asString()) {
DeprecationLevel.ERROR.name -> {
// ERROR is the default level
}
@@ -1118,7 +1117,7 @@ class FirElementSerializer private constructor(
DeprecationLevel.HIDDEN.name -> proto.level = ProtoBuf.VersionRequirement.Level.HIDDEN
}
when ((argumentMapping[RequireKotlinConstants.VERSION_KIND]?.toConstantValue(session) as? EnumValue)?.enumEntryName?.asString()) {
when (argumentMapping[RequireKotlinConstants.VERSION_KIND]?.toConstantValue<EnumValue>(session)?.enumEntryName?.asString()) {
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION.name -> {
// LANGUAGE_VERSION is the default kind
}
@@ -1128,7 +1127,7 @@ class FirElementSerializer private constructor(
proto.versionKind = ProtoBuf.VersionRequirement.VersionKind.API_VERSION
}
val errorCode = (argumentMapping[RequireKotlinConstants.ERROR_CODE]?.toConstantValue(session) as? IntValue)?.value
val errorCode = argumentMapping[RequireKotlinConstants.ERROR_CODE]?.toConstantValue<IntValue>(session)?.value
if (errorCode != null && errorCode != -1) {
proto.errorCode = errorCode
}
@@ -30,11 +30,12 @@ abstract class FirSerializerExtension {
@OptIn(ConstValueProviderInternals::class)
internal inline fun <T> processFile(firFile: FirFile, action: () -> T): T {
val previousFile = constValueProvider?.processingFirFile
constValueProvider?.processingFirFile = firFile
return try {
action()
} finally {
constValueProvider?.processingFirFile = null
constValueProvider?.processingFirFile = previousFile
}
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.serialization
import org.jetbrains.kotlin.constant.ConstantValue
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.declarations.*
@@ -79,7 +80,7 @@ abstract class FirSerializerExtensionBase(
property.receiverParameter?.serializeAnnotations(proto, protocol.propertyExtensionReceiverAnnotation)
if (!Flags.HAS_CONSTANT.get(proto.flags)) return
property.initializer?.toConstantValue(session, constValueProvider)?.let {
property.initializer?.toConstantValue<ConstantValue<*>>(session, constValueProvider)?.let {
proto.setExtension(protocol.compileTimeValue, annotationSerializer.valueProto(it).build())
}
}
@@ -25,25 +25,28 @@ import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
import org.jetbrains.kotlin.types.ConstantValueKind
internal fun FirExpression.toConstantValue(session: FirSession, constValueProvider: ConstValueProvider? = null): ConstantValue<*>? {
constValueProvider?.findConstantValueFor(this)?.let { return it }
return accept(FirToConstantValueTransformerUnsafe(), FirToConstantValueTransformerData(session, constValueProvider))
internal inline fun <reified T : ConstantValue<*>> FirExpression.toConstantValue(
session: FirSession,
constValueProvider: ConstValueProvider? = null
): T? {
return constValueProvider?.findConstantValueFor(this) as? T
?: accept(FirToConstantValueTransformerUnsafe(), FirToConstantValueTransformerData(session, constValueProvider)) as? T
}
internal fun FirExpression?.hasConstantValue(session: FirSession): Boolean {
return this?.accept(FirToConstantValueChecker, session) == true
}
private class FirToConstantValueTransformerSafe : FirToConstantValueTransformer(failOnNonConst = false)
internal class FirToConstantValueTransformerSafe : FirToConstantValueTransformer(failOnNonConst = false)
private class FirToConstantValueTransformerUnsafe : FirToConstantValueTransformer(failOnNonConst = true)
internal class FirToConstantValueTransformerUnsafe : FirToConstantValueTransformer(failOnNonConst = true)
private data class FirToConstantValueTransformerData(
internal data class FirToConstantValueTransformerData(
val session: FirSession,
val constValueProvider: ConstValueProvider?,
)
private abstract class FirToConstantValueTransformer(
internal abstract class FirToConstantValueTransformer(
private val failOnNonConst: Boolean,
) : FirDefaultVisitor<ConstantValue<*>?, FirToConstantValueTransformerData>() {
override fun visitElement(