Support annotations in constructor signatures of special serializers
This commit is contained in:
+51
-2
@@ -810,6 +810,27 @@ interface IrBuilderExtension {
|
|||||||
.map { it.name.toString() }
|
.map { it.name.toString() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.copyAnnotationsFrom(annotations: List<IrConstructorCall>): List<IrExpression> =
|
||||||
|
annotations.mapNotNull { annotationCall ->
|
||||||
|
val annotationClass = annotationCall.symbol.owner.parentAsClass
|
||||||
|
if (!annotationClass.descriptor.isSerialInfoAnnotation) return@mapNotNull null
|
||||||
|
|
||||||
|
if (compilerContext.platform.isJvm()) {
|
||||||
|
val implClass = compilerContext.serialInfoImplJvmIrGenerator.getImplClass(annotationClass)
|
||||||
|
val ctor = implClass.constructors.singleOrNull { it.valueParameters.size == annotationCall.valueArgumentsCount }
|
||||||
|
?: error("No constructor args found for SerialInfo annotation Impl class: ${implClass.render()}")
|
||||||
|
irCall(ctor).apply {
|
||||||
|
for (i in 0 until annotationCall.valueArgumentsCount) {
|
||||||
|
val argument = annotationCall.getValueArgument(i)
|
||||||
|
?: annotationClass.primaryConstructor!!.valueParameters[i].defaultValue?.expression
|
||||||
|
putValueArgument(i, argument!!.deepCopyWithVariables())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
annotationCall.deepCopyWithVariables()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Does not use sti and therefore does not perform encoder calls optimization
|
// Does not use sti and therefore does not perform encoder calls optimization
|
||||||
fun IrBuilderWithScope.serializerTower(
|
fun IrBuilderWithScope.serializerTower(
|
||||||
generator: SerializerIrGenerator,
|
generator: SerializerIrGenerator,
|
||||||
@@ -920,8 +941,14 @@ interface IrBuilderExtension {
|
|||||||
val hasNewCtxSerCtor =
|
val hasNewCtxSerCtor =
|
||||||
serializerClassOriginal.classId == contextSerializerId && compilerContext.referenceConstructors(serializerClass.fqNameSafe)
|
serializerClassOriginal.classId == contextSerializerId && compilerContext.referenceConstructors(serializerClass.fqNameSafe)
|
||||||
.any { it.owner.valueParameters.size == 3 }
|
.any { it.owner.valueParameters.size == 3 }
|
||||||
|
var needToCopyAnnotations = false
|
||||||
when (serializerClassOriginal.classId) {
|
when (serializerClassOriginal.classId) {
|
||||||
contextSerializerId, polymorphicSerializerId -> {
|
polymorphicSerializerId -> {
|
||||||
|
needToCopyAnnotations = true
|
||||||
|
args = listOf(classReference(kType))
|
||||||
|
typeArgs = listOf(thisIrType)
|
||||||
|
}
|
||||||
|
contextSerializerId -> {
|
||||||
args = listOf(classReference(kType))
|
args = listOf(classReference(kType))
|
||||||
typeArgs = listOf(thisIrType)
|
typeArgs = listOf(thisIrType)
|
||||||
|
|
||||||
@@ -950,10 +977,12 @@ interface IrBuilderExtension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
objectSerializerId -> {
|
objectSerializerId -> {
|
||||||
|
needToCopyAnnotations = true
|
||||||
args = listOf(irString(kType.serialName()), irGetObject(kType.toClassDescriptor!!))
|
args = listOf(irString(kType.serialName()), irGetObject(kType.toClassDescriptor!!))
|
||||||
typeArgs = listOf(thisIrType)
|
typeArgs = listOf(thisIrType)
|
||||||
}
|
}
|
||||||
sealedSerializerId -> {
|
sealedSerializerId -> {
|
||||||
|
needToCopyAnnotations = true
|
||||||
args = mutableListOf<IrExpression>().apply {
|
args = mutableListOf<IrExpression>().apply {
|
||||||
add(irString(kType.serialName()))
|
add(irString(kType.serialName()))
|
||||||
add(classReference(kType))
|
add(classReference(kType))
|
||||||
@@ -1031,16 +1060,36 @@ interface IrBuilderExtension {
|
|||||||
findSerializerConstructorForTypeArgumentsSerializers(serializerClass)
|
findSerializerConstructorForTypeArgumentsSerializers(serializerClass)
|
||||||
) { "Generated serializer does not have constructor with required number of arguments" }
|
) { "Generated serializer does not have constructor with required number of arguments" }
|
||||||
} else {
|
} else {
|
||||||
compilerContext.referenceConstructors(serializerClass.fqNameSafe).single { it.owner.isPrimary }
|
val constructors = compilerContext.referenceConstructors(serializerClass.fqNameSafe)
|
||||||
|
// search for new signature of polymorphic/sealed/contextual serializer
|
||||||
|
if (!needToCopyAnnotations) {
|
||||||
|
constructors.single { it.owner.isPrimary }
|
||||||
|
} else {
|
||||||
|
constructors.find { it.owner.lastArgumentIsAnnotationArray() } ?: run {
|
||||||
|
// not found - we are using old serialization runtime without this feature
|
||||||
|
needToCopyAnnotations = false
|
||||||
|
constructors.single { it.owner.isPrimary }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Return type should be correctly substituted
|
// Return type should be correctly substituted
|
||||||
assert(ctor.isBound)
|
assert(ctor.isBound)
|
||||||
val ctorDecl = ctor.owner
|
val ctorDecl = ctor.owner
|
||||||
|
if (needToCopyAnnotations) {
|
||||||
|
val classAnnotations = copyAnnotationsFrom(thisIrType.getClass()?.annotations.orEmpty())
|
||||||
|
args = args + createArrayOfExpression(compilerContext.builtIns.annotationType.toIrType(), classAnnotations)
|
||||||
|
}
|
||||||
|
|
||||||
val typeParameters = ctorDecl.parentAsClass.typeParameters
|
val typeParameters = ctorDecl.parentAsClass.typeParameters
|
||||||
val substitutedReturnType = ctorDecl.returnType.substitute(typeParameters, typeArgs)
|
val substitutedReturnType = ctorDecl.returnType.substitute(typeParameters, typeArgs)
|
||||||
return irInvoke(null, ctor, typeArguments = typeArgs, valueArguments = args, returnTypeHint = substitutedReturnType)
|
return irInvoke(null, ctor, typeArguments = typeArgs, valueArguments = args, returnTypeHint = substitutedReturnType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun IrConstructor.lastArgumentIsAnnotationArray(): Boolean {
|
||||||
|
val lastArgType = valueParameters.lastOrNull()?.type
|
||||||
|
return (lastArgType != null && (lastArgType as? IrSimpleType)?.arguments?.firstOrNull()?.typeOrNull?.classFqName?.toString() == "kotlin.Annotation")
|
||||||
|
}
|
||||||
|
|
||||||
private fun IrBuilderWithScope.wrapperClassReference(classType: KotlinType): IrClassReference {
|
private fun IrBuilderWithScope.wrapperClassReference(classType: KotlinType): IrClassReference {
|
||||||
if (compilerContext.platform.isJvm()) {
|
if (compilerContext.platform.isJvm()) {
|
||||||
// "Byte::class" -> "java.lang.Byte::class"
|
// "Byte::class" -> "java.lang.Byte::class"
|
||||||
|
|||||||
+2
-19
@@ -156,25 +156,8 @@ open class SerializerIrGenerator(
|
|||||||
receiver: IrVariable,
|
receiver: IrVariable,
|
||||||
method: IrFunctionSymbol
|
method: IrFunctionSymbol
|
||||||
) {
|
) {
|
||||||
for (annotationCall in annotations) {
|
copyAnnotationsFrom(annotations).forEach {
|
||||||
val annotationClass = annotationCall.symbol.owner.parentAsClass
|
+irInvoke(irGet(receiver), method, it)
|
||||||
if (!annotationClass.descriptor.isSerialInfoAnnotation) continue
|
|
||||||
|
|
||||||
val createAnnotation = if (compilerContext.platform.isJvm()) {
|
|
||||||
val implClass = serialInfoJvmGenerator.getImplClass(annotationClass)
|
|
||||||
val ctor = implClass.constructors.singleOrNull { it.valueParameters.size == annotationCall.valueArgumentsCount }
|
|
||||||
?: error("No constructor args found for SerialInfo annotation Impl class: ${implClass.render()}")
|
|
||||||
irCall(ctor).apply {
|
|
||||||
for (i in 0 until annotationCall.valueArgumentsCount) {
|
|
||||||
val argument = annotationCall.getValueArgument(i) ?: annotationClass.primaryConstructor!!.valueParameters[i].defaultValue?.expression
|
|
||||||
putValueArgument(i, argument!!.deepCopyWithVariables())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
annotationCall.deepCopyWithVariables()
|
|
||||||
}
|
|
||||||
|
|
||||||
+irInvoke(irGet(receiver), method, createAnnotation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-6
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -40,17 +40,22 @@ fun ClassLoweringPass.runOnFileInOrder(irFile: IrFile) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias SerializationPluginContext = IrPluginContext
|
|
||||||
|
class SerializationPluginContext(baseContext: IrPluginContext, val metadataPlugin: SerializationDescriptorSerializerPlugin?) :
|
||||||
|
IrPluginContext by baseContext {
|
||||||
|
lateinit var serialInfoImplJvmIrGenerator: SerialInfoImplJvmIrGenerator
|
||||||
|
}
|
||||||
|
|
||||||
private class SerializerClassLowering(
|
private class SerializerClassLowering(
|
||||||
val context: SerializationPluginContext,
|
baseContext: IrPluginContext,
|
||||||
val metadataPlugin: SerializationDescriptorSerializerPlugin?
|
metadataPlugin: SerializationDescriptorSerializerPlugin?
|
||||||
) : IrElementTransformerVoid(), ClassLoweringPass {
|
) : IrElementTransformerVoid(), ClassLoweringPass {
|
||||||
private val serialInfoJvmGenerator = SerialInfoImplJvmIrGenerator(context)
|
val context: SerializationPluginContext = SerializationPluginContext(baseContext, metadataPlugin)
|
||||||
|
private val serialInfoJvmGenerator = SerialInfoImplJvmIrGenerator(context).also { context.serialInfoImplJvmIrGenerator = it }
|
||||||
|
|
||||||
override fun lower(irClass: IrClass) {
|
override fun lower(irClass: IrClass) {
|
||||||
SerializableIrGenerator.generate(irClass, context, context.bindingContext)
|
SerializableIrGenerator.generate(irClass, context, context.bindingContext)
|
||||||
SerializerIrGenerator.generate(irClass, context, context.bindingContext, metadataPlugin, serialInfoJvmGenerator)
|
SerializerIrGenerator.generate(irClass, context, context.bindingContext, context.metadataPlugin, serialInfoJvmGenerator)
|
||||||
SerializableCompanionIrGenerator.generate(irClass, context, context.bindingContext)
|
SerializableCompanionIrGenerator.generate(irClass, context, context.bindingContext)
|
||||||
|
|
||||||
if (context.platform.isJvm() && KSerializerDescriptorResolver.isSerialInfoImpl(irClass.descriptor)) {
|
if (context.platform.isJvm() && KSerializerDescriptorResolver.isSerialInfoImpl(irClass.descriptor)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user