[Serialization] Workaround registering static writeSelf method in metadata

`IrGeneratedDeclarationsRegistrar` assumes that all generated functions
  are correct from a Kotlin point of view. But `writeSelf` method on JVM
  is a static method outside any object/companion object

So to properly calculate containing class for this method we should
  generate a dispatch receiver parameter, register the method in metadata,
  and then remove the parameter (to make function static)
This commit is contained in:
Dmitriy Novozhilov
2023-11-28 17:55:34 +02:00
parent 51dcd7c076
commit 139e1223ea
4 changed files with 46 additions and 6 deletions
@@ -15,8 +15,10 @@ import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.isSingleFieldValueClass
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.companionObject
import org.jetbrains.kotlin.ir.util.copyTo
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_CLASS_ID
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
import org.jetbrains.kotlinx.serialization.compiler.resolve.bitMaskSlotCount
@@ -58,17 +60,17 @@ class IrPreGenerator(
modality = Modality.FINAL
origin = SERIALIZATION_PLUGIN_ORIGIN
}
method.apply {
dispatchReceiverParameter = null // function is static
excludeFromJsExport()
}
method.excludeFromJsExport()
val typeParams = irClass.typeParameters.map {
val typeParamsMap = irClass.typeParameters.associateWith {
method.addTypeParameter(
it.name.asString(), compilerContext.irBuiltIns.anyNType
)
}
val typeParamsAsArguments = typeParams.map { it.defaultType }
// Despite this function should be static in bytecode, registerFunctionAsMetadataVisible needs a correct dispatch receiver
// to handle function metadata correctly. This dispatchReceiverParameter will become `null` later.
method.dispatchReceiverParameter = irClass.thisReceiver?.copyTo(method, remapTypeMap = typeParamsMap)
val typeParamsAsArguments = typeParamsMap.values.map { it.defaultType }
// object
method.addValueParameter(
@@ -96,7 +98,14 @@ class IrPreGenerator(
SERIALIZATION_PLUGIN_ORIGIN
)
}
compilerContext.referenceClass(JVM_STATIC_ANNOTATION_CLASS_ID)
?.let { method.annotations += method.createAnnotationCallWithoutArgs(it) }
compilerContext.metadataDeclarationRegistrar.registerFunctionAsMetadataVisible(method)
// Make function static in bytecode (see JvmStaticAnnotationLowering.makeStatic).
method.dispatchReceiverParameter = null
}
private fun preGenerateDeserializationConstructorIfNeeded() {