diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirAnnotationArgumentVisitor.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirAnnotationArgumentVisitor.kt index 728ff08f05d..c306a526327 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirAnnotationArgumentVisitor.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirAnnotationArgumentVisitor.kt @@ -13,7 +13,7 @@ import org.jetbrains.kotlin.metadata.deserialization.Flags internal object FirAnnotationArgumentVisitor : AnnotationArgumentVisitor() { override fun visitAnnotationValue(value: AnnotationValue, data: FirAnnotationArgumentVisitorData) { data.builder.type = ProtoBuf.Annotation.Argument.Value.Type.ANNOTATION - // TODO: annotation = serializeAnnotation(value.value) + data.builder.annotation = data.serializer.serializeAnnotation(value.value) } override fun visitArrayValue(value: ArrayValue, data: FirAnnotationArgumentVisitorData) { 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 497f8123f70..a8a007c93bc 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 @@ -28,7 +28,7 @@ class FirAnnotationSerializer(private val session: FirSession, internal val stri fun addArgument(argumentExpression: FirExpression, parameterName: Name) { val argument = ProtoBuf.Annotation.Argument.newBuilder() argument.nameId = stringTable.getStringIndex(parameterName.asString()) - argument.setValue(valueProto(argumentExpression.toConstantValue() ?: return)) + argument.setValue(valueProto(argumentExpression.toConstantValue(session) ?: return)) addArgument(argument) } diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt index 2d70117875e..f354043633b 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt @@ -884,7 +884,7 @@ class FirElementSerializer private constructor( private fun serializeVersionRequirementFromRequireKotlin(annotation: FirAnnotation): ProtoBuf.VersionRequirement.Builder? { val argumentMapping = annotation.argumentMapping.mapping - val versionString = (argumentMapping[RequireKotlinConstants.VERSION]?.toConstantValue() as? StringValue)?.value ?: return null + val versionString = (argumentMapping[RequireKotlinConstants.VERSION]?.toConstantValue(session) as? StringValue)?.value ?: return null val matchResult = RequireKotlinConstants.VERSION_REGEX.matchEntire(versionString) ?: return null val major = matchResult.groupValues.getOrNull(1)?.toIntOrNull() ?: return null @@ -897,12 +897,12 @@ class FirElementSerializer private constructor( writeVersionFull = { proto.versionFull = it } ) - val message = (argumentMapping[RequireKotlinConstants.MESSAGE]?.toConstantValue() as? StringValue)?.value + val message = (argumentMapping[RequireKotlinConstants.MESSAGE]?.toConstantValue(session) as? StringValue)?.value if (message != null) { proto.message = stringTable.getStringIndex(message) } - when ((argumentMapping[RequireKotlinConstants.LEVEL]?.toConstantValue() as? EnumValue)?.enumEntryName?.asString()) { + when ((argumentMapping[RequireKotlinConstants.LEVEL]?.toConstantValue(session) as? EnumValue)?.enumEntryName?.asString()) { DeprecationLevel.ERROR.name -> { // ERROR is the default level } @@ -910,7 +910,7 @@ class FirElementSerializer private constructor( DeprecationLevel.HIDDEN.name -> proto.level = ProtoBuf.VersionRequirement.Level.HIDDEN } - when ((argumentMapping[RequireKotlinConstants.VERSION_KIND]?.toConstantValue() as? EnumValue)?.enumEntryName?.asString()) { + when ((argumentMapping[RequireKotlinConstants.VERSION_KIND]?.toConstantValue(session) as? EnumValue)?.enumEntryName?.asString()) { ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION.name -> { // LANGUAGE_VERSION is the default kind } @@ -920,7 +920,7 @@ class FirElementSerializer private constructor( proto.versionKind = ProtoBuf.VersionRequirement.VersionKind.API_VERSION } - val errorCode = (argumentMapping[RequireKotlinConstants.ERROR_CODE]?.toConstantValue() as? IntValue)?.value + val errorCode = (argumentMapping[RequireKotlinConstants.ERROR_CODE]?.toConstantValue(session) as? IntValue)?.value if (errorCode != null && errorCode != -1) { proto.errorCode = errorCode } diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/ConstantValue.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/ConstantValue.kt index 331f1256469..f4ab8eaae2c 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/ConstantValue.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/ConstantValue.kt @@ -157,6 +157,7 @@ internal class KClassValue(value: Value) : ConstantValue(valu var type = argumentType var arrayDimensions = 0 while (true) { + if (type.isPrimitiveArray) break type = type.arrayElementType() ?: break arrayDimensions++ } 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 01be9b06a4f..67a5d79af0a 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 @@ -5,10 +5,23 @@ 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.containingClass import org.jetbrains.kotlin.fir.declarations.FirEnumEntry +import org.jetbrains.kotlin.fir.declarations.FirFunction import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.expressions.builder.FirAnnotationCallBuilder +import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationArgumentMapping +import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCall +import org.jetbrains.kotlin.fir.expressions.builder.buildArgumentList +import org.jetbrains.kotlin.fir.references.builder.buildSimpleNamedReference import org.jetbrains.kotlin.fir.render +import org.jetbrains.kotlin.fir.resolve.defaultType +import org.jetbrains.kotlin.fir.resolve.toFirRegularClass +import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.classId import org.jetbrains.kotlin.fir.types.coneTypeSafe @@ -16,12 +29,12 @@ import org.jetbrains.kotlin.fir.types.coneTypeUnsafe import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor import org.jetbrains.kotlin.types.ConstantValueKind -internal fun FirExpression.toConstantValue(): ConstantValue<*>? = accept(FirToConstantValueTransformer, null) +internal fun FirExpression.toConstantValue(session: FirSession): ConstantValue<*>? = accept(FirToConstantValueTransformer, session) -internal object FirToConstantValueTransformer : FirDefaultVisitor?, Nothing?>() { +internal object FirToConstantValueTransformer : FirDefaultVisitor?, FirSession>() { override fun visitElement( element: FirElement, - data: Nothing? + data: FirSession ): ConstantValue<*>? { error("Illegal element as annotation argument: ${element::class.qualifiedName} -> ${element.render()}") } @@ -29,7 +42,7 @@ internal object FirToConstantValueTransformer : FirDefaultVisitor visitConstExpression( constExpression: FirConstExpression, - data: Nothing? + data: FirSession ): ConstantValue<*>? { val value = constExpression.value return when (constExpression.kind) { @@ -53,59 +66,110 @@ internal object FirToConstantValueTransformer : FirDefaultVisitor { - return ArrayValue(arrayOfCall.argumentList.arguments.mapNotNull { it.accept(this, null) }) + return ArrayValue(arrayOfCall.argumentList.arguments.mapNotNull { it.accept(this, data) }) } override fun visitAnnotation( annotation: FirAnnotation, - data: Nothing? + data: FirSession ): ConstantValue<*> { return AnnotationValue(annotation) } - override fun visitAnnotationCall(annotationCall: FirAnnotationCall, data: Nothing?): ConstantValue<*> { + override fun visitAnnotationCall(annotationCall: FirAnnotationCall, data: FirSession): ConstantValue<*> { return visitAnnotation(annotationCall, data) } override fun visitGetClassCall( getClassCall: FirGetClassCall, - data: Nothing? + data: FirSession ): ConstantValue<*>? { - return KClassValue.create(getClassCall.typeRef.coneTypeUnsafe()) + return KClassValue.create(getClassCall.argument.typeRef.coneTypeUnsafe()) } override fun visitQualifiedAccessExpression( qualifiedAccessExpression: FirQualifiedAccessExpression, - data: Nothing? + data: FirSession ): ConstantValue<*>? { val symbol = qualifiedAccessExpression.toResolvedCallableSymbol() ?: return null - val enumEntry = symbol.fir as? FirEnumEntry ?: return null - val classId = enumEntry.returnTypeRef.coneTypeSafe()?.classId ?: return null - val outerClassId = classId.outerClassId ?: return null - return EnumValue(outerClassId, enumEntry.name) + + return when { + symbol.fir is FirEnumEntry -> { + val classId = symbol.fir.returnTypeRef.coneTypeSafe()?.classId ?: return null + EnumValue(classId, (symbol.fir as FirEnumEntry).name) + } + + symbol is FirConstructorSymbol -> { + val constructorCall = qualifiedAccessExpression as FirFunctionCall + val constructedClassSymbol = symbol.containingClass()?.toFirRegularClassSymbol(data) ?: return null + return if (constructedClassSymbol.classKind == ClassKind.ANNOTATION_CLASS) { + AnnotationValue( + buildAnnotationCall { + argumentMapping = buildAnnotationArgumentMapping { + constructorCall.argumentMapping?.forEach { (firExpression, firValueParameter) -> + mapping[firValueParameter.name] = firExpression + } + } + annotationTypeRef = qualifiedAccessExpression.typeRef + calleeReference = buildSimpleNamedReference { + source = qualifiedAccessExpression.source + name = qualifiedAccessExpression.calleeReference.name + } + } + ) + } else { + null + } + } + + symbol.callableId.packageName.asString() == "kotlin" -> { + val dispatchReceiver = qualifiedAccessExpression.dispatchReceiver + when (symbol.callableId.callableName.asString()) { + "toByte" -> ByteValue((dispatchReceiver.accept(this, data)!!.value as Number).toByte()) + "toLong" -> LongValue((dispatchReceiver.accept(this, data)!!.value as Number).toLong()) + "toShort" -> ShortValue((dispatchReceiver.accept(this, data)!!.value as Number).toShort()) + "toFloat" -> FloatValue((dispatchReceiver.accept(this, data)!!.value as Number).toFloat()) + "toDouble" -> DoubleValue((dispatchReceiver.accept(this, data)!!.value as Number).toDouble()) + "toChar" -> CharValue((dispatchReceiver.accept(this, data)!!.value as Number).toChar()) + "unaryMinus" -> { + when (val receiverValue = dispatchReceiver.accept(this, data)) { + is ByteValue -> ByteValue((-receiverValue.value).toByte()) + is LongValue -> LongValue(-receiverValue.value) + is ShortValue -> ShortValue((-receiverValue.value).toShort()) + is FloatValue -> FloatValue(-receiverValue.value) + is DoubleValue -> DoubleValue(-receiverValue.value) + else -> null + } + } + else -> null + } + } + + else -> null + } } - override fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression, data: Nothing?): ConstantValue<*>? { + override fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression, data: FirSession): ConstantValue<*>? { return visitQualifiedAccessExpression(propertyAccessExpression, data) } override fun visitFunctionCall( functionCall: FirFunctionCall, - data: Nothing? + data: FirSession ): ConstantValue<*>? { return visitQualifiedAccessExpression(functionCall, data) } override fun visitVarargArgumentsExpression( varargArgumentsExpression: FirVarargArgumentsExpression, - data: Nothing? + data: FirSession ): ConstantValue<*> { - return ArrayValue(varargArgumentsExpression.arguments.mapNotNull { it.accept(this, null) }) + return ArrayValue(varargArgumentsExpression.arguments.mapNotNull { it.accept(this, data) }) } - override fun visitNamedArgumentExpression(namedArgumentExpression: FirNamedArgumentExpression, data: Nothing?): ConstantValue<*>? { - return namedArgumentExpression.expression.accept(this, null) + override fun visitNamedArgumentExpression(namedArgumentExpression: FirNamedArgumentExpression, data: FirSession): ConstantValue<*>? { + return namedArgumentExpression.expression.accept(this, data) } } diff --git a/compiler/testData/codegen/box/reflection/annotations/onTypes/arrayKClass.kt b/compiler/testData/codegen/box/reflection/annotations/onTypes/arrayKClass.kt index 79e266cd756..1c5db7f1fe2 100644 --- a/compiler/testData/codegen/box/reflection/annotations/onTypes/arrayKClass.kt +++ b/compiler/testData/codegen/box/reflection/annotations/onTypes/arrayKClass.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: Fail: class kotlin.reflect.KClass // TARGET_BACKEND: JVM // WITH_REFLECT diff --git a/compiler/testData/codegen/box/reflection/annotations/onTypes/classLiteralWithExpectedType.kt b/compiler/testData/codegen/box/reflection/annotations/onTypes/classLiteralWithExpectedType.kt index 07ab1cbb0f0..0644ab1d3bb 100644 --- a/compiler/testData/codegen/box/reflection/annotations/onTypes/classLiteralWithExpectedType.kt +++ b/compiler/testData/codegen/box/reflection/annotations/onTypes/classLiteralWithExpectedType.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: assertEquals fails // TARGET_BACKEND: JVM // WITH_REFLECT diff --git a/compiler/testData/codegen/box/reflection/annotations/onTypes/differentArgumentTypes.kt b/compiler/testData/codegen/box/reflection/annotations/onTypes/differentArgumentTypes.kt index ac11a4374c0..66d9cbd4f36 100644 --- a/compiler/testData/codegen/box/reflection/annotations/onTypes/differentArgumentTypes.kt +++ b/compiler/testData/codegen/box/reflection/annotations/onTypes/differentArgumentTypes.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: assertEquals fails (something wrong with argument order/mapping) // TARGET_BACKEND: JVM // WITH_REFLECT package test