diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/BaseIrGenerator.kt b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/BaseIrGenerator.kt index 05c12df137e..59334939952 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/BaseIrGenerator.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/BaseIrGenerator.kt @@ -446,6 +446,11 @@ abstract class BaseIrGenerator(private val currentClass: IrClass, final override if (serializableClass.symbol == property.type.classifier) { return null } + // to avoid a cyclical dependency between the serializer cache and the cache of parametrized child serializers, + // the class should not cache its serializer as a Generic parameter of a child + if (property.type.checkTypeArgumentsHasSelf(serializableClass.symbol)) { + return null + } val serializer = getIrSerialTypeInfo(property, compilerContext).serializer ?: return null if (serializer.owner.kind == ClassKind.OBJECT) return null @@ -459,6 +464,17 @@ abstract class BaseIrGenerator(private val currentClass: IrClass, final override ) } + private fun IrSimpleType.checkTypeArgumentsHasSelf(itselfClass: IrClassSymbol): Boolean { + arguments.forEach { typeArgument -> + if (typeArgument.typeOrNull?.classifierOrNull == itselfClass) return true + if (typeArgument is IrSimpleType) { + if (typeArgument.checkTypeArgumentsHasSelf(itselfClass)) return true + } + } + + return false + } + fun IrBuilderWithScope.serializerInstance( serializerClassOriginal: IrClassSymbol?, pluginContext: SerializationPluginContext, diff --git a/plugins/kotlinx-serialization/testData/boxIr/caching.kt b/plugins/kotlinx-serialization/testData/boxIr/caching.kt index 19b04ed5f9a..04c0e469222 100644 --- a/plugins/kotlinx-serialization/testData/boxIr/caching.kt +++ b/plugins/kotlinx-serialization/testData/boxIr/caching.kt @@ -17,6 +17,20 @@ open class Open(val p: Open? = null) @Serializable abstract class Abstract(val p: Abstract? = null) +@Serializable +class GenericHolder { + var value: T? = null +} + +@Serializable +sealed class SealedGeneric { + var holder = GenericHolder() +} + +@Serializable +sealed class SealedListGeneric { + var holder = GenericHolder>>() +} fun box(): String { // A correctly cached class must be initialized correctly in order to exclude cyclic nesting of caches @@ -24,6 +38,8 @@ fun box(): String { Sealed.serializer() Open.serializer() Abstract.serializer() + SealedGeneric.serializer() + SealedListGeneric.serializer() return "OK" }