diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt index 2636acb610b..7fae634716c 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt @@ -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() { diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt index 437a07eb72c..e85fb79d25a 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt @@ -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() } } -} \ No newline at end of file +} diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt index eb053644e19..0f6c7a55a37 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt @@ -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) } -} \ No newline at end of file +} diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt index c094abd8fba..2302fb81d15 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt @@ -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) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen/Basic.ir.txt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen/Basic.ir.txt index 7abc6c996f2..501d7c624ef 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen/Basic.ir.txt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen/Basic.ir.txt @@ -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) {