Allow defining custom KSerializer for non-generic class as a class

Previously only objects were allowed. Due to a bug, this accidentally
worked in old backend.

#KT-46444 Fixed
Fixes https://github.com/Kotlin/kotlinx.serialization/issues/1587
This commit is contained in:
Leonid Startsev
2021-12-14 17:53:09 +00:00
committed by Space
parent 9a669092e3
commit 9b9522d714
3 changed files with 82 additions and 1 deletions
@@ -1093,7 +1093,14 @@ interface IrBuilderExtension {
val typeParameters = ctorDecl.parentAsClass.typeParameters
val substitutedReturnType = ctorDecl.returnType.substitute(typeParameters, typeArgs)
return irInvoke(null, ctor, typeArguments = typeArgs, valueArguments = args, returnTypeHint = substitutedReturnType)
return irInvoke(
null,
ctor,
// User may declare serializer with fixed type arguments, e.g. class SomeSerializer : KSerializer<ClosedRange<Float>>
typeArguments = typeArgs.takeIf { it.size == ctorDecl.typeParameters.size }.orEmpty(),
valueArguments = args.takeIf { it.size == ctorDecl.valueParameters.size }.orEmpty(),
returnTypeHint = substitutedReturnType
)
}
fun collectSerialInfoAnnotations(irClass: IrClass): List<IrConstructorCall> {
@@ -25,6 +25,12 @@ public class SerializationIrBoxTestGenerated extends AbstractSerializationIrBoxT
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/boxIr"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("classSerializerAsObject.kt")
public void testClassSerializerAsObject() throws Exception {
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/boxIr/classSerializerAsObject.kt");
}
@Test
@TestMetadata("multimoduleInheritance.kt")
public void testMultimoduleInheritance() throws Exception {
@@ -0,0 +1,68 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM_IR
// WITH_RUNTIME
package a
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlin.test.assertEquals
class Dummy
class DummyBox<T>
@Serializable(ClassSerializerOnClass::class)
class DummySpecified
class ClassSerializerGeneric : KSerializer<DummyBox<String>> {
override val descriptor get() = PrimitiveSerialDescriptor("ClassSerializerGeneric", PrimitiveKind.INT)
override fun deserialize(decoder: Decoder): DummyBox<String> = TODO()
override fun serialize(encoder: Encoder, value:DummyBox<String>): Unit = TODO()
}
class ClassSerializerDummy : KSerializer<Dummy> {
override val descriptor get() = PrimitiveSerialDescriptor("ClassSerializerDummy", PrimitiveKind.INT)
override fun deserialize(decoder: Decoder): Dummy = TODO()
override fun serialize(encoder: Encoder, value: Dummy): Unit = TODO()
}
object ObjectSerializerGeneric: KSerializer<DummyBox<String>> {
override val descriptor get() = PrimitiveSerialDescriptor("ObjectSerializerGeneric", PrimitiveKind.INT)
override fun deserialize(decoder: Decoder): DummyBox<String> = TODO()
override fun serialize(encoder: Encoder, value: DummyBox<String>): Unit = TODO()
}
object ObjectSerializerDummy: KSerializer<Dummy> {
override val descriptor get() = PrimitiveSerialDescriptor("ObjectSerializerDummy", PrimitiveKind.INT)
override fun deserialize(decoder: Decoder): Dummy = TODO()
override fun serialize(encoder: Encoder, value:Dummy): Unit = TODO()
}
class ClassSerializerOnClass: KSerializer<DummySpecified> {
override val descriptor get() = PrimitiveSerialDescriptor("ClassSerializerOnClass", PrimitiveKind.INT)
override fun deserialize(decoder: Decoder): DummySpecified = TODO()
override fun serialize(encoder: Encoder, value:DummySpecified): Unit = TODO()
}
@Serializable
class Holder(
@Serializable(ClassSerializerGeneric::class) val a: DummyBox<String>,
@Serializable(ClassSerializerDummy::class) val b: Dummy,
@Serializable(ObjectSerializerGeneric::class) val c: DummyBox<String>,
@Serializable(ObjectSerializerDummy::class) val d: Dummy,
val e: DummySpecified
)
fun box(): String {
val descs = Holder.serializer().descriptor.elementDescriptors.toList()
assertEquals("ClassSerializerGeneric", descs[0].serialName)
assertEquals("ClassSerializerDummy", descs[1].serialName)
assertEquals("ObjectSerializerGeneric", descs[2].serialName)
assertEquals("ObjectSerializerDummy", descs[3].serialName)
assertEquals("ClassSerializerOnClass", descs[4].serialName)
return "OK"
}