[K2] Support serialization of complex annotations

#KT-57611 Fixed
This commit is contained in:
Ivan Kylchik
2023-03-31 17:52:07 +02:00
committed by Space Team
parent 4a50bd9b16
commit ac480e2285
17 changed files with 328 additions and 11 deletions
@@ -7,20 +7,18 @@ package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.FirAnnotationContainer
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.buildAnnotation
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationArgumentMapping
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCall
import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression
import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.render
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.IrConst
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.getArgumentsWithIr
import org.jetbrains.kotlin.types.ConstantValueKind
@@ -56,7 +54,21 @@ class ConstValueProviderImpl(
else -> error("Cannot extract IR declaration for ${firAnnotationContainer.render()}")
} ?: return firAnnotation
return buildNewFirAnnotationByCorrespondingIrAnnotation(irDeclaration, firAnnotationContainer, firAnnotation)
val correctFirContainer = when (firAnnotation.useSiteTarget) {
AnnotationUseSiteTarget.FIELD, AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD -> {
(firAnnotationContainer as? FirProperty)?.backingField ?: return firAnnotation
}
else -> firAnnotationContainer
}
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(
@@ -121,8 +133,7 @@ class ConstValueProviderImpl(
return@forEach
}
val irExpression = irArguments.single { it.first.name == name }.second
// TODO recursion for annotations
mapping[name] = (irExpression as? IrConst<*>)?.toFirConst() ?: firExpression
mapping[name] = irExpression.convertToFir(firExpression)
}
}
@@ -139,6 +150,54 @@ class ConstValueProviderImpl(
}
}
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
@@ -28428,11 +28428,29 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/involvesIrInterpreter/serialization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("annotationInArguments.kt")
public void testAnnotationInArguments() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationInArguments.kt");
}
@Test
@TestMetadata("annotationSerialization.kt")
public void testAnnotationSerialization() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationSerialization.kt");
}
@Test
@TestMetadata("annotationWithArray.kt")
public void testAnnotationWithArray() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithArray.kt");
}
@Test
@TestMetadata("annotationWithDefaults.kt")
public void testAnnotationWithDefaults() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithDefaults.kt");
}
}
}
@@ -28428,11 +28428,29 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/involvesIrInterpreter/serialization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("annotationInArguments.kt")
public void testAnnotationInArguments() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationInArguments.kt");
}
@Test
@TestMetadata("annotationSerialization.kt")
public void testAnnotationSerialization() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationSerialization.kt");
}
@Test
@TestMetadata("annotationWithArray.kt")
public void testAnnotationWithArray() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithArray.kt");
}
@Test
@TestMetadata("annotationWithDefaults.kt")
public void testAnnotationWithDefaults() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithDefaults.kt");
}
}
}
@@ -1,5 +1,3 @@
// IGNORE_BACKEND_K2: NATIVE, JS_IR
// Ignore reason: KT-57611
// MODULE: lib
// FILE: Class.kt
@@ -0,0 +1,31 @@
// TARGET_BACKEND: JVM_IR
// TARGET_BACKEND: JS_IR
// TARGET_BACKEND: NATIVE
// MODULE: lib
// FILE: lib.kt
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
annotation class Annotation(val str: String)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
annotation class AnnotationWithAnnotation(val anno: Annotation)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
annotation class AnnotationWithAnnotationWithAnnotation(val anno: AnnotationWithAnnotation)
@AnnotationWithAnnotation(Annotation("Str" + "ing"))
class A
@AnnotationWithAnnotationWithAnnotation(AnnotationWithAnnotation(Annotation("Str" + "ing")))
class B
// MODULE: main
// FILE: main.kt
fun box(): String {
return "OK"
}
@@ -50,6 +50,19 @@ enum class SomeEnum {
B;
}
// TODO: can be uncommented after fix KT-57135
//@field:BinaryAnnotation("Str" + "ing")
//var x: Int = 5
//object Delegate {
// operator fun getValue(instance: Any?, property: Any) : String = ""
// operator fun setValue(instance: Any?, property: Any, value: String) {}
//}
//
//@delegate:BinaryAnnotation("Str" + "ing")
//val p: String by Delegate
// 7. VALUE_PARAMETER
fun @receiver:BinaryAnnotation("Str" + "ing") String.myExtension() { }
fun foo(@BinaryAnnotation("Str" + "ing") a: Int) { }
@@ -0,0 +1,27 @@
// TARGET_BACKEND: JVM_IR
// TARGET_BACKEND: JS_IR
// TARGET_BACKEND: NATIVE
// MODULE: lib
// FILE: lib.kt
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
annotation class AnnotationWithVararg(vararg val array: String)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
annotation class AnnotationWithArray(val array: Array<String>)
@AnnotationWithVararg("Str" + "ing", "String2", "String${3}")
class A
@AnnotationWithArray(["Str" + "ing", "String2", "String${3}"])
class B
// MODULE: main
// FILE: main.kt
fun box(): String {
return "OK"
}
@@ -0,0 +1,23 @@
// TARGET_BACKEND: JVM_IR
// TARGET_BACKEND: JS_IR
// TARGET_BACKEND: NATIVE
// MODULE: lib
// FILE: lib.kt
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
annotation class AnnotationWithDefault(val str: String = "Str" + "ing")
@AnnotationWithDefault()
class A
@AnnotationWithDefault("Other")
class B
// MODULE: main
// FILE: main.kt
fun box(): String {
return "OK"
}
@@ -28428,11 +28428,29 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/involvesIrInterpreter/serialization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("annotationInArguments.kt")
public void testAnnotationInArguments() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationInArguments.kt");
}
@Test
@TestMetadata("annotationSerialization.kt")
public void testAnnotationSerialization() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationSerialization.kt");
}
@Test
@TestMetadata("annotationWithArray.kt")
public void testAnnotationWithArray() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithArray.kt");
}
@Test
@TestMetadata("annotationWithDefaults.kt")
public void testAnnotationWithDefaults() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithDefaults.kt");
}
}
}
@@ -28428,11 +28428,29 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/involvesIrInterpreter/serialization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("annotationInArguments.kt")
public void testAnnotationInArguments() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationInArguments.kt");
}
@Test
@TestMetadata("annotationSerialization.kt")
public void testAnnotationSerialization() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationSerialization.kt");
}
@Test
@TestMetadata("annotationWithArray.kt")
public void testAnnotationWithArray() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithArray.kt");
}
@Test
@TestMetadata("annotationWithDefaults.kt")
public void testAnnotationWithDefaults() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithDefaults.kt");
}
}
}
@@ -21182,11 +21182,29 @@ public class FirJsCodegenBoxTestGenerated extends AbstractFirJsCodegenBoxTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/involvesIrInterpreter/serialization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
@Test
@TestMetadata("annotationInArguments.kt")
public void testAnnotationInArguments() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationInArguments.kt");
}
@Test
@TestMetadata("annotationSerialization.kt")
public void testAnnotationSerialization() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationSerialization.kt");
}
@Test
@TestMetadata("annotationWithArray.kt")
public void testAnnotationWithArray() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithArray.kt");
}
@Test
@TestMetadata("annotationWithDefaults.kt")
public void testAnnotationWithDefaults() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithDefaults.kt");
}
}
}
@@ -21182,11 +21182,29 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/involvesIrInterpreter/serialization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
@Test
@TestMetadata("annotationInArguments.kt")
public void testAnnotationInArguments() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationInArguments.kt");
}
@Test
@TestMetadata("annotationSerialization.kt")
public void testAnnotationSerialization() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationSerialization.kt");
}
@Test
@TestMetadata("annotationWithArray.kt")
public void testAnnotationWithArray() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithArray.kt");
}
@Test
@TestMetadata("annotationWithDefaults.kt")
public void testAnnotationWithDefaults() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithDefaults.kt");
}
}
}
@@ -21182,11 +21182,29 @@ public class IrJsES6CodegenBoxTestGenerated extends AbstractIrJsES6CodegenBoxTes
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/involvesIrInterpreter/serialization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
@Test
@TestMetadata("annotationInArguments.kt")
public void testAnnotationInArguments() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationInArguments.kt");
}
@Test
@TestMetadata("annotationSerialization.kt")
public void testAnnotationSerialization() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationSerialization.kt");
}
@Test
@TestMetadata("annotationWithArray.kt")
public void testAnnotationWithArray() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithArray.kt");
}
@Test
@TestMetadata("annotationWithDefaults.kt")
public void testAnnotationWithDefaults() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithDefaults.kt");
}
}
}
@@ -1,3 +1,5 @@
// KT-57135 K2 dosen't take into account `field` target on annotation for property
// MUTED_WHEN: K2
package test
annotation class AnnoClass
@@ -1,3 +1,5 @@
// KT-57135 K2 dosen't take into account `field` target on annotation for property
// MUTED_WHEN: K2
package test
annotation class Ann
@@ -24376,11 +24376,29 @@ public class FirNativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTe
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/involvesIrInterpreter/serialization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
}
@Test
@TestMetadata("annotationInArguments.kt")
public void testAnnotationInArguments() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationInArguments.kt");
}
@Test
@TestMetadata("annotationSerialization.kt")
public void testAnnotationSerialization() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationSerialization.kt");
}
@Test
@TestMetadata("annotationWithArray.kt")
public void testAnnotationWithArray() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithArray.kt");
}
@Test
@TestMetadata("annotationWithDefaults.kt")
public void testAnnotationWithDefaults() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithDefaults.kt");
}
}
}
@@ -24140,11 +24140,29 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/involvesIrInterpreter/serialization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
}
@Test
@TestMetadata("annotationInArguments.kt")
public void testAnnotationInArguments() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationInArguments.kt");
}
@Test
@TestMetadata("annotationSerialization.kt")
public void testAnnotationSerialization() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationSerialization.kt");
}
@Test
@TestMetadata("annotationWithArray.kt")
public void testAnnotationWithArray() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithArray.kt");
}
@Test
@TestMetadata("annotationWithDefaults.kt")
public void testAnnotationWithDefaults() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/serialization/annotationWithDefaults.kt");
}
}
}