From 3b789448a32f9b0a9966de0b0af3c1dcf63414fb Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Tue, 2 Mar 2021 19:09:09 +0300 Subject: [PATCH] Support static final write$Self method inside serializable classes on IR to properly serialize class hierarchies with/or private fields. JVM only for now, because Native/JS do not have private fields. Update tests and test data and rebase fix. Unify formEncodeDecodePropertyCall functions. Fix incorrect reference to object in writeSelf, so properties dependent on other properties would be correctly compared with defaults. --- .../backend/common/SerializableCodegen.kt | 19 +- .../backend/common/SerializerCodegen.kt | 4 +- .../compiler/backend/ir/GeneratorHelpers.kt | 109 ++++++++++- .../backend/ir/SerializableIrGenerator.kt | 59 +++++- .../backend/ir/SerializerIrGenerator.kt | 135 ++++++-------- .../SerializationResolveExtension.kt | 19 +- .../resolve/KSerializerDescriptorResolver.kt | 11 +- .../testData/codegen/Basic.ir.txt | 173 ++++++++++++------ .../diagnostics/DuplicateSerialName.kt | 2 +- .../diagnostics/DuplicateSerialName.txt | 3 + .../diagnostics/NoSuitableCtorInParent.kt | 2 +- .../diagnostics/NoSuitableCtorInParent.txt | 1 + .../testData/diagnostics/NonSerializable.kt | 2 +- .../testData/diagnostics/NonSerializable.txt | 3 + .../diagnostics/NullabilityIncompatible.kt | 2 +- .../diagnostics/NullabilityIncompatible.txt | 1 + .../diagnostics/ParamIsNotProperty.kt | 2 +- .../diagnostics/ParamIsNotProperty.txt | 1 + .../testData/diagnostics/SerializableEnums.kt | 2 +- .../diagnostics/SerializableEnums.txt | 1 + .../testData/diagnostics/Transients.kt | 2 +- .../testData/diagnostics/Transients.txt | 1 + 22 files changed, 387 insertions(+), 167 deletions(-) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCodegen.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCodegen.kt index 44d5ab74c30..03f5bdb6109 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCodegen.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCodegen.kt @@ -1,15 +1,16 @@ /* - * Copyright 2010-2020 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. */ package org.jetbrains.kotlinx.serialization.compiler.backend.common -import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.descriptorUtil.secondaryConstructors +import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlinx.serialization.compiler.resolve.* abstract class SerializableCodegen( @@ -37,7 +38,15 @@ abstract class SerializableCodegen( private fun generateSyntheticMethods() { val serializerDescriptor = serializableDescriptor.classSerializer ?: return if (serializableDescriptor.shouldHaveSpecificSyntheticMethods { SerializerCodegen.getSyntheticSaveMember(serializerDescriptor) }) { - val func = KSerializerDescriptorResolver.createWriteSelfFunctionDescriptor(serializableDescriptor) + val func = + serializableDescriptor.unsubstitutedMemberScope.getContributedFunctions( + Name.identifier(SerialEntityNames.WRITE_SELF_NAME.toString()), + NoLookupLocation.FROM_BACKEND + ).singleOrNull { function -> + function.kind == CallableMemberDescriptor.Kind.SYNTHESIZED && + function.modality == Modality.FINAL && + function.returnType?.isUnit() ?: false + } ?: return generateWriteSelfMethod(func) } } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt index 573d30f213c..bd9f278b32a 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2020 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. */ @@ -70,7 +70,7 @@ abstract class SerializerCodegen( serializerDescriptor::checkSerializableClassPropertyResult ) { true } - lateinit var localSerializersFieldsDescriptors: List> + var localSerializersFieldsDescriptors: List> = emptyList() protected set // Can be false if user specified inheritance from KSerializer explicitly 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 26f224ea283..0e49644af92 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 @@ -7,6 +7,7 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.ir import org.jetbrains.kotlin.backend.common.deepCopyWithVariables import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder +import org.jetbrains.kotlin.backend.common.lower.irIfThen import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations @@ -59,9 +60,9 @@ interface IrBuilderExtension { return throwMissedFieldExceptionFunc != null && throwMissedFieldExceptionArrayFunc != null } - fun IrClass.contributeFunction(descriptor: FunctionDescriptor, bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit) { - val f: IrSimpleFunction = searchForDeclaration(descriptor) ?: compilerContext.symbolTable.referenceSimpleFunction(descriptor).owner - // TODO: default parameters + fun IrClass.contributeFunction(descriptor: FunctionDescriptor, ignoreWhenMissing: Boolean = false, bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit) { + val f: IrSimpleFunction = searchForDeclaration(descriptor) + ?: (if (ignoreWhenMissing) return else compilerContext.symbolTable.referenceSimpleFunction(descriptor).owner) f.body = DeclarationIrBuilder(compilerContext, f.symbol, this.startOffset, this.endOffset).irBlockBody( this.startOffset, this.endOffset @@ -489,7 +490,7 @@ interface IrBuilderExtension { ) }.also { f -> generateOverriddenFunctionSymbols(f, compilerContext.symbolTable) - f.createParameterDeclarations(receiver = null) + f.createParameterDeclarations(descriptor) f.returnType = descriptor.returnType!!.toIrType() f.correspondingPropertySymbol = fieldSymbol.owner.correspondingPropertySymbol } @@ -572,7 +573,7 @@ interface IrBuilderExtension { } fun IrFunction.createParameterDeclarations( - receiver: IrValueParameter?, + descriptor: FunctionDescriptor, overwriteValueParameters: Boolean = false, copyTypeParameters: Boolean = true ) { @@ -589,7 +590,7 @@ interface IrBuilderExtension { if (copyTypeParameters) { assert(typeParameters.isEmpty()) - copyTypeParamsFromDescriptor() + copyTypeParamsFromDescriptor(descriptor) } dispatchReceiverParameter = descriptor.dispatchReceiverParameter?.let { irValueParameter(it) } @@ -601,7 +602,7 @@ interface IrBuilderExtension { valueParameters = descriptor.valueParameters.map { irValueParameter(it) } } - fun IrFunction.copyTypeParamsFromDescriptor() { + fun IrFunction.copyTypeParamsFromDescriptor(descriptor: FunctionDescriptor) { val newTypeParameters = descriptor.typeParameters.map { factory.createTypeParameter( startOffset, endOffset, @@ -991,4 +992,98 @@ interface IrBuilderExtension { return superClasses.singleOrNull { it.kind == ClassKind.CLASS } } + fun IrClass.findWriteSelfMethod(): IrSimpleFunction? = + declarations.filter { it is IrSimpleFunction && it.name == SerialEntityNames.WRITE_SELF_NAME && !it.isFakeOverride } + .takeUnless(Collection<*>::isEmpty)?.single() as IrSimpleFunction? + + fun IrBlockBodyBuilder.serializeAllProperties( + generator: AbstractSerialGenerator, + serializableIrClass: IrClass, + serializableProperties: List, + objectToSerialize: IrValueDeclaration, + localOutput: IrValueDeclaration, + localSerialDesc: IrValueDeclaration, + kOutputClass: ClassDescriptor, + ignoreIndexTo: Int, + initializerAdapter: (IrExpressionBody) -> IrExpression, + genericGetter: ((Int, KotlinType) -> IrExpression)? + ) { + + fun SerializableProperty.irGet(): IrExpression { + val ownerType = objectToSerialize.symbol.owner.type + return getProperty( + irGet( + type = ownerType, + variable = objectToSerialize.symbol + ), getIrPropertyFrom(serializableIrClass) + ) + } + + for ((index, property) in serializableProperties.withIndex()) { + if (index < ignoreIndexTo) continue + // output.writeXxxElementValue(classDesc, index, value) + val elementCall = formEncodeDecodePropertyCall( + generator, + irGet(localOutput), + property, { innerSerial, sti -> + val f = + kOutputClass.referenceFunctionSymbol("${CallingConventions.encode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}") + f to listOf( + irGet(localSerialDesc), + irInt(index), + innerSerial, + property.irGet() + ) + }, { + val f = + kOutputClass.referenceFunctionSymbol("${CallingConventions.encode}${it.elementMethodPrefix}${CallingConventions.elementPostfix}") + val args: MutableList = mutableListOf(irGet(localSerialDesc), irInt(index)) + if (it.elementMethodPrefix != "Unit") args.add(property.irGet()) + f to args + }, + genericGetter + ) + + // check for call to .shouldEncodeElementDefault + if (!property.optional) { + // emit call right away + +elementCall + } else { + // emit check: + // if (if (output.shouldEncodeElementDefault(this.descriptor, i)) true else {obj.prop != DEFAULT_VALUE} ) { + // output.encodeIntElement(this.descriptor, i, obj.prop)// block {obj.prop != DEFAULT_VALUE} may contain several statements + val shouldEncodeFunc = kOutputClass.referenceFunctionSymbol(CallingConventions.shouldEncodeDefault) + val partA = irInvoke(irGet(localOutput), shouldEncodeFunc, irGet(localSerialDesc), irInt(index)) + val partB = irNotEquals(property.irGet(), initializerAdapter(property.irField.initializer!!)) + // Ir infrastructure does not have dedicated symbol for ||, so + // `a || b == if (a) true else b`, see org.jetbrains.kotlin.ir.builders.PrimitivesKt.oror + val condition = irIfThenElse(compilerContext.irBuiltIns.booleanType, partA, irTrue(), partB) + +irIfThen(condition, elementCall) + } + } + } + + fun IrBlockBodyBuilder.formEncodeDecodePropertyCall( + enclosingGenerator: AbstractSerialGenerator, + encoder: IrExpression, + property: SerializableProperty, + whenHaveSerializer: (serializer: IrExpression, sti: SerialTypeInfo) -> FunctionWithArgs, + whenDoNot: (sti: SerialTypeInfo) -> FunctionWithArgs, + genericGetter: ((Int, KotlinType) -> IrExpression)? = null, + returnTypeHint: IrType? = null + ): IrExpression { + val sti = enclosingGenerator.getSerialTypeInfo(property) + val innerSerial = serializerInstance( + enclosingGenerator, + sti.serializer, + property.module, + property.type, + property.genericIndex, + genericGetter + ) + val (functionToCall, args: List) = if (innerSerial != null) whenHaveSerializer(innerSerial, sti) else whenDoNot(sti) + val typeArgs = if (functionToCall.descriptor.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf() + return irInvoke(encoder, functionToCall, typeArguments = typeArgs, valueArguments = args, returnTypeHint = returnTypeHint) + } + } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableIrGenerator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableIrGenerator.kt index d65caf3adcd..8cc43c95c2f 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableIrGenerator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableIrGenerator.kt @@ -25,9 +25,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.getOrPutNullable -import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen -import org.jetbrains.kotlinx.serialization.compiler.backend.common.isStaticSerializable -import org.jetbrains.kotlinx.serialization.compiler.backend.common.serialName +import org.jetbrains.kotlinx.serialization.compiler.backend.common.* import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext import org.jetbrains.kotlinx.serialization.compiler.resolve.* @@ -284,7 +282,57 @@ class SerializableIrGenerator( } override fun generateWriteSelfMethod(methodDescriptor: FunctionDescriptor) { - // no-op + irClass.contributeFunction(methodDescriptor, ignoreWhenMissing = true) { writeSelfFunction -> + val objectToSerialize = writeSelfFunction.valueParameters[0] + val localOutput = writeSelfFunction.valueParameters[1] + val localSerialDesc = writeSelfFunction.valueParameters[2] + val serializableProperties = properties.serializableProperties + val kOutputClass = serializableDescriptor.getClassFromSerializationPackage(SerialEntityNames.STRUCTURE_ENCODER_CLASS) + + val propertyByParamReplacer: (ValueParameterDescriptor) -> IrExpression? = + createPropertyByParamReplacer(irClass, serializableProperties, objectToSerialize, bindingContext) + + // Since writeSelf is a static method, we have to replace all references to this in property initializers + val thisSymbol = irClass.thisReceiver!!.symbol + val initializerAdapter: (IrExpressionBody) -> IrExpression = createInitializerAdapter(irClass, propertyByParamReplacer, thisSymbol to { irGet(objectToSerialize) }) + + // Compute offset of properties in superclass + var ignoreIndexTo = -1 + val superClass = irClass.getSuperClassOrAny() + if (superClass.descriptor.isInternalSerializable) { + ignoreIndexTo = bindingContext.serializablePropertiesFor(superClass.descriptor).size + + // call super.writeSelf + val superWriteSelfF = superClass.findWriteSelfMethod() + if (superWriteSelfF != null) { + val args = mutableListOf(irGet(objectToSerialize), irGet(localOutput), irGet(localSerialDesc)) + + val typeArgsForParent = serializableDescriptor.typeConstructor.supertypes.single { it.toClassDescriptor?.isInternalSerializable == true }.arguments + val parentWriteSelfSerializers = typeArgsForParent.map { arg -> + val genericIdx = serializableDescriptor.defaultType.arguments.indexOf(arg).let { if (it == -1) null else it } + val serial = findTypeSerializerOrContext(serializableDescriptor.module, arg.type) + serializerInstance( + this@SerializableIrGenerator, + serial, + serializableDescriptor.module, + arg.type, + genericIdx + ) { it, _ -> + irGet(writeSelfFunction.valueParameters[3 + it]) + }!! + } + +irInvoke(null, superWriteSelfF.symbol, typeArgsForParent.map { it.type.toIrType() }, args + parentWriteSelfSerializers) + } + } + + serializeAllProperties( + this@SerializableIrGenerator, irClass, serializableProperties, + objectToSerialize, localOutput, localSerialDesc, + kOutputClass, ignoreIndexTo, initializerAdapter + ) { it, _ -> + irGet(writeSelfFunction.valueParameters[3 + it]) + } + } } companion object { @@ -298,8 +346,7 @@ class SerializableIrGenerator( if (serializableClass.isInternalSerializable) { SerializableIrGenerator(irClass, context, bindingContext).generate() irClass.patchDeclarationParents(irClass.parent) - } - else if (serializableClass.serializableAnnotationIsUseless) { + } else if (serializableClass.serializableAnnotationIsUseless) { throw CompilationException( "@Serializable annotation on $serializableClass would be ignored because it is impossible to serialize it automatically. " + "Provide serializer manually via e.g. companion object", null, serializableClass.findPsi() 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 7964f76eb6a..924c60018d4 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 @@ -25,9 +25,9 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.util.OperatorNameConventions +import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerialTypeInfo import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen -import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext import org.jetbrains.kotlinx.serialization.compiler.resolve.* @@ -196,13 +196,13 @@ open class SerializerIrGenerator( val thisAsReceiverParameter = irClass.thisReceiver!! ctor.valueParameters.forEachIndexed { index, param -> val localSerial = localSerializersFieldsDescriptors[index].second.backingField!! - +irSetField(generateReceiverExpressionForFieldAccess( - thisAsReceiverParameter.symbol, - localSerializersFieldsDescriptors[index].first - ), localSerial, irGet(param)) + +irSetField( + generateReceiverExpressionForFieldAccess( + thisAsReceiverParameter.symbol, + localSerializersFieldsDescriptors[index].first + ), localSerial, irGet(param) + ) } - - } override fun generateChildSerializersGetter(function: FunctionDescriptor) = irClass.contributeFunction(function) { irFun -> @@ -256,69 +256,44 @@ open class SerializerIrGenerator( val objectToSerialize = saveFunc.valueParameters[1] val localOutput = irTemporary(call, "output") - fun SerializableProperty.irGet(): IrExpression { - val ownerType = objectToSerialize.symbol.owner.type - return getProperty( - irGet( - type = ownerType, - variable = objectToSerialize.symbol - ), getIrPropertyFrom(serializableIrClass) - ) - } + val writeSelfFunction = serializableIrClass.findWriteSelfMethod() - // Ignore comparing to default values of properties from superclass, - // because we do not have access to their fields (and initializers), if superclass is in another module. - // In future, IR analogue of JVM's write$Self should be implemented. - val superClass = serializableIrClass.getSuperClassOrAny().descriptor - val ignoreIndexTo = if (superClass.isInternalSerializable) { - bindingContext.serializablePropertiesFor(superClass).size - } else { - -1 - } - - val propertyByParamReplacer: (ValueParameterDescriptor) -> IrExpression? = - createPropertyByParamReplacer(serializableIrClass, serializableProperties, objectToSerialize, bindingContext) - - val thisSymbol = serializableIrClass.thisReceiver!!.symbol - val initializerAdapter: (IrExpressionBody) -> IrExpression = - createInitializerAdapter(serializableIrClass, propertyByParamReplacer, thisSymbol to { irGet(objectToSerialize) }) - - // internal serialization via virtual calls? - for ((index, property) in serializableProperties.withIndex()) { - // output.writeXxxElementValue(classDesc, index, value) - val elementCall = formEncodeDecodePropertyCall(irGet(localOutput), saveFunc.dispatchReceiverParameter!!, property, {innerSerial, sti -> - val f = - kOutputClass.referenceFunctionSymbol("${CallingConventions.encode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}") - f to listOf( - irGet(localSerialDesc), - irInt(index), - innerSerial, - property.irGet() + if (writeSelfFunction != null) { + // extract Tx from KSerializer list + val typeArgs = + localSerializersFieldsDescriptors.map { (_, ir) -> ir.backingField!!.type.cast().arguments.single().typeOrNull } + val args = mutableListOf(irGet(objectToSerialize), irGet(localOutput), irGet(localSerialDesc)) + args.addAll(localSerializersFieldsDescriptors.map { (_, ir) -> + irGetField( + irGet(saveFunc.dispatchReceiverParameter!!), + ir.backingField!! ) - }, { - val f = - kOutputClass.referenceFunctionSymbol("${CallingConventions.encode}${it.elementMethodPrefix}${CallingConventions.elementPostfix}") - val args: MutableList = mutableListOf(irGet(localSerialDesc), irInt(index)) - if (it.elementMethodPrefix != "Unit") args.add(property.irGet()) - f to args }) - - // check for call to .shouldEncodeElementDefault - if (!property.optional || index < ignoreIndexTo) { - // emit call right away - +elementCall + +irInvoke(null, writeSelfFunction.symbol, typeArgs, args) + } else { + // No write$Self, old behaviour: + // Ignore comparing to default values of properties from superclass, + // because we do not have access to their fields (and initializers), if superclass is in another module. + val superClass = serializableIrClass.getSuperClassOrAny().descriptor + val ignoreIndexTo = if (superClass.isInternalSerializable) { + bindingContext.serializablePropertiesFor(superClass).size } else { - // emit check: - // if ( if (output.shouldEncodeElementDefault(this.descriptor, i)) true else {obj.prop != DEFAULT_VALUE} ) { - // output.encodeIntElement(this.descriptor, i, obj.prop) - // block {obj.prop != DEFAULT_VALUE} may contain several statements - val shouldEncodeFunc = kOutputClass.referenceFunctionSymbol(CallingConventions.shouldEncodeDefault) - val partA = irInvoke(irGet(localOutput), shouldEncodeFunc, irGet(localSerialDesc), irInt(index)) - val partB = irNotEquals(property.irGet(), initializerAdapter(property.irField.initializer!!)) - // Ir infrastructure does not have dedicated symbol for ||, so - // `a || b == if (a) true else b`, see org.jetbrains.kotlin.ir.builders.PrimitivesKt.oror - val condition = irIfThenElse(compilerContext.irBuiltIns.booleanType, partA, irTrue(), partB) - +irIfThen(condition, elementCall) + -1 + } + + val propertyByParamReplacer: (ValueParameterDescriptor) -> IrExpression? = + createPropertyByParamReplacer(serializableIrClass, serializableProperties, objectToSerialize, bindingContext) + + val thisSymbol = serializableIrClass.thisReceiver!!.symbol + val initializerAdapter: (IrExpressionBody) -> IrExpression = + createInitializerAdapter(serializableIrClass, propertyByParamReplacer, thisSymbol to { irGet(objectToSerialize) }) + + serializeAllProperties( + this@SerializerIrGenerator, serializableIrClass, serializableProperties, objectToSerialize, + localOutput, localSerialDesc, kOutputClass, ignoreIndexTo, initializerAdapter + ) { it, _ -> + val (_, ir) = localSerializersFieldsDescriptors[it] + irGetField(irGet(saveFunc.dispatchReceiverParameter!!), ir.backingField!!) } } @@ -327,27 +302,25 @@ open class SerializerIrGenerator( +irInvoke(irGet(localOutput), wEndFunc, irGet(localSerialDesc)) } - protected inline fun IrBlockBodyBuilder.formEncodeDecodePropertyCall( + protected fun IrBlockBodyBuilder.formEncodeDecodePropertyCall( encoder: IrExpression, dispatchReceiver: IrValueParameter, property: SerializableProperty, whenHaveSerializer: (serializer: IrExpression, sti: SerialTypeInfo) -> FunctionWithArgs, whenDoNot: (sti: SerialTypeInfo) -> FunctionWithArgs, returnTypeHint: IrType? = null - ): IrExpression { - val sti = getSerialTypeInfo(property) - val innerSerial = serializerInstance( - this@SerializerIrGenerator, - dispatchReceiver, - sti.serializer, - property.module, - property.type, - genericIndex = property.genericIndex - ) - val (functionToCall, args: List) = if (innerSerial != null) whenHaveSerializer(innerSerial, sti) else whenDoNot(sti) - val typeArgs = if (functionToCall.descriptor.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf() - return irInvoke(encoder, functionToCall, typeArguments = typeArgs, valueArguments = args, returnTypeHint = returnTypeHint) - } + ): IrExpression = formEncodeDecodePropertyCall( + this@SerializerIrGenerator, + encoder, + property, + whenHaveSerializer, + whenDoNot, + { it, _ -> + val (_, ir) = localSerializersFieldsDescriptors[it] + irGetField(irGet(dispatchReceiver), ir.backingField!!) + }, + returnTypeHint + ) // returns null: Any? for boxed types and 0: for primitives private fun IrBuilderWithScope.defaultValueAndType(descriptor: PropertyDescriptor): Pair { diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt index 4a7c308eb7a..84ab5f929b5 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2020 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. */ @@ -39,9 +39,25 @@ open class SerializationResolveExtension @JvmOverloads constructor(val metadataP override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List = when { thisDescriptor.isSerializableObject || thisDescriptor.isCompanionObject && getSerializableClassDescriptorByCompanion(thisDescriptor) != null -> listOf(SerialEntityNames.SERIALIZER_PROVIDER_NAME) + thisDescriptor.isInternalSerializable && thisDescriptor.platform?.isJvm() == true && !hasCustomizedSerializeMethod(thisDescriptor) -> { + // add write$Self, but only if .serialize was not customized in companion. + // It works not only on JVM, but I see no reason to enable it on other platforms — + // private fields there have no access control, and additional function + // only increases compiled code size. + listOf(SerialEntityNames.WRITE_SELF_NAME) + } else -> emptyList() } + private fun hasCustomizedSerializeMethod(serializableClass: ClassDescriptor): Boolean { + // We cannot check whether companion has @Serializer(MyClass::class) annotation due to recursive resolve problems + // (apparently, resolve MyClass type asks for all function names, which leads us to this function again) + // so we rely on less strict check that companion just has non-empty @Serializer annotation. + // Anyway, I doubt that serializable class companion would ever be serializer for _another_ class. + val companion = serializableClass.companionObjectDescriptor ?: return false + return companion.annotations.hasAnnotation(SerializationAnnotations.serializerAnnotationFqName) + } + override fun generateSyntheticClasses( thisDescriptor: ClassDescriptor, name: Name, @@ -91,6 +107,7 @@ open class SerializationResolveExtension @JvmOverloads constructor(val metadataP ) { KSerializerDescriptorResolver.generateSerializerMethods(thisDescriptor, fromSupertypes, name, result) KSerializerDescriptorResolver.generateCompanionObjectMethods(thisDescriptor, name, result) + KSerializerDescriptorResolver.generateSerializableClassMethods(thisDescriptor, name, result) } override fun generateSyntheticProperties( diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt index 47698a6facf..798481c08f9 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2020 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. */ @@ -217,6 +217,11 @@ object KSerializerDescriptorResolver { } } + fun generateSerializableClassMethods(thisDescriptor: ClassDescriptor, name: Name, result: MutableCollection) { + if (thisDescriptor.isInternalSerializable && name == SerialEntityNames.WRITE_SELF_NAME) + result.add(createWriteSelfFunctionDescriptor(thisDescriptor)) + } + private fun createSerializableClassPropertyDescriptor( companionDescriptor: ClassDescriptor, classDescriptor: ClassDescriptor @@ -490,7 +495,7 @@ object KSerializerDescriptorResolver { if (KotlinBuiltIns.isPrimitiveType(this)) this else this.makeNullable() - fun createWriteSelfFunctionDescriptor(thisClass: ClassDescriptor): FunctionDescriptor { + fun createWriteSelfFunctionDescriptor(thisClass: ClassDescriptor): SimpleFunctionDescriptor { val jvmStaticClass = thisClass.module.findClassAcrossModuleDependencies( ClassId( FqName("kotlin.jvm"), @@ -570,7 +575,7 @@ object KSerializerDescriptorResolver { f.initialize( null, - thisClass.thisAsReceiverParameter, + null, typeArgs, args, returnType, 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 67e8d9c59a5..e260436683a 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 @@ -182,18 +182,10 @@ public final class ListOfUsers$$serializer : java/lang/Object, kotlinx/serializa ALOAD (3) INVOKEINTERFACE (kotlinx/serialization/encoding/Encoder, beginStructure, (Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/encoding/CompositeEncoder;) ASTORE (4) + ALOAD (2) ALOAD (4) ALOAD (3) - ICONST_0 - NEW - DUP - GETSTATIC (INSTANCE, LUser$$serializer;) - CHECKCAST - INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, , (Lkotlinx/serialization/KSerializer;)V) - CHECKCAST - ALOAD (2) - INVOKEVIRTUAL (ListOfUsers, getList, ()Ljava/util/List;) - INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeSerializableElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V) + INVOKESTATIC (ListOfUsers, write$Self, (LListOfUsers;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V) ALOAD (4) ALOAD (3) INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, endStructure, (Lkotlinx/serialization/descriptors/SerialDescriptor;)V) @@ -293,6 +285,35 @@ public final class ListOfUsers : java/lang/Object { } public final java.util.List getList() + + public final static void write$Self(ListOfUsers self, kotlinx.serialization.encoding.CompositeEncoder output, kotlinx.serialization.descriptors.SerialDescriptor serialDesc) { + LABEL (L0) + ALOAD (0) + LDC (self) + INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V) + ALOAD (1) + LDC (output) + INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V) + ALOAD (2) + LDC (serialDesc) + INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V) + LABEL (L1) + LINENUMBER (12) + ALOAD (1) + ALOAD (2) + ICONST_0 + NEW + DUP + GETSTATIC (INSTANCE, LUser$$serializer;) + CHECKCAST + INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, , (Lkotlinx/serialization/KSerializer;)V) + CHECKCAST + ALOAD (0) + GETFIELD (list, Ljava/util/List;) + INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeSerializableElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V) + RETURN + LABEL (L2) + } } public final class OptionalUser$$serializer : java/lang/Object, kotlinx/serialization/internal/GeneratedSerializer { @@ -467,47 +488,15 @@ public final class OptionalUser$$serializer : java/lang/Object, kotlinx/serializ ALOAD (3) INVOKEINTERFACE (kotlinx/serialization/encoding/Encoder, beginStructure, (Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/encoding/CompositeEncoder;) ASTORE (4) + ALOAD (2) ALOAD (4) ALOAD (3) - ICONST_0 - INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, shouldEncodeElementDefault, (Lkotlinx/serialization/descriptors/SerialDescriptor;I)Z) - IFEQ (L2) - ICONST_1 - GOTO (L3) - LABEL (L2) - ALOAD (2) - INVOKEVIRTUAL (OptionalUser, getUser, ()LUser;) - LABEL (L4) - LINENUMBER (10) - NEW - DUP - LDC () - LDC () - INVOKESPECIAL (User, , (Ljava/lang/String;Ljava/lang/String;)V) - INVOKESTATIC (kotlin/jvm/internal/Intrinsics, areEqual, (Ljava/lang/Object;Ljava/lang/Object;)Z) - IFNE (L5) - ICONST_1 - GOTO (L3) - LABEL (L5) - ICONST_0 - LABEL (L3) - IFEQ (L6) - LABEL (L7) - LINENUMBER (9) - ALOAD (4) - ALOAD (3) - ICONST_0 - GETSTATIC (INSTANCE, LUser$$serializer;) - CHECKCAST - ALOAD (2) - INVOKEVIRTUAL (OptionalUser, getUser, ()LUser;) - INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeSerializableElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V) - LABEL (L6) + INVOKESTATIC (OptionalUser, write$Self, (LOptionalUser;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V) ALOAD (4) ALOAD (3) INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, endStructure, (Lkotlinx/serialization/descriptors/SerialDescriptor;)V) RETURN - LABEL (L8) + LABEL (L2) } public void serialize(kotlinx.serialization.encoding.Encoder encoder, java.lang.Object value) { @@ -650,6 +639,59 @@ public final class OptionalUser : java/lang/Object { } public final User getUser() + + public final static void write$Self(OptionalUser self, kotlinx.serialization.encoding.CompositeEncoder output, kotlinx.serialization.descriptors.SerialDescriptor serialDesc) { + LABEL (L0) + ALOAD (0) + LDC (self) + INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V) + ALOAD (1) + LDC (output) + INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V) + ALOAD (2) + LDC (serialDesc) + INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V) + LABEL (L1) + LINENUMBER (9) + ALOAD (1) + ALOAD (2) + ICONST_0 + INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, shouldEncodeElementDefault, (Lkotlinx/serialization/descriptors/SerialDescriptor;I)Z) + IFEQ (L2) + ICONST_1 + GOTO (L3) + LABEL (L2) + ALOAD (0) + GETFIELD (user, LUser;) + LABEL (L4) + LINENUMBER (10) + NEW + DUP + LDC () + LDC () + INVOKESPECIAL (User, , (Ljava/lang/String;Ljava/lang/String;)V) + INVOKESTATIC (kotlin/jvm/internal/Intrinsics, areEqual, (Ljava/lang/Object;Ljava/lang/Object;)Z) + IFNE (L5) + ICONST_1 + GOTO (L3) + LABEL (L5) + ICONST_0 + LABEL (L3) + IFEQ (L6) + LABEL (L7) + LINENUMBER (9) + ALOAD (1) + ALOAD (2) + ICONST_0 + GETSTATIC (INSTANCE, LUser$$serializer;) + CHECKCAST + ALOAD (0) + GETFIELD (user, LUser;) + INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeSerializableElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V) + LABEL (L6) + RETURN + LABEL (L8) + } } public final class User$$serializer : java/lang/Object, kotlinx/serialization/internal/GeneratedSerializer { @@ -849,18 +891,10 @@ public final class User$$serializer : java/lang/Object, kotlinx/serialization/in ALOAD (3) INVOKEINTERFACE (kotlinx/serialization/encoding/Encoder, beginStructure, (Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/encoding/CompositeEncoder;) ASTORE (4) + ALOAD (2) ALOAD (4) ALOAD (3) - ICONST_0 - ALOAD (2) - INVOKEVIRTUAL (User, getFirstName, ()Ljava/lang/String;) - INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeStringElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILjava/lang/String;)V) - ALOAD (4) - ALOAD (3) - ICONST_1 - ALOAD (2) - INVOKEVIRTUAL (User, getLastName, ()Ljava/lang/String;) - INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeStringElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILjava/lang/String;)V) + INVOKESTATIC (User, write$Self, (LUser;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V) ALOAD (4) ALOAD (3) INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, endStructure, (Lkotlinx/serialization/descriptors/SerialDescriptor;)V) @@ -973,4 +1007,33 @@ public final class User : java/lang/Object { public final java.lang.String getFirstName() public final java.lang.String getLastName() + + public final static void write$Self(User self, kotlinx.serialization.encoding.CompositeEncoder output, kotlinx.serialization.descriptors.SerialDescriptor serialDesc) { + LABEL (L0) + ALOAD (0) + LDC (self) + INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V) + ALOAD (1) + LDC (output) + INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V) + ALOAD (2) + LDC (serialDesc) + INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V) + LABEL (L1) + LINENUMBER (6) + ALOAD (1) + ALOAD (2) + ICONST_0 + ALOAD (0) + GETFIELD (firstName, Ljava/lang/String;) + INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeStringElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILjava/lang/String;)V) + ALOAD (1) + ALOAD (2) + ICONST_1 + ALOAD (0) + GETFIELD (lastName, Ljava/lang/String;) + INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeStringElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILjava/lang/String;)V) + RETURN + LABEL (L2) + } } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/DuplicateSerialName.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/DuplicateSerialName.kt index 7690dec6678..e2fcbc9d74e 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/DuplicateSerialName.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/DuplicateSerialName.kt @@ -1,5 +1,5 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE - +// WITH_RUNTIME // FILE: test.kt import kotlinx.serialization.* diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/DuplicateSerialName.txt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/DuplicateSerialName.txt index ae4b5da28e0..2e220f82da2 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/DuplicateSerialName.txt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/DuplicateSerialName.txt @@ -7,6 +7,8 @@ package public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + @kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: Derived, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit + @kotlin.jvm.JvmStatic public final override /*1*/ /*fake_override*/ fun `write$Self`(/*0*/ self: Parent, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit @kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer { private constructor `$serializer`() @@ -36,6 +38,7 @@ package public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + @kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: Parent, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit @kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer { private constructor `$serializer`() diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NoSuitableCtorInParent.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NoSuitableCtorInParent.kt index bf721ed6639..7e8a4e795ad 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NoSuitableCtorInParent.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NoSuitableCtorInParent.kt @@ -1,5 +1,5 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE - +// WITH_RUNTIME // FILE: test.kt import kotlinx.serialization.* diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NoSuitableCtorInParent.txt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NoSuitableCtorInParent.txt index 1c4700e479b..257be147901 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NoSuitableCtorInParent.txt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NoSuitableCtorInParent.txt @@ -8,6 +8,7 @@ package public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + @kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: Derived, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit @kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer { private constructor `$serializer`() diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NonSerializable.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NonSerializable.kt index 4f14242cf2f..6752a185364 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NonSerializable.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NonSerializable.kt @@ -1,5 +1,5 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE - +// WITH_RUNTIME // FILE: test.kt import kotlinx.serialization.* diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NonSerializable.txt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NonSerializable.txt index 0dfb58e9182..8abd459cf5e 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NonSerializable.txt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NonSerializable.txt @@ -7,6 +7,7 @@ package public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + @kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: Basic, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit @kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer { private constructor `$serializer`() @@ -36,6 +37,7 @@ package public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + @kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: Inside, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit @kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer { private constructor `$serializer`() @@ -72,6 +74,7 @@ public final class NonSerializable { public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + @kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: WithImplicitType, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit @kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer { private constructor `$serializer`() diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NullabilityIncompatible.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NullabilityIncompatible.kt index b7f78a94933..d76d8bf3088 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NullabilityIncompatible.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NullabilityIncompatible.kt @@ -1,5 +1,5 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE - +// WITH_RUNTIME // FILE: test.kt import kotlinx.serialization.* import kotlinx.serialization.descriptors.* diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NullabilityIncompatible.txt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NullabilityIncompatible.txt index 8dcf020f79e..e3280bb5d5b 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NullabilityIncompatible.txt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NullabilityIncompatible.txt @@ -7,6 +7,7 @@ package public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + @kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: Foo, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit @kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer { private constructor `$serializer`() diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/ParamIsNotProperty.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/ParamIsNotProperty.kt index bb14e4124af..e7a7deb9c78 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/ParamIsNotProperty.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/ParamIsNotProperty.kt @@ -1,5 +1,5 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE - +// WITH_RUNTIME // FILE: test.kt import kotlinx.serialization.* diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/ParamIsNotProperty.txt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/ParamIsNotProperty.txt index d01dabbafa9..0d5dcf807e7 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/ParamIsNotProperty.txt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/ParamIsNotProperty.txt @@ -7,6 +7,7 @@ package public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + @kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: Test, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit @kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer { private constructor `$serializer`() diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/SerializableEnums.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/SerializableEnums.kt index c36d606989e..d5c71f19500 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/SerializableEnums.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/SerializableEnums.kt @@ -1,5 +1,5 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE - +// WITH_RUNTIME // FILE: test.kt import kotlinx.serialization.* import kotlinx.serialization.encoding.* diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/SerializableEnums.txt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/SerializableEnums.txt index 1e4d711f84a..8f427ca065c 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/SerializableEnums.txt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/SerializableEnums.txt @@ -23,6 +23,7 @@ public object EnumSerializer : kotlinx.serialization.KSerializer { private constructor `$serializer`() diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/Transients.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/Transients.kt index 4a8eb2139d7..c4833e69b3c 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/Transients.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/Transients.kt @@ -1,5 +1,5 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE - +// WITH_RUNTIME // FILE: test.kt import kotlinx.serialization.* diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/Transients.txt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/Transients.txt index 4cd20063cf8..86d03badc42 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/Transients.txt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/Transients.txt @@ -11,6 +11,7 @@ package public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String + @kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: WithTransients, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit @kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer { private constructor `$serializer`()