Fixes for IR serialization plugin
- Do not insert typeParameters into IrConstructor; - Set correct property symbol to IrField; - Use upper bound as a class descriptor for type parameters. This will allow to get upper bound's KClass in polymorphic serialization. Fixes https://github.com/Kotlin/kotlinx.serialization/issues/490; - Lazily add all serializer functions. Fixes https://github.com/Kotlin/kotlinx.serialization/issues/502; - Don't generate constructor invocation for abstract(sealed) classes deserializer. Such code is incorrect anyway (you can't create an instance of abstract class) and causes problems in devirtualization when exporting Native libraries.
This commit is contained in:
+20
-26
@@ -12,36 +12,23 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||
import org.jetbrains.kotlin.ir.types.makeNotNull
|
||||
import org.jetbrains.kotlin.ir.types.toKotlinType
|
||||
import org.jetbrains.kotlin.ir.types.typeWith
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.polymorphicSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
|
||||
val BackendContext.externalSymbols: ReferenceSymbolTable get() = ir.symbols.externalSymbolTable
|
||||
@@ -96,10 +83,11 @@ interface IrBuilderExtension {
|
||||
) else compilerContext.externalSymbols.referenceConstructor(descriptor).owner
|
||||
c.parent = this
|
||||
c.returnType = descriptor.returnType.toIrType()
|
||||
if (!fromStubs || overwriteValueParameters) c.createParameterDeclarations(receiver = null, overwriteValueParameters = overwriteValueParameters)
|
||||
if (c.typeParameters.isEmpty()) {
|
||||
c.copyTypeParamsFromDescriptor()
|
||||
}
|
||||
if (!fromStubs || overwriteValueParameters) c.createParameterDeclarations(
|
||||
receiver = null,
|
||||
overwriteValueParameters = overwriteValueParameters,
|
||||
copyTypeParameters = false
|
||||
)
|
||||
c.body = compilerContext.createIrBuilder(c.symbol).at(this).irBlockBody(this.startOffset, this.endOffset) { bodyGen(c) }
|
||||
this.addMember(c)
|
||||
}
|
||||
@@ -247,8 +235,10 @@ interface IrBuilderExtension {
|
||||
propertyDescriptor
|
||||
)
|
||||
irProperty.parent = propertyParent
|
||||
irProperty.backingField =
|
||||
generatePropertyBackingField(propertyDescriptor, irProperty).apply { parent = propertyParent }
|
||||
irProperty.backingField = generatePropertyBackingField(propertyDescriptor, irProperty).apply {
|
||||
parent = propertyParent
|
||||
correspondingProperty = irProperty
|
||||
}
|
||||
val fieldSymbol = irProperty.backingField!!.symbol
|
||||
irProperty.getter = propertyDescriptor.getter?.let { generatePropertyAccessor(it, fieldSymbol) }
|
||||
?.apply { parent = propertyParent }
|
||||
@@ -356,7 +346,11 @@ interface IrBuilderExtension {
|
||||
}
|
||||
}
|
||||
|
||||
fun IrFunction.createParameterDeclarations(receiver: IrValueParameter?, overwriteValueParameters: Boolean = false) {
|
||||
fun IrFunction.createParameterDeclarations(
|
||||
receiver: IrValueParameter?,
|
||||
overwriteValueParameters: Boolean = false,
|
||||
copyTypeParameters: Boolean = true
|
||||
) {
|
||||
fun ParameterDescriptor.irValueParameter() = IrValueParameterImpl(
|
||||
this@createParameterDeclarations.startOffset, this@createParameterDeclarations.endOffset,
|
||||
SERIALIZABLE_PLUGIN_ORIGIN,
|
||||
@@ -377,7 +371,7 @@ interface IrBuilderExtension {
|
||||
valueParameters.addAll(descriptor.valueParameters.map { it.irValueParameter() })
|
||||
|
||||
assert(typeParameters.isEmpty())
|
||||
copyTypeParamsFromDescriptor()
|
||||
if (copyTypeParameters) copyTypeParamsFromDescriptor()
|
||||
}
|
||||
|
||||
fun IrFunction.copyTypeParamsFromDescriptor() {
|
||||
|
||||
+12
-11
@@ -9,10 +9,7 @@ import org.jetbrains.kotlin.backend.common.BackendContext
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irIfThen
|
||||
import org.jetbrains.kotlin.backend.common.lower.irThrow
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
@@ -30,7 +27,6 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialType
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.DECODER_CLASS
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENCODER_CLASS
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.KSERIALIZER_NAME
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.STRUCTURE_DECODER_CLASS
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.STRUCTURE_ENCODER_CLASS
|
||||
@@ -153,7 +149,7 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
||||
compilerContext.irBuiltIns.unitType,
|
||||
primaryCtor.symbol
|
||||
).apply {
|
||||
ctor.typeParameters.forEachIndexed { index, irTypeParameter ->
|
||||
irClass.typeParameters.forEachIndexed { index, irTypeParameter ->
|
||||
putTypeArgument(index, irTypeParameter.defaultType)
|
||||
}
|
||||
}
|
||||
@@ -171,7 +167,7 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
||||
|
||||
}
|
||||
|
||||
override fun generateChildSerializersGetter(function: FunctionDescriptor) = irClass.contributeFunction(function) { irFun ->
|
||||
override fun generateChildSerializersGetter(function: FunctionDescriptor) = irClass.contributeFunction(function, fromStubs = true) { irFun ->
|
||||
val allSerializers = serializableProperties.map { requireNotNull(
|
||||
serializerTower(this@SerializerIrGenerator, irFun.dispatchReceiverParameter!!, it)) { "Property ${it.name} must have a serializer" }
|
||||
}
|
||||
@@ -188,7 +184,7 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
||||
fun ClassDescriptor.referenceMethod(methodName: String) =
|
||||
getFuncDesc(methodName).single().let { compilerContext.externalSymbols.referenceFunction(it) }
|
||||
|
||||
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc ->
|
||||
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function, fromStubs = true) { saveFunc ->
|
||||
|
||||
val fieldInitializer: (SerializableProperty) -> IrExpression? =
|
||||
buildInitializersRemapping(serializableIrClass).run { { invoke(it.irField) } }
|
||||
@@ -306,7 +302,7 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
||||
defaultPrimitive to kType
|
||||
}
|
||||
|
||||
override fun generateLoad(function: FunctionDescriptor) = irClass.contributeFunction(function) { loadFunc ->
|
||||
override fun generateLoad(function: FunctionDescriptor) = irClass.contributeFunction(function, fromStubs = true) { loadFunc ->
|
||||
fun irThis(): IrExpression =
|
||||
IrGetValueImpl(startOffset, endOffset, loadFunc.dispatchReceiverParameter!!.symbol)
|
||||
|
||||
@@ -436,7 +432,12 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
||||
compilerContext.externalSymbols.referenceConstructor(serializableDescriptor.unsubstitutedPrimaryConstructor!!)
|
||||
}
|
||||
|
||||
+irReturn(irInvoke(null, ctor, typeArgs, args))
|
||||
// todo: throw UnsupportedOperationException when feature branch with `open SerializerGenerator` (enums) will be merged
|
||||
if (serializableDescriptor.modality != Modality.ABSTRACT && serializableDescriptor.modality != Modality.SEALED) {
|
||||
+irReturn(irInvoke(null, ctor, typeArgs, args))
|
||||
} else {
|
||||
+irThrowNpe()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -449,4 +450,4 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
||||
SerializerIrGenerator(irClass, context, bindingContext).generate()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-6
@@ -29,10 +29,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.AbstractSerialGenerator
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerialTypeInfo
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findAddOnSerializer
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.DECODER_CLASS
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENCODER_CLASS
|
||||
@@ -220,7 +217,7 @@ internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(codeg
|
||||
// use iv == null to check only (do not emit serializer onto stack)
|
||||
internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?,
|
||||
iv: InstructionAdapter?, genericIndex: Int? = null, genericSerializerFieldGetter: (InstructionAdapter.(Int) -> Unit)? = null): Boolean {
|
||||
if (genericIndex != null) {
|
||||
if (maybeSerializer == null && genericIndex != null) {
|
||||
// get field from serializer object
|
||||
iv?.run { genericSerializerFieldGetter?.invoke(this, genericIndex) }
|
||||
return true
|
||||
@@ -406,4 +403,4 @@ fun InstructionAdapter.stackValueDefault(type: Type) {
|
||||
DOUBLE -> dconst(0.0)
|
||||
else -> aconst(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-5
@@ -28,10 +28,9 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationDescriptor
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.polymorphicSerializerId
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.KSERIALIZER_CLASS
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.serialInfoFqName
|
||||
|
||||
internal fun isAllowedToHaveAutoGeneratedSerializerMethods(
|
||||
@@ -97,7 +96,13 @@ internal val Annotations.serialTransient: Boolean
|
||||
|
||||
val KotlinType?.toClassDescriptor: ClassDescriptor?
|
||||
@JvmName("toClassDescriptor")
|
||||
get() = this?.constructor?.declarationDescriptor as? ClassDescriptor
|
||||
get() = this?.constructor?.declarationDescriptor?.let { descriptor ->
|
||||
when(descriptor) {
|
||||
is ClassDescriptor -> descriptor
|
||||
is TypeParameterDescriptor -> descriptor.representativeUpperBound.toClassDescriptor
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
internal val ClassDescriptor.shouldHaveGeneratedMethodsInCompanion: Boolean
|
||||
get() = this.kind == ClassKind.CLASS && annotations.hasAnnotation(SerializationAnnotations.serializableAnnotationFqName)
|
||||
|
||||
+3
-9
@@ -188,10 +188,8 @@ public final class ListOfUsers$$serializer : java/lang/Object, kotlinx/serializa
|
||||
ALOAD (4)
|
||||
ALOAD (3)
|
||||
INVOKEINTERFACE (kotlinx/serialization/CompositeEncoder, endStructure, (Lkotlinx/serialization/SerialDescriptor;)V)
|
||||
LABEL (L2)
|
||||
LINENUMBER (13)
|
||||
RETURN
|
||||
LABEL (L3)
|
||||
LABEL (L2)
|
||||
}
|
||||
|
||||
public void serialize(kotlinx.serialization.Encoder encoder, java.lang.Object obj) {
|
||||
@@ -493,10 +491,8 @@ public final class OptionalUser$$serializer : java/lang/Object, kotlinx/serializ
|
||||
ALOAD (4)
|
||||
ALOAD (3)
|
||||
INVOKEINTERFACE (kotlinx/serialization/CompositeEncoder, endStructure, (Lkotlinx/serialization/SerialDescriptor;)V)
|
||||
LABEL (L7)
|
||||
LINENUMBER (10)
|
||||
RETURN
|
||||
LABEL (L8)
|
||||
LABEL (L7)
|
||||
}
|
||||
|
||||
public void serialize(kotlinx.serialization.Encoder encoder, java.lang.Object obj) {
|
||||
@@ -840,10 +836,8 @@ public final class User$$serializer : java/lang/Object, kotlinx/serialization/in
|
||||
ALOAD (4)
|
||||
ALOAD (3)
|
||||
INVOKEINTERFACE (kotlinx/serialization/CompositeEncoder, endStructure, (Lkotlinx/serialization/SerialDescriptor;)V)
|
||||
LABEL (L2)
|
||||
LINENUMBER (7)
|
||||
RETURN
|
||||
LABEL (L3)
|
||||
LABEL (L2)
|
||||
}
|
||||
|
||||
public void serialize(kotlinx.serialization.Encoder encoder, java.lang.Object obj) {
|
||||
|
||||
Reference in New Issue
Block a user