[KxSerialization] Fix NPE if sealed class has self-referencing in generic parameter

Fixes #KT-58918

If the serializable class contains itself as a generic parameter of the property, and its serializer is not an object (for example, for a sealed class), in this case there is a race in the initialization of the serializer and child serializers.

Merge-request: KT-MR-10363
Merged-by: Sergey Shanshin <Sergey.Shanshin@jetbrains.com>
This commit is contained in:
Sergey.Shanshin
2023-06-01 12:01:04 +00:00
committed by Space Team
parent e180296f0e
commit 13e2a3ae94
2 changed files with 32 additions and 0 deletions
@@ -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,
+16
View File
@@ -17,6 +17,20 @@ open class Open(val p: Open? = null)
@Serializable
abstract class Abstract(val p: Abstract? = null)
@Serializable
class GenericHolder<T> {
var value: T? = null
}
@Serializable
sealed class SealedGeneric {
var holder = GenericHolder<SealedGeneric>()
}
@Serializable
sealed class SealedListGeneric {
var holder = GenericHolder<GenericHolder<List<SealedListGeneric>>>()
}
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"
}