Support serializable inline classes in IR plugin
as well as standard unsigned types.
This commit is contained in:
+7
-15
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2017 JetBrains s.r.o.
|
* Copyright 2010-2020 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.
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlinx.serialization.compiler.backend.common
|
package org.jetbrains.kotlinx.serialization.compiler.backend.common
|
||||||
@@ -41,9 +30,12 @@ abstract class SerializableCodegen(
|
|||||||
generateSyntheticMethods()
|
generateSyntheticMethods()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inline fun ClassDescriptor.shouldHaveSpecificSyntheticMethods(functionPresenceChecker: () -> FunctionDescriptor?) =
|
||||||
|
!isInline && (isAbstractSerializableClass() || isSealedSerializableClass() || functionPresenceChecker() != null)
|
||||||
|
|
||||||
private fun generateSyntheticInternalConstructor() {
|
private fun generateSyntheticInternalConstructor() {
|
||||||
val serializerDescriptor = serializableDescriptor.classSerializer ?: return
|
val serializerDescriptor = serializableDescriptor.classSerializer ?: return
|
||||||
if (serializableDescriptor.isAbstractSerializableClass() || serializableDescriptor.isSealedSerializableClass() || SerializerCodegen.getSyntheticLoadMember(serializerDescriptor) != null) {
|
if (serializableDescriptor.shouldHaveSpecificSyntheticMethods { SerializerCodegen.getSyntheticLoadMember(serializerDescriptor) }) {
|
||||||
val constrDesc = serializableDescriptor.secondaryConstructors.find(ClassConstructorDescriptor::isSerializationCtor) ?: return
|
val constrDesc = serializableDescriptor.secondaryConstructors.find(ClassConstructorDescriptor::isSerializationCtor) ?: return
|
||||||
generateInternalConstructor(constrDesc)
|
generateInternalConstructor(constrDesc)
|
||||||
}
|
}
|
||||||
@@ -51,7 +43,7 @@ abstract class SerializableCodegen(
|
|||||||
|
|
||||||
private fun generateSyntheticMethods() {
|
private fun generateSyntheticMethods() {
|
||||||
val serializerDescriptor = serializableDescriptor.classSerializer ?: return
|
val serializerDescriptor = serializableDescriptor.classSerializer ?: return
|
||||||
if (serializableDescriptor.isAbstractSerializableClass() || serializableDescriptor.isSealedSerializableClass() || SerializerCodegen.getSyntheticSaveMember(serializerDescriptor) != null) {
|
if (serializableDescriptor.shouldHaveSpecificSyntheticMethods { SerializerCodegen.getSyntheticSaveMember(serializerDescriptor) }) {
|
||||||
val func = KSerializerDescriptorResolver.createWriteSelfFunctionDescriptor(serializableDescriptor)
|
val func = KSerializerDescriptorResolver.createWriteSelfFunctionDescriptor(serializableDescriptor)
|
||||||
generateWriteSelfMethod(func)
|
generateWriteSelfMethod(func)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -168,6 +168,10 @@ fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType
|
|||||||
"F", "kotlin.Float" -> "FloatSerializer"
|
"F", "kotlin.Float" -> "FloatSerializer"
|
||||||
"D", "kotlin.Double" -> "DoubleSerializer"
|
"D", "kotlin.Double" -> "DoubleSerializer"
|
||||||
"C", "kotlin.Char" -> "CharSerializer"
|
"C", "kotlin.Char" -> "CharSerializer"
|
||||||
|
"kotlin.UInt" -> "UIntSerializer"
|
||||||
|
"kotlin.ULong" -> "ULongSerializer"
|
||||||
|
"kotlin.UByte" -> "UByteSerializer"
|
||||||
|
"kotlin.UShort" -> "UShortSerializer"
|
||||||
"kotlin.String" -> "StringSerializer"
|
"kotlin.String" -> "StringSerializer"
|
||||||
"kotlin.Pair" -> "PairSerializer"
|
"kotlin.Pair" -> "PairSerializer"
|
||||||
"kotlin.Triple" -> "TripleSerializer"
|
"kotlin.Triple" -> "TripleSerializer"
|
||||||
|
|||||||
+1
-1
@@ -99,7 +99,7 @@ interface IrBuilderExtension {
|
|||||||
typeHint: IrType? = null
|
typeHint: IrType? = null
|
||||||
): IrMemberAccessExpression<*> {
|
): IrMemberAccessExpression<*> {
|
||||||
assert(callee.isBound) { "Symbol $callee expected to be bound" }
|
assert(callee.isBound) { "Symbol $callee expected to be bound" }
|
||||||
val returnType = typeHint ?: callee.run { owner.returnType }
|
val returnType = typeHint ?: callee.owner.returnType
|
||||||
val call = irCall(callee, type = returnType)
|
val call = irCall(callee, type = returnType)
|
||||||
call.dispatchReceiver = dispatchReceiver
|
call.dispatchReceiver = dispatchReceiver
|
||||||
args.forEachIndexed(call::putValueArgument)
|
args.forEachIndexed(call::putValueArgument)
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@ class SerialInfoImplJvmIrGenerator(
|
|||||||
override val compilerContext: SerializationPluginContext
|
override val compilerContext: SerializationPluginContext
|
||||||
get() = context
|
get() = context
|
||||||
|
|
||||||
private val jvmNameClass = context.referenceClass(DescriptorUtils.JVM_NAME)!!.owner
|
private val jvmNameClass get() = context.referenceClass(DescriptorUtils.JVM_NAME)!!.owner
|
||||||
|
|
||||||
private val implGenerated = mutableSetOf<IrClass>()
|
private val implGenerated = mutableSetOf<IrClass>()
|
||||||
private val annotationToImpl = mutableMapOf<IrClass, IrClass>()
|
private val annotationToImpl = mutableMapOf<IrClass, IrClass>()
|
||||||
|
|||||||
+142
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.ir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.addTypeParameter
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||||
|
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||||
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
|
import org.jetbrains.kotlin.ir.types.defaultType
|
||||||
|
import org.jetbrains.kotlin.ir.types.typeOrNull
|
||||||
|
import org.jetbrains.kotlin.ir.util.constructors
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||||
|
|
||||||
|
private fun SerializationPluginContext.coerceInlineClasses(argument: IrExpression, from: IrType, to: IrType): IrExpression {
|
||||||
|
if (this.platform?.isJvm() != true) return argument.apply { type = to }
|
||||||
|
val unsafeCoerce = irFactory.buildFun {
|
||||||
|
name = Name.special("<unsafe-coerce>")
|
||||||
|
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
|
||||||
|
}.apply {
|
||||||
|
parent = IrExternalPackageFragmentImpl.createEmptyExternalPackageFragment(moduleDescriptor, FqName("kotlin.jvm.internal"))
|
||||||
|
val src = addTypeParameter("T", irBuiltIns.anyNType)
|
||||||
|
val dst = addTypeParameter("R", irBuiltIns.anyNType)
|
||||||
|
addValueParameter("v", src.defaultType)
|
||||||
|
returnType = dst.defaultType
|
||||||
|
}.symbol
|
||||||
|
return IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, to, unsafeCoerce).apply {
|
||||||
|
putTypeArgument(0, from)
|
||||||
|
putTypeArgument(1, to)
|
||||||
|
putValueArgument(0, argument)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SerializerForInlineClassGenerator(
|
||||||
|
irClass: IrClass,
|
||||||
|
compilerContext: SerializationPluginContext,
|
||||||
|
bindingContext: BindingContext,
|
||||||
|
serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
|
||||||
|
) : SerializerIrGenerator(irClass, compilerContext, bindingContext, null, serialInfoJvmGenerator) {
|
||||||
|
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc ->
|
||||||
|
fun irThis(): IrExpression =
|
||||||
|
IrGetValueImpl(startOffset, endOffset, saveFunc.dispatchReceiverParameter!!.symbol)
|
||||||
|
|
||||||
|
val encoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.ENCODER_CLASS)
|
||||||
|
val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol
|
||||||
|
val encodeInline = encoderClass.referenceMethod(CallingConventions.encodeInline)
|
||||||
|
val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol)
|
||||||
|
|
||||||
|
// val inlineEncoder = encoder.encodeInline()
|
||||||
|
val encodeInlineCall: IrExpression = irInvoke(irGet(saveFunc.valueParameters[0]), encodeInline, serialDescGetter)
|
||||||
|
val inlineEncoder = irTemporary(encodeInlineCall, nameHint = "inlineEncoder")
|
||||||
|
|
||||||
|
val property = serializableProperties.first()
|
||||||
|
val value = getFromBox(irGet(saveFunc.valueParameters[1]), property)
|
||||||
|
|
||||||
|
// inlineEncoder.encodeInt/String/SerializableValue
|
||||||
|
val elementCall = formEncodeDecodePropertyCall(irGet(inlineEncoder), saveFunc.dispatchReceiverParameter!!, property, {innerSerial, sti ->
|
||||||
|
val f =
|
||||||
|
encoderClass.referenceMethod("${CallingConventions.encode}${sti.elementMethodPrefix}SerializableValue")
|
||||||
|
f to listOf(
|
||||||
|
innerSerial,
|
||||||
|
value
|
||||||
|
)
|
||||||
|
}, {
|
||||||
|
val f =
|
||||||
|
encoderClass.referenceMethod("${CallingConventions.encode}${it.elementMethodPrefix}")
|
||||||
|
val args = if (it.elementMethodPrefix != "Unit") listOf(value) else emptyList()
|
||||||
|
f to args
|
||||||
|
})
|
||||||
|
|
||||||
|
val actualEncodeCall = irIfNull(compilerContext.irBuiltIns.unitType, irGet(inlineEncoder), irNull(), elementCall)
|
||||||
|
+actualEncodeCall
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateLoad(function: FunctionDescriptor) = irClass.contributeFunction(function) { loadFunc ->
|
||||||
|
fun irThis(): IrExpression =
|
||||||
|
IrGetValueImpl(startOffset, endOffset, loadFunc.dispatchReceiverParameter!!.symbol)
|
||||||
|
|
||||||
|
val decoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.DECODER_CLASS)
|
||||||
|
val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol
|
||||||
|
val decodeInline = decoderClass.referenceMethod(CallingConventions.decodeInline)
|
||||||
|
val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol)
|
||||||
|
|
||||||
|
// val inlineDecoder = decoder.decodeInline()
|
||||||
|
val inlineDecoder: IrExpression = irInvoke(irGet(loadFunc.valueParameters[0]), decodeInline, serialDescGetter)
|
||||||
|
|
||||||
|
val property = serializableProperties.first()
|
||||||
|
val inlinedType = property.type.toIrType()
|
||||||
|
val actualCall = formEncodeDecodePropertyCall(inlineDecoder, loadFunc.dispatchReceiverParameter!!, property, { innerSerial, sti ->
|
||||||
|
decoderClass.referenceMethod( "${CallingConventions.decode}${sti.elementMethodPrefix}SerializableValue") to listOf(innerSerial)
|
||||||
|
}, {
|
||||||
|
decoderClass.referenceMethod("${CallingConventions.decode}${it.elementMethodPrefix}") to listOf()
|
||||||
|
}, returnTypeHint = inlinedType)
|
||||||
|
val value = coerceToBox(actualCall, inlinedType, loadFunc.returnType)
|
||||||
|
+irReturn(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val serialDescImplClass: ClassDescriptor = serializerDescriptor
|
||||||
|
.getClassFromInternalSerializationPackage(SerialEntityNames.SERIAL_DESCRIPTOR_FOR_INLINE)
|
||||||
|
|
||||||
|
override fun IrBlockBodyBuilder.instantiateNewDescriptor(
|
||||||
|
serialDescImplClass: ClassDescriptor,
|
||||||
|
correctThis: IrExpression
|
||||||
|
): IrExpression {
|
||||||
|
val ctor = compilerContext.referenceConstructors(serialDescImplClass.fqNameSafe).single { it.owner.isPrimary }
|
||||||
|
return irInvoke(
|
||||||
|
null, ctor,
|
||||||
|
irString(serialName),
|
||||||
|
correctThis
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Compiler will elide these in corresponding inline class lowerings (when serialize/deserialize functions will be split in two)
|
||||||
|
|
||||||
|
fun IrBlockBodyBuilder.coerceToBox(expression: IrExpression, propertyType: IrType, inlineClassBoxType: IrType): IrExpression {
|
||||||
|
return irInvoke(null, serializableIrClass.constructors.single { it.isPrimary }.symbol, (inlineClassBoxType as IrSimpleType).arguments.map { it.typeOrNull }, listOf(expression))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBlockBodyBuilder.getFromBox(expression: IrExpression, serializableProperty: SerializableProperty): IrExpression {
|
||||||
|
return getProperty(expression, serializableProperty.irProp)
|
||||||
|
}
|
||||||
|
}
|
||||||
+54
-47
@@ -25,8 +25,11 @@ import org.jetbrains.kotlin.platform.jvm.isJvm
|
|||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
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.SerializerCodegen
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo
|
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializerCodegenImpl
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializerForEnumsCodegen
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
|
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||||
@@ -39,6 +42,8 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.UN
|
|||||||
|
|
||||||
object SERIALIZABLE_PLUGIN_ORIGIN : IrDeclarationOriginImpl("SERIALIZER", true)
|
object SERIALIZABLE_PLUGIN_ORIGIN : IrDeclarationOriginImpl("SERIALIZER", true)
|
||||||
|
|
||||||
|
internal typealias FunctionWithArgs = Pair<IrFunctionSymbol, List<IrExpression>>
|
||||||
|
|
||||||
open class SerializerIrGenerator(
|
open class SerializerIrGenerator(
|
||||||
val irClass: IrClass,
|
val irClass: IrClass,
|
||||||
final override val compilerContext: SerializationPluginContext,
|
final override val compilerContext: SerializationPluginContext,
|
||||||
@@ -286,22 +291,7 @@ open class SerializerIrGenerator(
|
|||||||
// internal serialization via virtual calls?
|
// internal serialization via virtual calls?
|
||||||
for ((index, property) in serializableProperties.filter { !it.transient }.withIndex()) {
|
for ((index, property) in serializableProperties.filter { !it.transient }.withIndex()) {
|
||||||
// output.writeXxxElementValue(classDesc, index, value)
|
// output.writeXxxElementValue(classDesc, index, value)
|
||||||
val sti = getSerialTypeInfo(property)
|
val elementCall = formEncodeDecodePropertyCall(irGet(localOutput), saveFunc.dispatchReceiverParameter!!, property, {innerSerial, sti ->
|
||||||
val innerSerial = serializerInstance(
|
|
||||||
this@SerializerIrGenerator,
|
|
||||||
saveFunc.dispatchReceiverParameter!!,
|
|
||||||
sti.serializer,
|
|
||||||
property.module,
|
|
||||||
property.type,
|
|
||||||
genericIndex = property.genericIndex
|
|
||||||
)
|
|
||||||
val (writeFunc, args: List<IrExpression>) = if (innerSerial == null) {
|
|
||||||
val f =
|
|
||||||
kOutputClass.referenceMethod("${CallingConventions.encode}${sti.elementMethodPrefix}${CallingConventions.elementPostfix}")
|
|
||||||
val args: MutableList<IrExpression> = mutableListOf(irGet(localSerialDesc), irInt(index))
|
|
||||||
if (sti.elementMethodPrefix != "Unit") args.add(property.irGet())
|
|
||||||
f to args
|
|
||||||
} else {
|
|
||||||
val f =
|
val f =
|
||||||
kOutputClass.referenceMethod("${CallingConventions.encode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}")
|
kOutputClass.referenceMethod("${CallingConventions.encode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}")
|
||||||
f to listOf(
|
f to listOf(
|
||||||
@@ -310,9 +300,13 @@ open class SerializerIrGenerator(
|
|||||||
innerSerial,
|
innerSerial,
|
||||||
property.irGet()
|
property.irGet()
|
||||||
)
|
)
|
||||||
}
|
}, {
|
||||||
val typeArgs = if (writeFunc.descriptor.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf()
|
val f =
|
||||||
val elementCall = irInvoke(irGet(localOutput), writeFunc, typeArguments = typeArgs, valueArguments = args)
|
kOutputClass.referenceMethod("${CallingConventions.encode}${it.elementMethodPrefix}${CallingConventions.elementPostfix}")
|
||||||
|
val args: MutableList<IrExpression> = mutableListOf(irGet(localSerialDesc), irInt(index))
|
||||||
|
if (it.elementMethodPrefix != "Unit") args.add(property.irGet())
|
||||||
|
f to args
|
||||||
|
})
|
||||||
|
|
||||||
// check for call to .shouldEncodeElementDefault
|
// check for call to .shouldEncodeElementDefault
|
||||||
if (!property.optional || index < ignoreIndexTo) {
|
if (!property.optional || index < ignoreIndexTo) {
|
||||||
@@ -337,6 +331,28 @@ open class SerializerIrGenerator(
|
|||||||
+irInvoke(irGet(localOutput), wEndFunc, irGet(localSerialDesc))
|
+irInvoke(irGet(localOutput), wEndFunc, irGet(localSerialDesc))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected inline 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<IrExpression>) = 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)
|
||||||
|
}
|
||||||
|
|
||||||
// returns null: Any? for boxed types and 0: <number type> for primitives
|
// returns null: Any? for boxed types and 0: <number type> for primitives
|
||||||
private fun IrBuilderWithScope.defaultValueAndType(prop: SerializableProperty): Pair<IrExpression, IrType> {
|
private fun IrBuilderWithScope.defaultValueAndType(prop: SerializableProperty): Pair<IrExpression, IrType> {
|
||||||
val kType = prop.descriptor.returnType!!
|
val kType = prop.descriptor.returnType!!
|
||||||
@@ -403,33 +419,23 @@ open class SerializerIrGenerator(
|
|||||||
val decoderCalls: List<Pair<Int, IrExpression>> =
|
val decoderCalls: List<Pair<Int, IrExpression>> =
|
||||||
serializableProperties.mapIndexed { index, property ->
|
serializableProperties.mapIndexed { index, property ->
|
||||||
val body = irBlock {
|
val body = irBlock {
|
||||||
val sti = getSerialTypeInfo(property)
|
val decodeFuncToCall = formEncodeDecodePropertyCall(localInput.get(), loadFunc.dispatchReceiverParameter!!, property, {innerSerial, sti ->
|
||||||
val innerSerial = serializerInstance(
|
inputClass.referenceMethod(
|
||||||
this@SerializerIrGenerator,
|
"${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}", {it.valueParameters.size == 4}
|
||||||
loadFunc.dispatchReceiverParameter!!,
|
) to listOf(
|
||||||
sti.serializer,
|
localSerialDesc.get(), irInt(index), innerSerial, localProps[index].get()
|
||||||
property.module,
|
)
|
||||||
property.type,
|
}, {
|
||||||
genericIndex = property.genericIndex
|
inputClass.referenceMethod(
|
||||||
)
|
"${CallingConventions.decode}${it.elementMethodPrefix}${CallingConventions.elementPostfix}", {it.valueParameters.size == 2}
|
||||||
val isSerializable = innerSerial != null
|
) to listOf(
|
||||||
val decodeFuncToCall =
|
localSerialDesc.get(), irInt(index)
|
||||||
(if (isSerializable) "${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}"
|
)
|
||||||
else "${CallingConventions.decode}${sti.elementMethodPrefix}${CallingConventions.elementPostfix}")
|
}, returnTypeHint = property.type.toIrType())
|
||||||
.let {
|
|
||||||
inputClass.referenceMethod(it) { it.valueParameters.size == if (isSerializable) 4 else 2 }
|
|
||||||
}
|
|
||||||
val typeArgs =
|
|
||||||
if (decodeFuncToCall.descriptor.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf()
|
|
||||||
val args = mutableListOf<IrExpression>(localSerialDesc.get(), irInt(index))
|
|
||||||
if (isSerializable) {
|
|
||||||
args.add(innerSerial!!)
|
|
||||||
args.add(localProps[index].get())
|
|
||||||
}
|
|
||||||
// local$i = localInput.decode...(...)
|
// local$i = localInput.decode...(...)
|
||||||
+irSet(
|
+irSet(
|
||||||
localProps[index].symbol,
|
localProps[index].symbol,
|
||||||
irInvoke(localInput.get(), decodeFuncToCall, typeArgs, args, returnTypeHint = property.type.toIrType())
|
decodeFuncToCall
|
||||||
)
|
)
|
||||||
// bitMask[i] |= 1 << x
|
// bitMask[i] |= 1 << x
|
||||||
val bitPos = 1 shl (index % 32)
|
val bitPos = 1 shl (index % 32)
|
||||||
@@ -507,11 +513,12 @@ open class SerializerIrGenerator(
|
|||||||
serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
|
serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
|
||||||
) {
|
) {
|
||||||
val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return
|
val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return
|
||||||
if (serializableDesc.isSerializableEnum()) {
|
val generator = when {
|
||||||
SerializerForEnumsGenerator(irClass, context, bindingContext, serialInfoJvmGenerator).generate()
|
serializableDesc.isSerializableEnum() -> SerializerForEnumsGenerator(irClass, context, bindingContext, serialInfoJvmGenerator)
|
||||||
} else {
|
serializableDesc.isInline -> SerializerForInlineClassGenerator(irClass, context, bindingContext, serialInfoJvmGenerator)
|
||||||
SerializerIrGenerator(irClass, context, bindingContext, metadataPlugin, serialInfoJvmGenerator).generate()
|
else -> SerializerIrGenerator(irClass, context, bindingContext, metadataPlugin, serialInfoJvmGenerator)
|
||||||
}
|
}
|
||||||
|
generator.generate()
|
||||||
irClass.patchDeclarationParents(irClass.parent)
|
irClass.patchDeclarationParents(irClass.parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-7
@@ -123,10 +123,10 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (descriptor.isInlineClass()) {
|
// if (descriptor.isInlineClass()) {
|
||||||
trace.reportOnSerializableAnnotation(descriptor, SerializationErrors.INLINE_CLASSES_NOT_SUPPORTED)
|
// trace.reportOnSerializableAnnotation(descriptor, SerializationErrors.INLINE_CLASSES_NOT_SUPPORTED)
|
||||||
return false
|
// return false
|
||||||
}
|
// }
|
||||||
if (!descriptor.hasSerializableAnnotationWithoutArgs) return false
|
if (!descriptor.hasSerializableAnnotationWithoutArgs) return false
|
||||||
|
|
||||||
if (descriptor.serializableAnnotationIsUseless) {
|
if (descriptor.serializableAnnotationIsUseless) {
|
||||||
@@ -258,9 +258,9 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
|
|||||||
) {
|
) {
|
||||||
if (type.genericIndex != null) return // type arguments always have serializer stored in class' field
|
if (type.genericIndex != null) return // type arguments always have serializer stored in class' field
|
||||||
val element = ktType?.typeElement
|
val element = ktType?.typeElement
|
||||||
if (type.isUnsupportedInlineType()) {
|
// if (type.isUnsupportedInlineType()) {
|
||||||
trace.report(SerializationErrors.INLINE_CLASSES_NOT_SUPPORTED.on(element ?: fallbackElement))
|
// trace.report(SerializationErrors.INLINE_CLASSES_NOT_SUPPORTED.on(element ?: fallbackElement))
|
||||||
}
|
// }
|
||||||
val serializer = findTypeSerializerOrContextUnchecked(module, type)
|
val serializer = findTypeSerializerOrContextUnchecked(module, type)
|
||||||
if (serializer != null) {
|
if (serializer != null) {
|
||||||
checkCustomSerializerMatch(module, type, type, element, trace, fallbackElement)
|
checkCustomSerializerMatch(module, type, type, element, trace, fallbackElement)
|
||||||
|
|||||||
+4
-13
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2017 JetBrains s.r.o.
|
* Copyright 2010-2020 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.
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlinx.serialization.compiler.extensions
|
package org.jetbrains.kotlinx.serialization.compiler.extensions
|
||||||
@@ -26,6 +15,7 @@ import org.jetbrains.kotlin.platform.jvm.isJvm
|
|||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.platform
|
import org.jetbrains.kotlin.resolve.descriptorUtil.platform
|
||||||
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
|
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
|
||||||
|
import org.jetbrains.kotlin.resolve.isInlineClass
|
||||||
import org.jetbrains.kotlin.resolve.lazy.LazyClassContext
|
import org.jetbrains.kotlin.resolve.lazy.LazyClassContext
|
||||||
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
|
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
@@ -87,6 +77,7 @@ open class SerializationResolveExtension @JvmOverloads constructor(val metadataP
|
|||||||
if (thisDescriptor.isInternalSerializable) {
|
if (thisDescriptor.isInternalSerializable) {
|
||||||
// do not add synthetic deserialization constructor if .deserialize method is customized
|
// do not add synthetic deserialization constructor if .deserialize method is customized
|
||||||
if (thisDescriptor.hasCompanionObjectAsSerializer && SerializerCodegen.getSyntheticLoadMember(thisDescriptor.companionObjectDescriptor!!) == null) return
|
if (thisDescriptor.hasCompanionObjectAsSerializer && SerializerCodegen.getSyntheticLoadMember(thisDescriptor.companionObjectDescriptor!!) == null) return
|
||||||
|
if (thisDescriptor.isInline) return
|
||||||
result.add(KSerializerDescriptorResolver.createLoadConstructorDescriptor(thisDescriptor, bindingContext, metadataPlugin))
|
result.add(KSerializerDescriptorResolver.createLoadConstructorDescriptor(thisDescriptor, bindingContext, metadataPlugin))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -69,6 +69,7 @@ object SerialEntityNames {
|
|||||||
const val SERIAL_DESCRIPTOR_CLASS = "SerialDescriptor"
|
const val SERIAL_DESCRIPTOR_CLASS = "SerialDescriptor"
|
||||||
const val SERIAL_DESCRIPTOR_CLASS_IMPL = "PluginGeneratedSerialDescriptor"
|
const val SERIAL_DESCRIPTOR_CLASS_IMPL = "PluginGeneratedSerialDescriptor"
|
||||||
const val SERIAL_DESCRIPTOR_FOR_ENUM = "EnumDescriptor"
|
const val SERIAL_DESCRIPTOR_FOR_ENUM = "EnumDescriptor"
|
||||||
|
const val SERIAL_DESCRIPTOR_FOR_INLINE = "InlineClassDescriptor"
|
||||||
|
|
||||||
const val PLUGIN_EXCEPTIONS_FILE = "PluginExceptions"
|
const val PLUGIN_EXCEPTIONS_FILE = "PluginExceptions"
|
||||||
|
|
||||||
@@ -114,6 +115,8 @@ object CallingConventions {
|
|||||||
const val encode = "encode"
|
const val encode = "encode"
|
||||||
const val encodeEnum = "encodeEnum"
|
const val encodeEnum = "encodeEnum"
|
||||||
const val decodeEnum = "decodeEnum"
|
const val decodeEnum = "decodeEnum"
|
||||||
|
const val encodeInline = "encodeInline"
|
||||||
|
const val decodeInline = "decodeInline"
|
||||||
const val decodeElementIndex = "decodeElementIndex"
|
const val decodeElementIndex = "decodeElementIndex"
|
||||||
const val decodeSequentially = "decodeSequentially"
|
const val decodeSequentially = "decodeSequentially"
|
||||||
const val elementPostfix = "Element"
|
const val elementPostfix = "Element"
|
||||||
|
|||||||
+7
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2020 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -8,10 +8,12 @@ package org.jetbrains.kotlinx.serialization.compiler.extensions
|
|||||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||||
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
|
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||||
import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor
|
import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor
|
||||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||||
|
import org.jetbrains.kotlinx.serialization.idea.runIfEnabledIn
|
||||||
import org.jetbrains.kotlinx.serialization.idea.runIfEnabledOn
|
import org.jetbrains.kotlinx.serialization.idea.runIfEnabledOn
|
||||||
|
|
||||||
class SerializationIDECodegenExtension : SerializationCodegenExtension() {
|
class SerializationIDECodegenExtension : SerializationCodegenExtension() {
|
||||||
@@ -31,7 +33,10 @@ class SerializationIDEJsExtension : SerializationJsExtension() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SerializationIDEIrExtension : SerializationLoweringExtension() {
|
class SerializationIDEIrExtension : SerializationLoweringExtension() {
|
||||||
|
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||||
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
|
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
|
||||||
/* No-op – don't enable IR extensions in IDE */
|
runIfEnabledIn(pluginContext.moduleDescriptor) {
|
||||||
|
super.generate(moduleFragment, pluginContext)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+15
-8
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2020 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -7,16 +7,23 @@ package org.jetbrains.kotlinx.serialization.idea
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.idea.core.unwrapModuleSourceInfo
|
import org.jetbrains.kotlin.idea.core.unwrapModuleSourceInfo
|
||||||
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
|
|
||||||
fun <T> getIfEnabledOn(clazz: ClassDescriptor, body: () -> T): T? {
|
private fun isEnabledIn(moduleDescriptor: ModuleDescriptor): Boolean {
|
||||||
val module = clazz.module.getCapability(ModuleInfo.Capability)?.unwrapModuleSourceInfo()?.module ?: return null
|
val module = moduleDescriptor.getCapability(ModuleInfo.Capability)?.unwrapModuleSourceInfo()?.module ?: return false
|
||||||
val facet = KotlinFacet.get(module) ?: return null
|
val facet = KotlinFacet.get(module) ?: return false
|
||||||
val pluginClasspath = facet.configuration.settings.compilerArguments?.pluginClasspaths ?: return null
|
val pluginClasspath = facet.configuration.settings.compilerArguments?.pluginClasspaths ?: return false
|
||||||
if (pluginClasspath.none(KotlinSerializationImportHandler::isPluginJarPath)) return null
|
if (pluginClasspath.none(KotlinSerializationImportHandler::isPluginJarPath)) return false
|
||||||
return body()
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun runIfEnabledOn(clazz: ClassDescriptor, body: () -> Unit) { getIfEnabledOn<Unit>(clazz, body) }
|
fun <T> getIfEnabledOn(clazz: ClassDescriptor, body: () -> T): T? {
|
||||||
|
return if (isEnabledIn(clazz.module)) body() else null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun runIfEnabledOn(clazz: ClassDescriptor, body: () -> Unit) { getIfEnabledOn<Unit>(clazz, body) }
|
||||||
|
|
||||||
|
fun runIfEnabledIn(moduleDescriptor: ModuleDescriptor, block: () -> Unit) { if (isEnabledIn(moduleDescriptor)) block() }
|
||||||
Reference in New Issue
Block a user