From 45aacae94547512a491fe572f37198af3424083a Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Sat, 8 Apr 2023 14:55:56 +0200 Subject: [PATCH] [K2] Rewrite the way of extraction const values from IR for FIR Right now it is much easier to extract constant values from `EvaluatedConstTracker` #KT-57928 #KT-57929 --- .../serialization/FirAnnotationSerializer.kt | 26 +- .../serialization/FirSerializerExtension.kt | 7 +- .../FirSerializerExtensionBase.kt | 40 +--- .../constant/ConstValueProvider.kt | 34 +-- .../constant/ConstantValueUtils.kt | 18 +- .../constant/FirToConstantValueTransformer.kt | 21 +- .../backend/jvm/FirJvmSerializerExtension.kt | 3 +- .../fir/backend/ConstValueProviderImpl.kt | 226 ++---------------- .../kotlin/fir/backend/ConversionUtils.kt | 2 +- .../kotlin/constant/ConstantValue.kt | 4 +- 10 files changed, 82 insertions(+), 299 deletions(-) diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirAnnotationSerializer.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirAnnotationSerializer.kt index b8a72224e0b..1a9c3a71af9 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirAnnotationSerializer.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirAnnotationSerializer.kt @@ -9,27 +9,32 @@ import org.jetbrains.kotlin.constant.AnnotationValue import org.jetbrains.kotlin.constant.ConstantValue import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.expressions.FirAnnotation +import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.toSymbol +import org.jetbrains.kotlin.fir.serialization.constant.ConstValueProvider import org.jetbrains.kotlin.fir.serialization.constant.coneTypeSafe -import org.jetbrains.kotlin.fir.serialization.constant.convertToConstantValues +import org.jetbrains.kotlin.fir.serialization.constant.toConstantValue import org.jetbrains.kotlin.fir.types.ConeClassLikeType -import org.jetbrains.kotlin.fir.types.coneTypeSafe import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.name.Name -class FirAnnotationSerializer(private val session: FirSession, internal val stringTable: FirElementAwareStringTable) { +class FirAnnotationSerializer( + private val session: FirSession, + internal val stringTable: FirElementAwareStringTable, + private val constValueProvider: ConstValueProvider? +) { fun serializeAnnotation(annotation: FirAnnotation): ProtoBuf.Annotation { - return serializeAnnotation( - annotation.typeRef.coneTypeSafe(), - annotation.argumentMapping.mapping.convertToConstantValues(session) - ) + // 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 + ?: error("Cannot serialize annotation ${annotation.render()}") + return serializeAnnotation(annotationValue) } fun serializeAnnotation(annotation: AnnotationValue): ProtoBuf.Annotation { return serializeAnnotation(annotation.coneTypeSafe(), annotation.value.argumentsMapping) } - private fun serializeAnnotation(coneType: ConeClassLikeType?, argumentsMapping: Map?>): ProtoBuf.Annotation { + private fun serializeAnnotation(coneType: ConeClassLikeType?, argumentsMapping: Map>): ProtoBuf.Annotation { return ProtoBuf.Annotation.newBuilder().apply { val lookupTag = coneType?.lookupTag ?: error { "Annotation without proper lookup tag: $coneType" } @@ -37,10 +42,7 @@ class FirAnnotationSerializer(private val session: FirSession, internal val stri id = lookupTag.toSymbol(session)?.let { stringTable.getFqNameIndex(it.fir) } ?: stringTable.getQualifiedClassNameIndex(lookupTag.classId) - fun addArgument(argumentExpression: ConstantValue<*>?, parameterName: Name) { - if (argumentExpression == null) { - error("Cannot use null argument expression for parameter $parameterName") - } + fun addArgument(argumentExpression: ConstantValue<*>, parameterName: Name) { val argument = ProtoBuf.Annotation.Argument.newBuilder() argument.nameId = stringTable.getStringIndex(parameterName.asString()) argument.setValue(valueProto(argumentExpression)) diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtension.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtension.kt index e1eec4479bd..29e2b4fa61b 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtension.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtension.kt @@ -9,12 +9,10 @@ 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 @@ -25,7 +23,7 @@ abstract class FirSerializerExtension { abstract val metadataVersion: BinaryVersion - val annotationSerializer by lazy { FirAnnotationSerializer(session, stringTable) } + val annotationSerializer by lazy { FirAnnotationSerializer(session, stringTable, constValueProvider) } protected abstract val constValueProvider: ConstValueProvider? @@ -83,8 +81,7 @@ abstract class FirSerializerExtension { open fun serializeTypeAlias(typeAlias: FirTypeAlias, proto: ProtoBuf.TypeAlias.Builder) { for (annotation in typeAlias.nonSourceAnnotations(session)) { - val annotationWithConstants = constValueProvider?.getNewFirAnnotationWithConstantValues(typeAlias, annotation) ?: annotation - proto.addAnnotation(annotationSerializer.serializeAnnotation(annotationWithConstants)) + proto.addAnnotation(annotationSerializer.serializeAnnotation(annotation)) } } diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtensionBase.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtensionBase.kt index bf5fb3c561c..ab743039ce6 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtensionBase.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtensionBase.kt @@ -9,7 +9,7 @@ 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.buildValueProtoBufIfPropertyHasConst +import org.jetbrains.kotlin.fir.serialization.constant.toConstantValue import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.Flags import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable @@ -50,7 +50,7 @@ abstract class FirSerializerExtensionBase( childSerializer: FirElementSerializer ) { function.serializeAnnotations(proto, protocol.functionAnnotation) - function.receiverParameter?.serializeAnnotations(proto, protocol.functionExtensionReceiverAnnotation, function) + function.receiverParameter?.serializeAnnotations(proto, protocol.functionExtensionReceiverAnnotation) } override fun serializeProperty( @@ -72,17 +72,17 @@ abstract class FirSerializerExtensionBase( destination += annotation } - regularPropertyAnnotations.serializeAnnotations(proto, protocol.propertyAnnotation, property) - fieldPropertyAnnotations.serializeAnnotations(proto, protocol.propertyBackingFieldAnnotation, property) - delegatePropertyAnnotations.serializeAnnotations(proto, protocol.propertyDelegatedFieldAnnotation, property) + regularPropertyAnnotations.serializeAnnotations(proto, protocol.propertyAnnotation) + fieldPropertyAnnotations.serializeAnnotations(proto, protocol.propertyBackingFieldAnnotation) + delegatePropertyAnnotations.serializeAnnotations(proto, protocol.propertyDelegatedFieldAnnotation) property.getter?.serializeAnnotations(proto, protocol.propertyGetterAnnotation) property.setter?.serializeAnnotations(proto, protocol.propertySetterAnnotation) - property.receiverParameter?.serializeAnnotations(proto, protocol.propertyExtensionReceiverAnnotation, property) + property.receiverParameter?.serializeAnnotations(proto, protocol.propertyExtensionReceiverAnnotation) if (!Flags.HAS_CONSTANT.get(proto.flags)) return - constValueProvider?.buildValueProtoBufIfPropertyHasConst(property, annotationSerializer)?.let { constProtoBuf -> - proto.setExtension(protocol.compileTimeValue, constProtoBuf) + property.initializer?.toConstantValue(session, constValueProvider)?.let { + proto.setExtension(protocol.compileTimeValue, annotationSerializer.valueProto(it).build()) } } @@ -96,7 +96,7 @@ abstract class FirSerializerExtensionBase( override fun serializeTypeAnnotations(annotations: List, proto: ProtoBuf.Type.Builder) { // TODO support const extraction for type annotations - annotations.serializeAnnotations(proto, protocol.typeAnnotation, container = null) + annotations.serializeAnnotations(proto, protocol.typeAnnotation) } override fun serializeTypeParameter(typeParameter: FirTypeParameter, proto: ProtoBuf.TypeParameter.Builder) { @@ -112,11 +112,10 @@ abstract class FirSerializerExtensionBase( BuilderType : GeneratedMessageLite.ExtendableBuilder, > FirAnnotationContainer.serializeAnnotations( proto: GeneratedMessageLite.ExtendableBuilder, - extension: GeneratedMessageLite.GeneratedExtension>?, - container: FirAnnotationContainer? = this + extension: GeneratedMessageLite.GeneratedExtension>? ) { if (extension == null) return - this.nonSourceAnnotations(session).serializeAnnotations(proto, extension, container) + this.nonSourceAnnotations(session).serializeAnnotations(proto, extension) } @Suppress("Reformat") @@ -126,25 +125,10 @@ abstract class FirSerializerExtensionBase( > List.serializeAnnotations( proto: GeneratedMessageLite.ExtendableBuilder, extension: GeneratedMessageLite.GeneratedExtension>?, - container: FirAnnotationContainer?, ) { if (extension == null) return for (annotation in this) { - val annotationWithConstants = when { - container == null -> null - extension == protocol.propertyExtensionReceiverAnnotation || extension == protocol.functionExtensionReceiverAnnotation -> - constValueProvider?.getNewFirAnnotationWithConstantValues( - container, - annotation, - (container as FirCallableDeclaration).receiverParameter!!, - ) - else -> - constValueProvider?.getNewFirAnnotationWithConstantValues( - container, - annotation, - ) - } ?: annotation - proto.addExtensionOrNull(extension, annotationSerializer.serializeAnnotation(annotationWithConstants)) + proto.addExtensionOrNull(extension, annotationSerializer.serializeAnnotation(annotation)) } } diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/ConstValueProvider.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/ConstValueProvider.kt index 0e672695501..75104dd0bfa 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/ConstValueProvider.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/ConstValueProvider.kt @@ -5,40 +5,14 @@ package org.jetbrains.kotlin.fir.serialization.constant -import org.jetbrains.kotlin.fir.FirAnnotationContainer +import org.jetbrains.kotlin.constant.ConstantValue +import org.jetbrains.kotlin.constant.EvaluatedConstTracker import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.declarations.FirProperty -import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor -import org.jetbrains.kotlin.fir.declarations.FirReceiverParameter -import org.jetbrains.kotlin.fir.expressions.FirAnnotation 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 val evaluatedConstTracker: EvaluatedConstTracker - abstract fun getConstantValueForProperty(firProperty: FirProperty): FirExpression? - - abstract fun getNewFirAnnotationWithConstantValues( - firAnnotationContainer: FirAnnotationContainer, - firAnnotation: FirAnnotation, - ): FirAnnotation - - abstract fun getNewFirAnnotationWithConstantValues( - firExtensionReceiverContainer: FirAnnotationContainer, - firAnnotation: FirAnnotation, - receiverParameter: FirReceiverParameter, - ): FirAnnotation - - fun FirExpression?.toProtoBuf(annotationSerializer: FirAnnotationSerializer): ProtoBuf.Annotation.Argument.Value? { - val constantValue = this?.toConstantValue(session) ?: return null - return annotationSerializer.valueProto(constantValue).build() - } -} - -fun ConstValueProvider.buildValueProtoBufIfPropertyHasConst( - firProperty: FirProperty, annotationSerializer: FirAnnotationSerializer -): ProtoBuf.Annotation.Argument.Value? { - return getConstantValueForProperty(firProperty).toProtoBuf(annotationSerializer) + abstract fun findConstantValueFor(firExpression: FirExpression?): ConstantValue<*>? } diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/ConstantValueUtils.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/ConstantValueUtils.kt index 04b9fd53b0a..a70826b3d38 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/ConstantValueUtils.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/ConstantValueUtils.kt @@ -12,20 +12,30 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirValueParameter import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.defaultType import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.name.Name -internal fun Map.convertToConstantValues(session: FirSession): Map?> { +internal fun Map.convertToConstantValues( + session: FirSession, + constValueProvider: ConstValueProvider? +): Map> { return this.map { (name, firExpression) -> - name to firExpression.toConstantValue(session) + val constantValue = constValueProvider?.findConstantValueFor(firExpression) + ?: firExpression.toConstantValue(session, constValueProvider) + ?: error("Cannot convert expression ${firExpression.render()} to constant") + name to constantValue }.toMap() } -internal fun LinkedHashMap.convertToConstantValues(session: FirSession): Map?> { +internal fun LinkedHashMap.convertToConstantValues( + session: FirSession, + constValueProvider: ConstValueProvider?, +): Map> { return this.map { (firExpression, firValueParameter) -> firValueParameter.name to firExpression } - .toMap().convertToConstantValues(session) + .toMap().convertToConstantValues(session, constValueProvider) } inline fun AnnotationValue.coneTypeSafe(): T? { diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/FirToConstantValueTransformer.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/FirToConstantValueTransformer.kt index 22958a43c28..6210cc3476d 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/FirToConstantValueTransformer.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/FirToConstantValueTransformer.kt @@ -25,19 +25,26 @@ 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): ConstantValue<*>? { - return accept(FirToConstantValueTransformerUnsafe, session) +internal fun FirExpression.toConstantValue(session: FirSession, constValueProvider: ConstValueProvider? = null): ConstantValue<*>? { + constValueProvider?.findConstantValueFor(this)?.let { return it } + return accept(FirToConstantValueTransformerUnsafe(constValueProvider), 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) +private class FirToConstantValueTransformerSafe( + constValueProvider: ConstValueProvider? +) : FirToConstantValueTransformer(failOnNonConst = false, constValueProvider) + +private class FirToConstantValueTransformerUnsafe( + constValueProvider: ConstValueProvider? +) : FirToConstantValueTransformer(failOnNonConst = true, constValueProvider) private abstract class FirToConstantValueTransformer( - private val failOnNonConst: Boolean + private val failOnNonConst: Boolean, + private val constValueProvider: ConstValueProvider? ) : FirDefaultVisitor?, FirSession>() { override fun visitElement( element: FirElement, @@ -90,7 +97,7 @@ private abstract class FirToConstantValueTransformer( annotation: FirAnnotation, data: FirSession ): ConstantValue<*> { - val mapping = annotation.argumentMapping.mapping.convertToConstantValues(data) + val mapping = annotation.argumentMapping.mapping.convertToConstantValues(data, constValueProvider) return AnnotationValue.create(annotation.annotationTypeRef.coneType, mapping) } @@ -135,7 +142,7 @@ private abstract class FirToConstantValueTransformer( val constructedClassSymbol = symbol.containingClassLookupTag()?.toFirRegularClassSymbol(data) ?: return null if (constructedClassSymbol.classKind != ClassKind.ANNOTATION_CLASS) return null - val mapping = constructorCall.resolvedArgumentMapping?.convertToConstantValues(data) ?: return null + val mapping = constructorCall.resolvedArgumentMapping?.convertToConstantValues(data, constValueProvider) ?: return null return AnnotationValue.create(qualifiedAccessExpression.typeRef.coneType, mapping) } diff --git a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmSerializerExtension.kt b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmSerializerExtension.kt index c4c98f811df..71be020a427 100644 --- a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmSerializerExtension.kt +++ b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmSerializerExtension.kt @@ -176,8 +176,7 @@ class FirJvmSerializerExtension( override fun serializeTypeParameter(typeParameter: FirTypeParameter, proto: ProtoBuf.TypeParameter.Builder) { for (annotation in typeParameter.nonSourceAnnotations(session)) { - val annotationWithConstants = constValueProvider?.getNewFirAnnotationWithConstantValues(typeParameter, annotation) ?: annotation - proto.addExtension(JvmProtoBuf.typeParameterAnnotation, annotationSerializer.serializeAnnotation(annotationWithConstants)) + proto.addExtension(JvmProtoBuf.typeParameterAnnotation, annotationSerializer.serializeAnnotation(annotation)) } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConstValueProviderImpl.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConstValueProviderImpl.kt index 80152765bf3..8fb5aa14c0c 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConstValueProviderImpl.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConstValueProviderImpl.kt @@ -5,222 +5,32 @@ package org.jetbrains.kotlin.fir.backend -import org.jetbrains.kotlin.builtins.PrimitiveType -import org.jetbrains.kotlin.builtins.StandardNames -import org.jetbrains.kotlin.builtins.UnsignedType -import org.jetbrains.kotlin.descriptors.ClassKind -import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget -import org.jetbrains.kotlin.fir.FirAnnotationContainer +import org.jetbrains.kotlin.constant.ConstantValue +import org.jetbrains.kotlin.constant.EvaluatedConstTracker import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.expressions.* -import org.jetbrains.kotlin.fir.expressions.builder.* -import org.jetbrains.kotlin.fir.render +import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.serialization.constant.ConstValueProvider -import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase -import org.jetbrains.kotlin.ir.declarations.IrProperty -import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.types.* -import org.jetbrains.kotlin.ir.util.getArgumentsWithIr -import org.jetbrains.kotlin.ir.util.hasAnnotation -import org.jetbrains.kotlin.ir.util.parentAsClass -import org.jetbrains.kotlin.ir.util.parentClassOrNull -import org.jetbrains.kotlin.types.ConstantValueKind class ConstValueProviderImpl( - private val components: Fir2IrComponents, + components: Fir2IrComponents, ) : ConstValueProvider() { override val session: FirSession = components.session + override val evaluatedConstTracker: EvaluatedConstTracker = components.configuration.evaluatedConstTracker - override fun getConstantValueForProperty(firProperty: FirProperty): FirExpression? { - val firInitializer = firProperty.initializer - val irProperty: IrProperty = components.declarationStorage.getCachedIrProperty(firProperty) ?: return firInitializer - val irConst = irProperty.backingField?.initializer?.expression as? IrConst<*> ?: return firInitializer - return irConst.toFirConst() ?: firInitializer - } + override fun findConstantValueFor(firExpression: FirExpression?): ConstantValue<*>? { + if (firExpression == null) return null - override fun getNewFirAnnotationWithConstantValues( - firAnnotationContainer: FirAnnotationContainer, - firAnnotation: FirAnnotation, - ): FirAnnotation { - if (firAnnotation is FirErrorAnnotationCall || firAnnotation.source == null) return firAnnotation - - val irDeclaration = when (firAnnotationContainer) { - is FirClass -> components.classifierStorage.getCachedIrClass(firAnnotationContainer) - is FirEnumEntry -> components.classifierStorage.getCachedIrEnumEntry(firAnnotationContainer) - is FirTypeAlias -> components.classifierStorage.getCachedTypeAlias(firAnnotationContainer) - is FirTypeParameter -> components.classifierStorage.getCachedIrTypeParameter(firAnnotationContainer) - - is FirScript -> components.declarationStorage.getCachedIrScript(firAnnotationContainer) - is FirConstructor -> components.declarationStorage.getCachedIrConstructor(firAnnotationContainer) - is FirPropertyAccessor -> components.declarationStorage.getCachedIrProperty(firAnnotationContainer.propertySymbol.fir) - ?.let { if (firAnnotationContainer.isGetter) it.getter else it.setter } - is FirFunction -> components.declarationStorage.getCachedIrFunction(firAnnotationContainer) - is FirProperty -> components.declarationStorage.getCachedIrProperty(firAnnotationContainer) - is FirValueParameter -> components.declarationStorage.getCachedIrFunction(firAnnotationContainer.containingFunctionSymbol.fir) - ?.valueParameters?.single { it.name == firAnnotationContainer.name } - else -> error("Cannot extract IR declaration for ${firAnnotationContainer.render()}") - } ?: return firAnnotation - - val correctFirContainer = when (firAnnotation.useSiteTarget) { - AnnotationUseSiteTarget.FIELD, AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD -> { - (firAnnotationContainer as? FirProperty)?.backingField ?: return firAnnotation - } - else -> firAnnotationContainer + return if (firExpression is FirQualifiedAccessExpression) { + // TODO check that this behavior is expected in ConversionUtils and if not fix it + val calleeReference = firExpression.calleeReference + val start = calleeReference.source?.startOffsetSkippingComments() ?: calleeReference.source?.startOffset ?: return null + val end = firExpression.source?.endOffset ?: return null + evaluatedConstTracker.load(start, end) + } else { + val start = firExpression.source?.startOffset ?: return null + val end = firExpression.source?.endOffset ?: return null + evaluatedConstTracker.load(start, end) } - - val correctIrDeclaration = when (firAnnotation.useSiteTarget) { - AnnotationUseSiteTarget.FIELD, AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD -> { - (irDeclaration as? IrProperty)?.backingField ?: return firAnnotation - } - else -> irDeclaration - } - - return buildNewFirAnnotationByCorrespondingIrAnnotation(correctIrDeclaration, correctFirContainer, firAnnotation) - } - - override fun getNewFirAnnotationWithConstantValues( - firExtensionReceiverContainer: FirAnnotationContainer, - firAnnotation: FirAnnotation, - receiverParameter: FirReceiverParameter - ): FirAnnotation { - if (firAnnotation is FirErrorAnnotationCall || firAnnotation.source == null) return firAnnotation - - val extensionReceiver = when (firExtensionReceiverContainer) { - is FirFunction -> components.declarationStorage.getCachedIrFunction(firExtensionReceiverContainer)?.extensionReceiverParameter - is FirProperty -> components.declarationStorage.getCachedIrProperty(firExtensionReceiverContainer)?.getter?.extensionReceiverParameter - else -> error("Cannot extract IR extension receiver for ${firExtensionReceiverContainer::class}") - } ?: return firAnnotation - - return buildNewFirAnnotationByCorrespondingIrAnnotation(extensionReceiver, receiverParameter, firAnnotation) - } - - private fun buildNewFirAnnotationByCorrespondingIrAnnotation( - irDeclaration: IrDeclarationBase, - firAnnotationContainer: FirAnnotationContainer, - firAnnotation: FirAnnotation - ): FirAnnotation { - val unwrappedIrAnnotations = irDeclaration.annotations.flatMap { - val containerClass = it.symbol.owner.parentAsClass - val realAnnotation = containerClass.parentClassOrNull ?: return@flatMap listOf(it) - if (realAnnotation.kind != ClassKind.ANNOTATION_CLASS || !realAnnotation.hasAnnotation(StandardNames.FqNames.repeatable)) { - return@flatMap listOf(it) - } - - (it.getValueArgument(0) as IrVararg).elements.map { repAnno -> repAnno as IrConstructorCall } - }.filter { it.startOffset != -1 && it.endOffset != -1 } - - assert(unwrappedIrAnnotations.size == firAnnotationContainer.annotations.size) { - "Number of annotations for IR and FIR declaration are not equal" - } - - val irArguments = unwrappedIrAnnotations - .find { it.startOffset == firAnnotation.source?.startOffset && it.endOffset == firAnnotation.source?.endOffset } - ?.getArgumentsWithIr() - ?: error("Could not find corresponding IR annotation for ${firAnnotation.render()}") - - val annotationArgsMapping = buildAnnotationArgumentMapping { - firAnnotation.argumentMapping.mapping.forEach { (name, firExpression) -> - if (firExpression is FirConstExpression<*>) { - mapping[name] = firExpression - return@forEach - } - val irExpression = irArguments.single { it.first.name == name }.second - mapping[name] = irExpression.convertToFir(firExpression) - } - } - - return when (firAnnotation) { - is FirAnnotationCall -> buildAnnotationCall { - this.annotationTypeRef = firAnnotation.annotationTypeRef - this.calleeReference = firAnnotation.calleeReference - this.argumentMapping = annotationArgsMapping - } - else -> buildAnnotation { - this.annotationTypeRef = firAnnotation.annotationTypeRef - this.argumentMapping = annotationArgsMapping - } - } - } - - private fun IrElement.convertToFir(firExpression: FirExpression): FirExpression { - return when { - this is IrConst<*> -> toFirConst() ?: firExpression - this is IrConstructorCall && firExpression is FirFunctionCall -> { - val resolvedArgumentMapping = firExpression.resolvedArgumentMapping ?: return firExpression - val irArgs = this.getArgumentsWithIr() - buildFunctionCall { - this.source = firExpression.source - this.typeRef = firExpression.typeRef - this.dispatchReceiver = firExpression.dispatchReceiver - this.extensionReceiver = firExpression.extensionReceiver - this.explicitReceiver = firExpression.explicitReceiver - this.calleeReference = firExpression.calleeReference - this.annotations.addAll(firExpression.annotations) - this.typeArguments.addAll(firExpression.typeArguments) - - val newArgMapping = LinkedHashMap( - resolvedArgumentMapping.map { (key, value) -> - irArgs.first { it.first.name == value.name }.second.convertToFir(key) to value - }.toMap() - ) - this.argumentList = buildResolvedArgumentList(newArgMapping, firExpression.argumentList.source) - } - } - this is IrVararg && firExpression is FirVarargArgumentsExpression -> buildVarargArgumentsExpression { - this.source = firExpression.source - this.typeRef = firExpression.typeRef - this.annotations.addAll(firExpression.annotations) - this.varargElementType = firExpression.varargElementType - this.arguments.addAll( - firExpression.arguments.zip(this@convertToFir.elements).map { it.second.convertToFir(it.first) } - ) - } - this is IrVararg && firExpression is FirArrayOfCall -> buildArrayOfCall { - this.source = firExpression.source - this.typeRef = firExpression.typeRef - this.annotations.addAll(firExpression.annotations) - this.argumentList = buildArgumentList { - this.source = firExpression.argumentList.source - this.arguments.addAll( - firExpression.argumentList.arguments.zip(this@convertToFir.elements).map { it.second.convertToFir(it.first) } - ) - } - } - else -> firExpression - } - } - - 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 IrConst.toFirConst(): FirConstExpression? { - @Suppress("UNCHECKED_CAST") - val kind = getConstantKind() as? ConstantValueKind ?: return null - return buildConstExpression(null, kind, this.value) } } \ No newline at end of file diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt index 507df83726d..9ab39df0206 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt @@ -63,7 +63,7 @@ import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.addToStdlib.runIf -private fun AbstractKtSourceElement?.startOffsetSkippingComments(): Int? { +fun AbstractKtSourceElement?.startOffsetSkippingComments(): Int? { return when (this) { is KtPsiSourceElement -> this.psi.startOffsetSkippingComments is KtLightSourceElement -> this.startOffsetSkippingComments diff --git a/core/compiler.common/src/org/jetbrains/kotlin/constant/ConstantValue.kt b/core/compiler.common/src/org/jetbrains/kotlin/constant/ConstantValue.kt index 6c371a3f269..c22a231ffc9 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/constant/ConstantValue.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/constant/ConstantValue.kt @@ -30,12 +30,12 @@ abstract class IntegerValueConstant protected constructor(value: T) : Con abstract class UnsignedValueConstant protected constructor(value: T) : ConstantValue(value) class AnnotationValue private constructor(value: Value) : ConstantValue(value) { - class Value(val type: KotlinTypeMarker, val argumentsMapping: Map?>) + class Value(val type: KotlinTypeMarker, val argumentsMapping: Map>) override fun accept(visitor: AnnotationArgumentVisitor, data: D): R = visitor.visitAnnotationValue(this, data) companion object { - fun create(type: KotlinTypeMarker, argumentsMapping: Map?>): AnnotationValue { + fun create(type: KotlinTypeMarker, argumentsMapping: Map>): AnnotationValue { return AnnotationValue( Value(type, argumentsMapping) )