Added support of external serializers to the FIR

Co-authored-by: Leonid Startsev <leonid.startsev@jetbrains.com>
Merge-request: KT-MR-7334
Merged-by: Sergey Shanshin <Sergey.Shanshin@jetbrains.com>
This commit is contained in:
Sergey.Shanshin
2022-10-13 15:25:39 +00:00
committed by Space Team
parent 817afcd4af
commit 5a1c2c56bd
28 changed files with 629 additions and 101 deletions
@@ -15,12 +15,9 @@ import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.companionObject
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
import org.jetbrains.kotlinx.serialization.compiler.resolve.bitMaskSlotCount
import org.jetbrains.kotlinx.serialization.compiler.resolve.hasCompanionObjectAsSerializer
/**
* Generates only specific declarations, but NOT their bodies.
@@ -43,7 +40,12 @@ class IrPreGenerator(
private fun preGenerateWriteSelfMethodIfNeeded() {
if (!irClass.isInternalSerializable) return
val serializerDescriptor = irClass.classSerializer(compilerContext)?.owner ?: return
if (!irClass.shouldHaveSpecificSyntheticMethods { serializerDescriptor.findPluginGeneratedMethod(SerialEntityNames.SAVE) }) return
if (!irClass.shouldHaveSpecificSyntheticMethods {
serializerDescriptor.findPluginGeneratedMethod(
SerialEntityNames.SAVE,
compilerContext.afterK2
)
}) return
if (irClass.findWriteSelfMethod() != null) return
val method = irClass.addFunction {
name = SerialEntityNames.WRITE_SELF_NAME
@@ -95,7 +97,7 @@ class IrPreGenerator(
if (!irClass.isInternalSerializable) return
// do not add synthetic deserialization constructor if .deserialize method is customized
if (irClass.hasCompanionObjectAsSerializer && irClass.companionObject()
?.findPluginGeneratedMethod(SerialEntityNames.LOAD) == null
?.findPluginGeneratedMethod(SerialEntityNames.LOAD, compilerContext.afterK2) == null
) return
if (irClass.isValue) return
if (irClass.findSerializableSyntheticConstructor() != null) return
@@ -133,4 +135,4 @@ class IrPreGenerator(
}
}
}
}
@@ -57,9 +57,9 @@ internal val IrClass.isInternallySerializableObject: Boolean
get() = kind == ClassKind.OBJECT && hasSerializableOrMetaAnnotationWithoutArgs()
internal fun IrClass.findPluginGeneratedMethod(name: String): IrSimpleFunction? {
internal fun IrClass.findPluginGeneratedMethod(name: String, afterK2: Boolean): IrSimpleFunction? {
return this.functions.find {
it.name.asString() == name && it.isFromPlugin()
it.name.asString() == name && it.isFromPlugin(afterK2)
}
}
@@ -147,8 +147,13 @@ fun IrClass.getSuperClassNotAny(): IrClass? {
}
@OptIn(ObsoleteDescriptorBasedAPI::class)
internal fun IrDeclaration.isFromPlugin(): Boolean =
this.origin == IrDeclarationOrigin.GeneratedByPlugin(SerializationPluginKey) || (this.descriptor as? CallableMemberDescriptor)?.kind == CallableMemberDescriptor.Kind.SYNTHESIZED // old FE doesn't specify origin
internal fun IrDeclaration.isFromPlugin(afterK2: Boolean): Boolean =
if (afterK2) {
this.origin == IrDeclarationOrigin.GeneratedByPlugin(SerializationPluginKey)
} else {
// old FE doesn't specify custom origin
(this.descriptor as? CallableMemberDescriptor)?.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
}
internal fun IrConstructor.isSerializationCtor(): Boolean {
/*kind == CallableMemberDescriptor.Kind.SYNTHESIZED does not work because DeserializedClassConstructorDescriptor loses its kind*/
@@ -248,4 +253,4 @@ fun IrSimpleType.argumentTypesOrUpperBounds(): List<IrType> {
}
internal inline fun IrClass.shouldHaveSpecificSyntheticMethods(functionPresenceChecker: () -> IrSimpleFunction?) =
!isValue && (isAbstractOrSealedSerializableClass || functionPresenceChecker() != null)
!isValue && (isAbstractOrSealedSerializableClass || functionPresenceChecker() != null)
@@ -157,7 +157,7 @@ class SerializableCompanionIrGenerator(
it.valueParameters.size == 1
&& it.valueParameters.first().isVararg
&& it.returnType.isKSerializer()
&& it.isFromPlugin()
&& it.isFromPlugin(compilerContext.afterK2)
}?.let { return it }
val kSerializerStarType = compilerContext.getClassFromRuntime(SerialEntityNames.KSERIALIZER_CLASS).starProjectedType
val f = irClass.addFunction(
@@ -359,7 +359,7 @@ class SerializableIrGenerator(
private fun generateSyntheticInternalConstructor() {
val serializerDescriptor = irClass.classSerializer(compilerContext)?.owner ?: return
if (irClass.shouldHaveSpecificSyntheticMethods { serializerDescriptor.findPluginGeneratedMethod(LOAD) }) {
if (irClass.shouldHaveSpecificSyntheticMethods { serializerDescriptor.findPluginGeneratedMethod(LOAD, compilerContext.afterK2) }) {
val constrDesc = irClass.constructors.find(IrConstructor::isSerializationCtor) ?: return
generateInternalConstructor(constrDesc)
}
@@ -367,7 +367,7 @@ class SerializableIrGenerator(
private fun generateSyntheticMethods() {
val serializerDescriptor = irClass.classSerializer(compilerContext)?.owner ?: return
if (irClass.shouldHaveSpecificSyntheticMethods { serializerDescriptor.findPluginGeneratedMethod(SAVE) }) {
if (irClass.shouldHaveSpecificSyntheticMethods { serializerDescriptor.findPluginGeneratedMethod(SAVE, compilerContext.afterK2) }) {
val func = irClass.findWriteSelfMethod() ?: return
func.origin = SERIALIZATION_PLUGIN_ORIGIN
generateWriteSelfMethod(func)
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
@@ -63,7 +62,7 @@ open class SerializerIrGenerator(
protected val generatedSerialDescPropertyDescriptor = getProperty(
SerialEntityNames.SERIAL_DESC_FIELD,
{ true }
)?.takeIf { it.isFromPlugin() }
)?.takeIf { it.isFromPlugin(compilerContext.afterK2) }
protected val anySerialDescProperty = getProperty(
SerialEntityNames.SERIAL_DESC_FIELD,
@@ -592,15 +591,17 @@ open class SerializerIrGenerator(
val prop = generatedSerialDescPropertyDescriptor?.let { generateSerializableClassProperty(it); true } ?: false
if (prop)
generateSerialDesc()
val save = irClass.findPluginGeneratedMethod(SAVE)?.let { generateSave(it); true } ?: false
val load = irClass.findPluginGeneratedMethod(LOAD)?.let { generateLoad(it); true } ?: false
irClass.findPluginGeneratedMethod(SerialEntityNames.CHILD_SERIALIZERS_GETTER.identifier)?.let { generateChildSerializersGetter(it) }
irClass.findPluginGeneratedMethod(SerialEntityNames.TYPE_PARAMS_SERIALIZERS_GETTER.identifier)
val withFir = compilerContext.afterK2
val save = irClass.findPluginGeneratedMethod(SAVE, withFir)?.let { generateSave(it); true } ?: false
val load = irClass.findPluginGeneratedMethod(LOAD, withFir)?.let { generateLoad(it); true } ?: false
irClass.findPluginGeneratedMethod(SerialEntityNames.CHILD_SERIALIZERS_GETTER.identifier, withFir)
?.let { generateChildSerializersGetter(it) }
irClass.findPluginGeneratedMethod(SerialEntityNames.TYPE_PARAMS_SERIALIZERS_GETTER.identifier, withFir)
?.let { generateTypeParamsSerializersGetter(it) }
if (!prop && (save || load))
generateSerialDesc()
if (serializableIrClass.typeParameters.isNotEmpty()) {
findSerializerConstructorForTypeArgumentsSerializers(irClass)?.takeIf { it.owner.isFromPlugin() }?.let {
findSerializerConstructorForTypeArgumentsSerializers(irClass)?.takeIf { it.owner.isFromPlugin(withFir) }?.let {
generateGenericFieldsAndConstructor(it.owner)
}
}
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.CompilationException
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.common.extensions.IrIntrinsicExtension
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContextImpl
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.fileParent