Skip to content

Commit 9e1fcba

Browse files
sandwwraithSpace Team
authored andcommitted
[kx.serialization] Do not try to instantiate type params serializers
if they are not required for custom serializer Also make Instantiator.Args much simpler #KT-76949 Fixed
1 parent 2f88ae4 commit 9e1fcba

File tree

2 files changed

+66
-42
lines changed

2 files changed

+66
-42
lines changed

plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/BaseIrGenerator.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -506,8 +506,10 @@ abstract class BaseIrGenerator(private val currentClass: IrClass, final override
506506
}
507507

508508
return type.arguments.map { argumentType ->
509-
argumentType as? IrSimpleType ?: return null
510-
val serializer = findTypeSerializerOrContext(compilerContext, argumentType)
509+
if (argumentType !is IrSimpleType) return null
510+
// If serializer is null, it is either a type parameter or non-serializable class.
511+
// In both cases, we cannot cache it.
512+
val serializer = findTypeSerializerOrContextUnchecked(compilerContext, argumentType) ?: return null
511513
serializerInstance(
512514
serializer,
513515
compilerContext,

plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/Instantiator.kt

Lines changed: 62 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import org.jetbrains.kotlin.descriptors.ClassKind
1010
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
1111
import org.jetbrains.kotlin.ir.builders.*
1212
import org.jetbrains.kotlin.ir.declarations.IrClass
13+
import org.jetbrains.kotlin.ir.declarations.IrConstructor
1314
import org.jetbrains.kotlin.ir.expressions.IrClassReference
1415
import org.jetbrains.kotlin.ir.expressions.IrExpression
16+
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
1517
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
1618
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
1719
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
@@ -28,7 +30,6 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializersClassIds.
2830
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializersClassIds.polymorphicSerializerId
2931
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializersClassIds.referenceArraySerializerId
3032
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializersClassIds.sealedSerializerId
31-
import kotlin.collections.orEmpty
3233

3334
internal class Instantiator(
3435
val generator: BaseIrGenerator,
@@ -50,7 +51,6 @@ internal class Instantiator(
5051

5152
data class Args(
5253
val args: List<IrExpression>, val typeArgs: List<IrType>,
53-
val useCompanionShortcut: Boolean, val needToCopyAnnotations: Boolean,
5454
)
5555

5656
context(irBuilder: IrBuilderWithScope)
@@ -70,60 +70,80 @@ internal class Instantiator(
7070
kType as? IrSimpleType ?: error("Don't know how to work with type ${kType::class}")
7171
val typeArgumentsAsTypes = kType.argumentTypesOrUpperBounds()
7272

73-
val args = when (serializerClass.owner.classId) {
74-
polymorphicSerializerId -> Args(listOf(classReferenceOf(kType)), listOf(kType), false, true)
75-
contextSerializerId -> {
76-
doContextSerializer(kType, genericIndex, typeArgumentsAsTypes) ?: return null
77-
}
73+
val needToCopyAnnotations = serializerClass.owner.classId.let { it == polymorphicSerializerId || it == objectSerializerId }
74+
75+
// If KType is interface, .classSerializer always yields PolymorphicSerializer, which may be unavailable for interfaces from other modules
76+
val canUseShortcut =
77+
!kType.isInterface() && serializerClass == kType.classOrUpperBound()?.owner.classSerializer(compilerContext) && generator !is SerializableCompanionIrGenerator
78+
79+
var ctor: IrConstructor? = null
80+
81+
val (args, typeArgs) = when (serializerClass.owner.classId) {
82+
polymorphicSerializerId -> Args(listOf(classReferenceOf(kType)), listOf(kType))
83+
contextSerializerId -> argsForContextSerializer(kType, genericIndex, typeArgumentsAsTypes) ?: return null
7884
objectSerializerId -> Args(
7985
args = listOf(irBuilder.irString(kType.serialName()), irBuilder.irGetObject(kType.classOrUpperBound()!!)),
8086
typeArgs = listOf(kType),
81-
useCompanionShortcut = false,
82-
needToCopyAnnotations = true,
8387
)
84-
sealedSerializerId -> doSealed(serializerClass, kType)
88+
sealedSerializerId -> return instantiateSealedSerializer(serializerClass, kType)
8589
enumSerializerId -> return instantiateEnumSerializer(kType)
8690
referenceArraySerializerId -> {
8791
val (origArgs, origTypeArgs) = regularArgs(typeArgumentsAsTypes) ?: return null
8892
val args = listOf(generator.wrapperClassReference(typeArgumentsAsTypes.single())) + origArgs
8993
val typeArgs = listOf(origTypeArgs[0].makeNotNull()) + origTypeArgs
90-
Args(args, typeArgs, false, false)
94+
Args(args, typeArgs)
95+
}
96+
else -> {
97+
if (canUseShortcut) {
98+
regularArgs(typeArgumentsAsTypes) ?: return null
99+
} else {
100+
ctor = findConstructor(serializerClass, needToCopyAnnotations).owner
101+
val requiresArgs = ctor.parameters.isNotEmpty()
102+
if (!requiresArgs) Args(emptyList(), emptyList()) else regularArgs(typeArgumentsAsTypes) ?: return null
103+
}
91104
}
92-
else -> regularArgs(typeArgumentsAsTypes) ?: return null
93105
}
94106

95-
val canUseShortcut =
96-
!kType.isInterface() && serializerClass == kType.classOrUpperBound()?.owner.classSerializer(compilerContext) && generator !is SerializableCompanionIrGenerator
97-
if (canUseShortcut || args.useCompanionShortcut) {
107+
if (canUseShortcut) {
98108
// This is default type serializer, we can shortcut through Companion.serializer()
99109
// BUT not during generation of this method itself
100-
// TODO: check if we still want to build args for sealed/polymorphic serializers here
101-
generator.callSerializerFromCompanion(kType, args.typeArgs, args.args, serializerClass.owner.classId)?.let { return it }
110+
// For future: check if we still want to build args for polymorphic/object serializers here, likely not.
111+
generator.callSerializerFromCompanion(kType, typeArgs, args, serializerClass.owner.classId)?.let { return it }
102112
}
103113

114+
val newArgs = if (needToCopyAnnotations) addAnnotationsToArgs(kType, args) else args
104115

105-
val needToCopyAnnotations = args.needToCopyAnnotations
106-
107-
val ctor = findConstructor(serializerClass, needToCopyAnnotations)
108-
val ctorDecl = ctor.owner
109-
110-
val newArgs = if (needToCopyAnnotations) {
111-
val classAnnotations =
112-
generator.copyAnnotationsFrom(kType.getClass()?.let { generator.collectSerialInfoAnnotations(it) }.orEmpty())
113-
args.args + generator.createArrayOfExpression(compilerContext.irBuiltIns.annotationType, classAnnotations)
114-
} else args.args
116+
if (ctor == null) ctor = findConstructor(serializerClass, needToCopyAnnotations).owner
117+
return callConstructor(ctor, typeArgs, newArgs)
118+
}
115119

116-
val typeParameters = ctorDecl.parentAsClass.typeParameters
117-
val substitutedReturnType = ctorDecl.returnType.substitute(typeParameters, args.typeArgs)
120+
context(irBuilder: IrBuilderWithScope)
121+
private fun callConstructor(
122+
ctor: IrConstructor,
123+
typeArgs: List<IrType>,
124+
valueArgs: List<IrExpression>,
125+
): IrFunctionAccessExpression {
126+
val typeParameters = ctor.parentAsClass.typeParameters
127+
val substitutedReturnType = ctor.returnType.substitute(typeParameters, typeArgs)
118128
return generator.irInvoke(
119-
ctor,
129+
ctor.symbol,
120130
// User may declare serializer with fixed type arguments, e.g. class SomeSerializer : KSerializer<ClosedRange<Float>>
121-
arguments = newArgs.takeIf { it.size == ctorDecl.parameters.size }.orEmpty(),
122-
typeArguments = args.typeArgs.takeIf { it.size == ctorDecl.typeParameters.size }.orEmpty(),
131+
arguments = valueArgs.takeIf { it.size == ctor.parameters.size }.orEmpty(),
132+
typeArguments = typeArgs.takeIf { it.size == ctor.typeParameters.size }.orEmpty(),
123133
returnTypeHint = substitutedReturnType
124134
)
125135
}
126136

137+
context(irBuilder: IrBuilderWithScope)
138+
private fun addAnnotationsToArgs(
139+
kType: IrSimpleType,
140+
args: List<IrExpression>,
141+
): List<IrExpression> {
142+
val classAnnotations =
143+
generator.copyAnnotationsFrom(kType.getClass()?.let { generator.collectSerialInfoAnnotations(it) }.orEmpty())
144+
return args + generator.createArrayOfExpression(compilerContext.irBuiltIns.annotationType, classAnnotations)
145+
}
146+
127147
private fun findConstructor(serializerClass: IrClassSymbol, needToCopyAnnotations: Boolean): IrConstructorSymbol {
128148
val serializable = getSerializableClassDescriptorBySerializer(serializerClass.owner)
129149
val ctor = if (serializable?.typeParameters?.isNotEmpty() == true) {
@@ -152,7 +172,7 @@ internal class Instantiator(
152172
context(irBuilder: IrBuilderWithScope)
153173
private fun classReferenceOf(kType: IrSimpleType): IrClassReference = generator.classReference(kType.classOrUpperBound()!!)
154174

155-
context(irBuilder: IrBuilderWithScope) private fun doContextSerializer(
175+
context(irBuilder: IrBuilderWithScope) private fun argsForContextSerializer(
156176
kType: IrSimpleType,
157177
genericIndex: Int?,
158178
typeArgumentsAsTypes: List<IrType>,
@@ -187,7 +207,7 @@ internal class Instantiator(
187207
})
188208
)
189209
}
190-
return Args(args, typeArgs, false, false)
210+
return Args(args, typeArgs)
191211
}
192212

193213
context(irBuilder: IrBuilderWithScope) private fun instantiateEnumSerializer(kType: IrSimpleType): IrExpression {
@@ -248,13 +268,13 @@ internal class Instantiator(
248268
)
249269
instantiate(argSer, it) ?: return null
250270
}
251-
return Args(args, typeArgumentsAsTypes, false, false)
271+
return Args(args, typeArgumentsAsTypes)
252272
}
253273

254-
context(irBuilder: IrBuilderWithScope) private fun doSealed(
274+
context(irBuilder: IrBuilderWithScope) private fun instantiateSealedSerializer(
255275
serializerClass: IrClassSymbol,
256276
kType: IrSimpleType,
257-
): Args {
277+
): IrExpression {
258278
val needToCopyAnnotations = true
259279
val typeArgs = listOf(kType)
260280

@@ -290,8 +310,7 @@ internal class Instantiator(
290310
}
291311
}
292312
}
293-
return Args(args, typeArgs, true, false)
294-
// generator.callSerializerFromCompanion(kType, typeArgs, args, sealedSerializerId)?.let { return TODO(it.toString()) }
313+
generator.callSerializerFromCompanion(kType, typeArgs, args, sealedSerializerId)?.let { return it }
295314
}
296315

297316

@@ -352,7 +371,10 @@ internal class Instantiator(
352371
)
353372
)
354373
}
355-
return Args(args, typeArgs, false, needToCopyAnnotations)
374+
val newArgs = addAnnotationsToArgs(kType, args)
375+
376+
val ctor = findConstructorWithoutTypeParameters(serializerClass, needToCopyAnnotations).owner
377+
return callConstructor(ctor, typeArgs, newArgs)
356378
}
357379

358380
context(irBuilder: IrBuilderWithScope)

0 commit comments

Comments
 (0)