From e0dce31cdefb386dcbade987168b0fa9d187377a Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Fri, 3 Feb 2023 15:19:28 +0100 Subject: [PATCH] Support situation when argument for serializer() function has SerialInfo annotations. Because SerializationJvmIrIntrinsicSupport does not instantiate annotations yet, this info could be lost. As a workaround, it is possible to call Companion.serializer() functions instead of direct serializer instantiation, as they are plugin-generated and correctly handle annotations. Note that for some cases (enums & interfaces) this WA is not enough, so additional work is needed later. Fixes https://github.com/Kotlin/kotlinx.serialization/issues/2179 --- .../ir/SerializationJvmIrIntrinsicSupport.kt | 17 +++++--- .../testData/boxIr/intrinsicAnnotations.kt | 40 +++++++++++++++++++ .../testData/codegen/Intrinsics.asm.ir.txt | 11 ++--- .../codegen/IntrinsicsAdvanced.asm.ir.txt | 6 ++- ...SerializationFirBlackBoxTestGenerated.java | 6 +++ .../SerializationIrBoxTestGenerated.java | 6 +++ 6 files changed, 73 insertions(+), 13 deletions(-) create mode 100644 plugins/kotlinx-serialization/testData/boxIr/intrinsicAnnotations.kt diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializationJvmIrIntrinsicSupport.kt b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializationJvmIrIntrinsicSupport.kt index b70a8828814..9671d156327 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializationJvmIrIntrinsicSupport.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializationJvmIrIntrinsicSupport.kt @@ -49,6 +49,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializersClassIds. import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializersClassIds.referenceArraySerializerId import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializersClassIds.sealedSerializerId import org.jetbrains.kotlinx.serialization.compiler.resolve.SpecialBuiltins +import org.jetbrains.kotlinx.serialization.compiler.resolve.annotationsWithArguments import org.jetbrains.kotlinx.serialization.compiler.resolve.getClassFromSerializationPackage import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type @@ -381,8 +382,8 @@ class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContex val descriptor = StringBuilder("(${serializersModuleType.descriptor}${AsmTypes.K_CLASS_TYPE.descriptor}") // Generic args (if present) if (argSerializers.isNotEmpty()) { - fillArray(kSerializerType, argSerializers) { _, serializer -> - instantiate(serializer, null) + fillArray(kSerializerType, argSerializers) { _, (type, _) -> + generateSerializerForType(type, this, intrinsicType) } descriptor.append(kSerializerArrayType.descriptor) } @@ -485,8 +486,8 @@ class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContex aconst(null) } signature.append(kSerializerType.descriptor) - fillArray(kSerializerType, argSerializers) { _, serializer -> - instantiate(serializer, null) + fillArray(kSerializerType, argSerializers) { _, (type, _) -> + generateSerializerForType(type, this, intrinsicType) } signature.append(kSerializerArrayType.descriptor) } @@ -498,7 +499,8 @@ class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContex AsmUtil.wrapJavaClassIntoKClass(this) signature.append(AsmTypes.K_CLASS_TYPE.descriptor) // Reference array serializer still needs serializer for its argument type - instantiate(argSerializers[0], signature) + generateSerializerForType(argSerializers[0].first, this, intrinsicType) + signature.append(kSerializerType.descriptor) } sealedSerializerId -> { @@ -550,7 +552,10 @@ class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContex signature.append("Ljava/lang/Object;") } // all serializers get arguments with serializers of their generic types - else -> argSerializers.forEach { instantiate(it, signature) } + else -> argSerializers.forEach { (type, _) -> + generateSerializerForType(type, this, intrinsicType) + signature.append(kSerializerType.descriptor) + } } signature.append(")V") // invoke constructor diff --git a/plugins/kotlinx-serialization/testData/boxIr/intrinsicAnnotations.kt b/plugins/kotlinx-serialization/testData/boxIr/intrinsicAnnotations.kt new file mode 100644 index 00000000000..573e492324f --- /dev/null +++ b/plugins/kotlinx-serialization/testData/boxIr/intrinsicAnnotations.kt @@ -0,0 +1,40 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM_IR + +// WITH_STDLIB + +import kotlinx.serialization.* +import kotlinx.serialization.json.* +import kotlinx.serialization.internal.* +import kotlinx.serialization.descriptors.* +import kotlinx.serialization.modules.* +import kotlin.test.* + +@Serializable +@JsonClassDiscriminator("sealed") +sealed class Sealed + +@Serializable +@JsonClassDiscriminator("abstract") +abstract class Abstract + +@Serializable +@JsonClassDiscriminator("object") +object Object + +fun test(descriptor: SerialDescriptor, value: String, name: String = descriptor.serialName) { + val anno = descriptor.annotations.filterIsInstance().singleOrNull() + requireNotNull(anno) { "Annotation value not found for $name" } + assertEquals(anno.discriminator, value, "Annotation value incorrect for $name") +} + +fun box(): String { + test(serializer().descriptor, "sealed") + test(serializer().descriptor, "abstract") + test(serializer().descriptor, "object") + test(serializer>().descriptor.getElementDescriptor(0), "sealed", "List") + test(serializer>().descriptor.getElementDescriptor(0), "abstract", "List") + test(serializer>().descriptor.getElementDescriptor(0), "object", "List") + test(serializer>().descriptor.getElementDescriptor(0), "sealed", "Array") + return "OK" +} diff --git a/plugins/kotlinx-serialization/testData/codegen/Intrinsics.asm.ir.txt b/plugins/kotlinx-serialization/testData/codegen/Intrinsics.asm.ir.txt index 7d84fdf36e4..cc00b38db9a 100644 --- a/plugins/kotlinx-serialization/testData/codegen/Intrinsics.asm.ir.txt +++ b/plugins/kotlinx-serialization/testData/codegen/Intrinsics.asm.ir.txt @@ -127,7 +127,8 @@ public final class IntrinsicsKt : java/lang/Object { GETSTATIC (Box, Companion, LBox$Companion;) NEW (kotlinx/serialization/internal/ArrayListSerializer) DUP - GETSTATIC (Simple$$serializer, INSTANCE, LSimple$$serializer;) + GETSTATIC (Simple, Companion, LSimple$Companion;) + INVOKEVIRTUAL (Simple$Companion, serializer, ()Lkotlinx/serialization/KSerializer;) INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, , (Lkotlinx/serialization/KSerializer;)V) INVOKEVIRTUAL (Box$Companion, serializer, (Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;) POP @@ -142,7 +143,8 @@ public final class IntrinsicsKt : java/lang/Object { GETSTATIC (Box, Companion, LBox$Companion;) NEW (kotlinx/serialization/internal/ArrayListSerializer) DUP - GETSTATIC (Simple$$serializer, INSTANCE, LSimple$$serializer;) + GETSTATIC (Simple, Companion, LSimple$Companion;) + INVOKEVIRTUAL (Simple$Companion, serializer, ()Lkotlinx/serialization/KSerializer;) INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, , (Lkotlinx/serialization/KSerializer;)V) INVOKEVIRTUAL (Box$Companion, serializer, (Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;) INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, , (Lkotlinx/serialization/KSerializer;)V) @@ -167,10 +169,9 @@ public final class IntrinsicsKt : java/lang/Object { DUP NEW (kotlinx/serialization/internal/ArrayListSerializer) DUP - NEW (Box$$serializer) - DUP + GETSTATIC (Box, Companion, LBox$Companion;) GETSTATIC (kotlinx/serialization/internal/IntSerializer, INSTANCE, Lkotlinx/serialization/internal/IntSerializer;) - INVOKESPECIAL (Box$$serializer, , (Lkotlinx/serialization/KSerializer;)V) + INVOKEVIRTUAL (Box$Companion, serializer, (Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;) INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, , (Lkotlinx/serialization/KSerializer;)V) INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, , (Lkotlinx/serialization/KSerializer;)V) LABEL (L21) diff --git a/plugins/kotlinx-serialization/testData/codegen/IntrinsicsAdvanced.asm.ir.txt b/plugins/kotlinx-serialization/testData/codegen/IntrinsicsAdvanced.asm.ir.txt index cf86bf8bcda..12abb1a5d01 100644 --- a/plugins/kotlinx-serialization/testData/codegen/IntrinsicsAdvanced.asm.ir.txt +++ b/plugins/kotlinx-serialization/testData/codegen/IntrinsicsAdvanced.asm.ir.txt @@ -50,7 +50,8 @@ public final class IntrinsicsAdvancedKt : java/lang/Object { POP NEW (kotlinx/serialization/internal/ArrayListSerializer) DUP - GETSTATIC (Simple$$serializer, INSTANCE, LSimple$$serializer;) + GETSTATIC (Simple, Companion, LSimple$Companion;) + INVOKEVIRTUAL (Simple$Companion, serializer, ()Lkotlinx/serialization/KSerializer;) INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, , (Lkotlinx/serialization/KSerializer;)V) POP LABEL (L3) @@ -109,7 +110,8 @@ public final class IntrinsicsAdvancedKt : java/lang/Object { ANEWARRAY (kotlinx/serialization/KSerializer) DUP ICONST_0 - GETSTATIC (Simple$$serializer, INSTANCE, LSimple$$serializer;) + GETSTATIC (Simple, Companion, LSimple$Companion;) + INVOKEVIRTUAL (Simple$Companion, serializer, ()Lkotlinx/serialization/KSerializer;) AASTORE INVOKESTATIC (kotlinx/serialization/SerializersKt, noCompiledSerializer, (Lkotlinx/serialization/modules/SerializersModule;Lkotlin/reflect/KClass;[Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;) LABEL (L15) diff --git a/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationFirBlackBoxTestGenerated.java b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationFirBlackBoxTestGenerated.java index ce5e787241f..a56971730b0 100644 --- a/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationFirBlackBoxTestGenerated.java +++ b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationFirBlackBoxTestGenerated.java @@ -111,6 +111,12 @@ public class SerializationFirBlackBoxTestGenerated extends AbstractSerialization runTest("plugins/kotlinx-serialization/testData/boxIr/inlineClasses.kt"); } + @Test + @TestMetadata("intrinsicAnnotations.kt") + public void testIntrinsicAnnotations() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/intrinsicAnnotations.kt"); + } + @Test @TestMetadata("intrinsicsBox.kt") public void testIntrinsicsBox() throws Exception { diff --git a/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrBoxTestGenerated.java b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrBoxTestGenerated.java index ee802f07f1b..ced9e702dd7 100644 --- a/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrBoxTestGenerated.java +++ b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrBoxTestGenerated.java @@ -109,6 +109,12 @@ public class SerializationIrBoxTestGenerated extends AbstractSerializationIrBoxT runTest("plugins/kotlinx-serialization/testData/boxIr/inlineClasses.kt"); } + @Test + @TestMetadata("intrinsicAnnotations.kt") + public void testIntrinsicAnnotations() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/intrinsicAnnotations.kt"); + } + @Test @TestMetadata("intrinsicsBox.kt") public void testIntrinsicsBox() throws Exception {