Refactor most of the new code, split huge GeneratorHelpers.kt appropriately
This commit is contained in:
+4
-44
@@ -5,19 +5,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlinx.serialization.compiler.backend.common
|
package org.jetbrains.kotlinx.serialization.compiler.backend.common
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.fileParent
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrVararg
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
|
||||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
|
||||||
import org.jetbrains.kotlin.ir.types.isNullable
|
|
||||||
import org.jetbrains.kotlin.ir.types.typeOrNull
|
|
||||||
import org.jetbrains.kotlin.ir.util.findAnnotation
|
|
||||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
@@ -31,46 +21,15 @@ import org.jetbrains.kotlin.types.typeUtil.supertypes
|
|||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.isKSerializer
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.isKSerializer
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.toClassDescriptor
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.toClassDescriptor
|
||||||
abstract class AbstractIrGenerator(private val currentClass: IrClass) {
|
|
||||||
private fun getClassListFromFileAnnotation(annotationFqName: FqName): List<IrClassSymbol> {
|
|
||||||
val annotation = currentClass.fileParent.annotations.findAnnotation(annotationFqName) ?: return emptyList()
|
|
||||||
val vararg = annotation.getValueArgument(0) as? IrVararg ?: return emptyList()
|
|
||||||
return vararg.elements
|
|
||||||
.mapNotNull { (it as? IrClassReference)?.symbol as? IrClassSymbol}
|
|
||||||
}
|
|
||||||
|
|
||||||
val contextualKClassListInCurrentFile: Set<IrClassSymbol> by lazy {
|
|
||||||
getClassListFromFileAnnotation(
|
|
||||||
SerializationAnnotations.contextualFqName,
|
|
||||||
).plus(
|
|
||||||
getClassListFromFileAnnotation(
|
|
||||||
SerializationAnnotations.contextualOnFileFqName,
|
|
||||||
)
|
|
||||||
).toSet()
|
|
||||||
}
|
|
||||||
|
|
||||||
val additionalSerializersInScopeOfCurrentFile: Map<Pair<IrClassSymbol, Boolean>, IrClassSymbol> by lazy {
|
|
||||||
getClassListFromFileAnnotation(SerializationAnnotations.additionalSerializersFqName,)
|
|
||||||
.associateBy(
|
|
||||||
{ serializerSymbol ->
|
|
||||||
val kotlinType = (serializerSymbol.owner.superTypes.find(::isKSerializer) as? IrSimpleType)?.arguments?.firstOrNull()?.typeOrNull
|
|
||||||
val classSymbol = kotlinType?.classOrNull
|
|
||||||
?: throw AssertionError("Argument for ${SerializationAnnotations.additionalSerializersFqName} does not implement KSerializer or does not provide serializer for concrete type")
|
|
||||||
classSymbol to kotlinType.isNullable()
|
|
||||||
},
|
|
||||||
{ it }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class AbstractSerialGenerator(val bindingContext: BindingContext?, val currentDeclaration: ClassDescriptor) {
|
abstract class AbstractSerialGenerator(val bindingContext: BindingContext?, val currentDeclaration: ClassDescriptor) {
|
||||||
|
|
||||||
private fun getKClassListFromFileAnnotation(annotationFqName: FqName, declarationInFile: DeclarationDescriptor): List<KotlinType> {
|
private fun getKClassListFromFileAnnotation(annotationFqName: FqName, declarationInFile: DeclarationDescriptor): List<KotlinType> {
|
||||||
if (bindingContext == null) return emptyList() // TODO: support @UseSerializers in FIR
|
if (bindingContext == null) return emptyList()
|
||||||
val annotation = AnnotationsUtils
|
val annotation = AnnotationsUtils
|
||||||
.getContainingFileAnnotations(bindingContext, declarationInFile)
|
.getContainingFileAnnotations(bindingContext, declarationInFile)
|
||||||
.find { it.fqName == annotationFqName }
|
.find { it.fqName == annotationFqName }
|
||||||
?: return emptyList()
|
?: return emptyList()
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val typeList: List<KClassValue> = annotation.firstArgument()?.value as? List<KClassValue> ?: return emptyList()
|
val typeList: List<KClassValue> = annotation.firstArgument()?.value as? List<KClassValue> ?: return emptyList()
|
||||||
return typeList.map { it.getArgumentType(declarationInFile.module) }
|
return typeList.map { it.getArgumentType(declarationInFile.module) }
|
||||||
@@ -102,5 +61,6 @@ abstract class AbstractSerialGenerator(val bindingContext: BindingContext?, val
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected fun ClassDescriptor.getFuncDesc(funcName: String): Sequence<FunctionDescriptor> =
|
protected fun ClassDescriptor.getFuncDesc(funcName: String): Sequence<FunctionDescriptor> =
|
||||||
unsubstitutedMemberScope.getDescriptorsFiltered { it == Name.identifier(funcName) }.asSequence().filterIsInstance<FunctionDescriptor>()
|
unsubstitutedMemberScope.getDescriptorsFiltered { it == Name.identifier(funcName) }.asSequence()
|
||||||
|
.filterIsInstance<FunctionDescriptor>()
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -8,7 +8,6 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.common
|
|||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||||
|
|||||||
+4
-63
@@ -10,11 +10,6 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|||||||
import org.jetbrains.kotlin.codegen.CompilationException
|
import org.jetbrains.kotlin.codegen.CompilationException
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
|
||||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
|
||||||
import org.jetbrains.kotlin.ir.util.isTypeParameter
|
|
||||||
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
||||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
@@ -26,32 +21,17 @@ import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
|||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.*
|
import org.jetbrains.kotlin.types.typeUtil.*
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
|
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
|
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages.internalPackageFqName
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages.internalPackageFqName
|
||||||
|
|
||||||
interface ISerialTypeInfo<C, D, T : KotlinTypeMarker, S : ISerializableProperty<D, T>> {
|
|
||||||
val property: S
|
|
||||||
val elementMethodPrefix: String
|
|
||||||
val serializer: C?
|
|
||||||
}
|
|
||||||
|
|
||||||
open class SerialTypeInfo(
|
open class SerialTypeInfo(
|
||||||
override val property: SerializableProperty,
|
val property: SerializableProperty,
|
||||||
override val elementMethodPrefix: String,
|
val elementMethodPrefix: String,
|
||||||
override val serializer: ClassDescriptor? = null
|
val serializer: ClassDescriptor? = null
|
||||||
) : ISerialTypeInfo<ClassDescriptor, PropertyDescriptor, KotlinType, SerializableProperty>
|
)
|
||||||
|
|
||||||
class IrSerialTypeInfo(
|
|
||||||
override val property: IrSerializableProperty,
|
|
||||||
override val elementMethodPrefix: String,
|
|
||||||
override val serializer: IrClassSymbol? = null
|
|
||||||
) : ISerialTypeInfo<IrClassSymbol, IrProperty, IrSimpleType, IrSerializableProperty>
|
|
||||||
|
|
||||||
|
|
||||||
fun AbstractSerialGenerator.findAddOnSerializer(propertyType: KotlinType, module: ModuleDescriptor): ClassDescriptor? {
|
fun AbstractSerialGenerator.findAddOnSerializer(propertyType: KotlinType, module: ModuleDescriptor): ClassDescriptor? {
|
||||||
additionalSerializersInScopeOfCurrentFile[propertyType.toClassDescriptor to propertyType.isMarkedNullable]?.let { return it }
|
additionalSerializersInScopeOfCurrentFile[propertyType.toClassDescriptor to propertyType.isMarkedNullable]?.let { return it }
|
||||||
@@ -63,48 +43,9 @@ fun AbstractSerialGenerator.findAddOnSerializer(propertyType: KotlinType, module
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun AbstractIrGenerator.findAddOnSerializer(propertyType: IrType, ctx: SerializationPluginContext): IrClassSymbol? {
|
|
||||||
val classSymbol = propertyType.classOrNull ?: return null
|
|
||||||
additionalSerializersInScopeOfCurrentFile[classSymbol to propertyType.isNullable()]?.let { return it }
|
|
||||||
if (classSymbol in contextualKClassListInCurrentFile)
|
|
||||||
return ctx.getClassFromRuntime(SpecialBuiltins.contextSerializer)
|
|
||||||
if (classSymbol.owner.annotations.hasAnnotation(SerializationAnnotations.polymorphicFqName))
|
|
||||||
return ctx.getClassFromRuntime(SpecialBuiltins.polymorphicSerializer)
|
|
||||||
if (propertyType.isNullable()) return findAddOnSerializer(propertyType.makeNotNull(), ctx)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun KotlinType.isGeneratedSerializableObject() =
|
fun KotlinType.isGeneratedSerializableObject() =
|
||||||
toClassDescriptor?.run { kind == ClassKind.OBJECT && hasSerializableOrMetaAnnotationWithoutArgs } == true
|
toClassDescriptor?.run { kind == ClassKind.OBJECT && hasSerializableOrMetaAnnotationWithoutArgs } == true
|
||||||
|
|
||||||
fun AbstractIrGenerator.getIrSerialTypeInfo(property: IrSerializableProperty, ctx: SerializationPluginContext): IrSerialTypeInfo {
|
|
||||||
fun SerializableInfo(serializer: IrClassSymbol?) =
|
|
||||||
IrSerialTypeInfo(property, if (property.type.isNullable()) "Nullable" else "", serializer)
|
|
||||||
|
|
||||||
val T = property.type
|
|
||||||
property.serializableWith(ctx)?.let { return SerializableInfo(it) }
|
|
||||||
findAddOnSerializer(T, ctx)?.let { return SerializableInfo(it) }
|
|
||||||
T.overridenSerializer?.let { return SerializableInfo(it) }
|
|
||||||
return when {
|
|
||||||
T.isTypeParameter() -> IrSerialTypeInfo(property, if (property.type.isMarkedNullable()) "Nullable" else "", null)
|
|
||||||
T.isPrimitiveType() -> IrSerialTypeInfo(
|
|
||||||
property,
|
|
||||||
T.classFqName!!.asString().removePrefix("kotlin.")
|
|
||||||
)
|
|
||||||
T.isString() -> IrSerialTypeInfo(property, "String")
|
|
||||||
T.isArray() -> {
|
|
||||||
val serializer = property.serializableWith(ctx) ?: ctx.getClassFromInternalSerializationPackage(SpecialBuiltins.referenceArraySerializer)
|
|
||||||
SerializableInfo(serializer)
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
val serializer =
|
|
||||||
findTypeSerializerOrContext(ctx, property.type)
|
|
||||||
SerializableInfo(serializer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("FunctionName", "LocalVariableName")
|
@Suppress("FunctionName", "LocalVariableName")
|
||||||
fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
|
fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
|
||||||
fun SerializableInfo(serializer: ClassDescriptor?) =
|
fun SerializableInfo(serializer: ClassDescriptor?) =
|
||||||
|
|||||||
+578
@@ -0,0 +1,578 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 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.backend.common.lower.irIfThen
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.functionByName
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.ir.fileParent
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.ir.representativeUpperBound
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.descriptors.isSealed
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrValueDeclaration
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||||
|
import org.jetbrains.kotlin.ir.deepCopyWithVariables
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrVararg
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
|
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||||
|
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||||
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.*
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||||
|
|
||||||
|
abstract class BaseIrGenerator(private val currentClass: IrClass, final override val compilerContext: SerializationPluginContext): IrBuilderWithPluginContext {
|
||||||
|
|
||||||
|
private val throwMissedFieldExceptionFunc
|
||||||
|
= compilerContext.referenceFunctions(CallableId(SerializationPackages.internalPackageFqName, SerialEntityNames.SINGLE_MASK_FIELD_MISSING_FUNC_NAME)).singleOrNull()
|
||||||
|
|
||||||
|
private val throwMissedFieldExceptionArrayFunc
|
||||||
|
= compilerContext.referenceFunctions(CallableId(SerializationPackages.internalPackageFqName, SerialEntityNames.ARRAY_MASK_FIELD_MISSING_FUNC_NAME)).singleOrNull()
|
||||||
|
|
||||||
|
private val enumSerializerFactoryFunc
|
||||||
|
= compilerContext.referenceFunctions(CallableId(SerializationPackages.internalPackageFqName, SerialEntityNames.ENUM_SERIALIZER_FACTORY_FUNC_NAME)).singleOrNull()
|
||||||
|
|
||||||
|
private val markedEnumSerializerFactoryFunc
|
||||||
|
= compilerContext.referenceFunctions(CallableId(SerializationPackages.internalPackageFqName, SerialEntityNames.MARKED_ENUM_SERIALIZER_FACTORY_FUNC_NAME)).singleOrNull()
|
||||||
|
|
||||||
|
fun useFieldMissingOptimization(): Boolean {
|
||||||
|
return throwMissedFieldExceptionFunc != null && throwMissedFieldExceptionArrayFunc != null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getClassListFromFileAnnotation(annotationFqName: FqName): List<IrClassSymbol> {
|
||||||
|
val annotation = currentClass.fileParent.annotations.findAnnotation(annotationFqName) ?: return emptyList()
|
||||||
|
val vararg = annotation.getValueArgument(0) as? IrVararg ?: return emptyList()
|
||||||
|
return vararg.elements
|
||||||
|
.mapNotNull { (it as? IrClassReference)?.symbol as? IrClassSymbol }
|
||||||
|
}
|
||||||
|
|
||||||
|
val contextualKClassListInCurrentFile: Set<IrClassSymbol> by lazy {
|
||||||
|
getClassListFromFileAnnotation(
|
||||||
|
SerializationAnnotations.contextualFqName,
|
||||||
|
).plus(
|
||||||
|
getClassListFromFileAnnotation(
|
||||||
|
SerializationAnnotations.contextualOnFileFqName,
|
||||||
|
)
|
||||||
|
).toSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
val additionalSerializersInScopeOfCurrentFile: Map<Pair<IrClassSymbol, Boolean>, IrClassSymbol> by lazy {
|
||||||
|
getClassListFromFileAnnotation(SerializationAnnotations.additionalSerializersFqName,)
|
||||||
|
.associateBy(
|
||||||
|
{ serializerSymbol ->
|
||||||
|
val kotlinType = (serializerSymbol.owner.superTypes.find(IrType::isKSerializer) as? IrSimpleType)?.arguments?.firstOrNull()?.typeOrNull
|
||||||
|
val classSymbol = kotlinType?.classOrNull
|
||||||
|
?: throw AssertionError("Argument for ${SerializationAnnotations.additionalSerializersFqName} does not implement KSerializer or does not provide serializer for concrete type")
|
||||||
|
classSymbol to kotlinType.isNullable()
|
||||||
|
},
|
||||||
|
{ it }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBlockBodyBuilder.generateGoldenMaskCheck(
|
||||||
|
seenVars: List<IrValueDeclaration>,
|
||||||
|
properties: IrSerializableProperties,
|
||||||
|
serialDescriptor: IrExpression
|
||||||
|
) {
|
||||||
|
val fieldsMissedTest: IrExpression
|
||||||
|
val throwErrorExpr: IrExpression
|
||||||
|
|
||||||
|
val maskSlotCount = seenVars.size
|
||||||
|
if (maskSlotCount == 1) {
|
||||||
|
val goldenMask = properties.goldenMask
|
||||||
|
|
||||||
|
|
||||||
|
throwErrorExpr = irInvoke(
|
||||||
|
null,
|
||||||
|
throwMissedFieldExceptionFunc!!,
|
||||||
|
irGet(seenVars[0]),
|
||||||
|
irInt(goldenMask),
|
||||||
|
serialDescriptor,
|
||||||
|
typeHint = compilerContext.irBuiltIns.unitType
|
||||||
|
)
|
||||||
|
|
||||||
|
fieldsMissedTest = irNotEquals(
|
||||||
|
irInt(goldenMask),
|
||||||
|
irBinOp(
|
||||||
|
OperatorNameConventions.AND,
|
||||||
|
irInt(goldenMask),
|
||||||
|
irGet(seenVars[0])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val goldenMaskList = properties.goldenMaskList
|
||||||
|
|
||||||
|
var compositeExpression: IrExpression? = null
|
||||||
|
for (i in goldenMaskList.indices) {
|
||||||
|
val singleCheckExpr = irNotEquals(
|
||||||
|
irInt(goldenMaskList[i]),
|
||||||
|
irBinOp(
|
||||||
|
OperatorNameConventions.AND,
|
||||||
|
irInt(goldenMaskList[i]),
|
||||||
|
irGet(seenVars[i])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
compositeExpression = if (compositeExpression == null) {
|
||||||
|
singleCheckExpr
|
||||||
|
} else {
|
||||||
|
irBinOp(
|
||||||
|
OperatorNameConventions.OR,
|
||||||
|
compositeExpression,
|
||||||
|
singleCheckExpr
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldsMissedTest = compositeExpression!!
|
||||||
|
|
||||||
|
throwErrorExpr = irBlock {
|
||||||
|
+irInvoke(
|
||||||
|
null,
|
||||||
|
throwMissedFieldExceptionArrayFunc!!,
|
||||||
|
createPrimitiveArrayOfExpression(compilerContext.irBuiltIns.intType, goldenMaskList.indices.map { irGet(seenVars[it]) }),
|
||||||
|
createPrimitiveArrayOfExpression(compilerContext.irBuiltIns.intType, goldenMaskList.map { irInt(it) }),
|
||||||
|
serialDescriptor,
|
||||||
|
typeHint = compilerContext.irBuiltIns.unitType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+irIfThen(compilerContext.irBuiltIns.unitType, fieldsMissedTest, throwErrorExpr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBlockBodyBuilder.serializeAllProperties(
|
||||||
|
serializableProperties: List<IrSerializableProperty>,
|
||||||
|
objectToSerialize: IrValueDeclaration,
|
||||||
|
localOutput: IrValueDeclaration,
|
||||||
|
localSerialDesc: IrValueDeclaration,
|
||||||
|
kOutputClass: IrClassSymbol,
|
||||||
|
ignoreIndexTo: Int,
|
||||||
|
initializerAdapter: (IrExpressionBody) -> IrExpression,
|
||||||
|
genericGetter: ((Int, IrType) -> IrExpression)?
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun IrSerializableProperty.irGet(): IrExpression {
|
||||||
|
val ownerType = objectToSerialize.symbol.owner.type
|
||||||
|
return getProperty(
|
||||||
|
irGet(
|
||||||
|
type = ownerType,
|
||||||
|
variable = objectToSerialize.symbol
|
||||||
|
), ir
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((index, property) in serializableProperties.withIndex()) {
|
||||||
|
if (index < ignoreIndexTo) continue
|
||||||
|
// output.writeXxxElementValue(classDesc, index, value)
|
||||||
|
val elementCall = formEncodeDecodePropertyCall(
|
||||||
|
irGet(localOutput),
|
||||||
|
property, { innerSerial, sti ->
|
||||||
|
val f =
|
||||||
|
kOutputClass.functionByName("${CallingConventions.encode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}")
|
||||||
|
f to listOf(
|
||||||
|
irGet(localSerialDesc),
|
||||||
|
irInt(index),
|
||||||
|
innerSerial,
|
||||||
|
property.irGet()
|
||||||
|
)
|
||||||
|
}, {
|
||||||
|
val f =
|
||||||
|
kOutputClass.functionByName("${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
|
||||||
|
},
|
||||||
|
genericGetter
|
||||||
|
)
|
||||||
|
|
||||||
|
// check for call to .shouldEncodeElementDefault
|
||||||
|
val encodeDefaults = property.ir.getEncodeDefaultAnnotationValue()
|
||||||
|
val field =
|
||||||
|
property.ir.backingField // Nullable when property from another module; can't compare it with default value on JS or Native
|
||||||
|
if (!property.optional || encodeDefaults == true || field == null) {
|
||||||
|
// emit call right away
|
||||||
|
+elementCall
|
||||||
|
} else {
|
||||||
|
val partB = irNotEquals(property.irGet(), initializerAdapter(field.initializer!!))
|
||||||
|
|
||||||
|
val condition = if (encodeDefaults == false) {
|
||||||
|
// drop default without call to .shouldEncodeElementDefault
|
||||||
|
partB
|
||||||
|
} 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.functionByName(CallingConventions.shouldEncodeDefault)
|
||||||
|
val partA = irInvoke(irGet(localOutput), shouldEncodeFunc, irGet(localSerialDesc), irInt(index))
|
||||||
|
// Ir infrastructure does not have dedicated symbol for ||, so
|
||||||
|
// `a || b == if (a) true else b`, see org.jetbrains.kotlin.ir.builders.PrimitivesKt.oror
|
||||||
|
irIfThenElse(compilerContext.irBuiltIns.booleanType, partA, irTrue(), partB)
|
||||||
|
}
|
||||||
|
+irIfThen(condition, elementCall)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun IrBlockBodyBuilder.formEncodeDecodePropertyCall(
|
||||||
|
encoder: IrExpression,
|
||||||
|
property: IrSerializableProperty,
|
||||||
|
whenHaveSerializer: (serializer: IrExpression, sti: IrSerialTypeInfo) -> FunctionWithArgs,
|
||||||
|
whenDoNot: (sti: IrSerialTypeInfo) -> FunctionWithArgs,
|
||||||
|
genericGetter: ((Int, IrType) -> IrExpression)? = null,
|
||||||
|
returnTypeHint: IrType? = null
|
||||||
|
): IrExpression {
|
||||||
|
val sti = getIrSerialTypeInfo(property, compilerContext)
|
||||||
|
val innerSerial = serializerInstance(
|
||||||
|
sti.serializer,
|
||||||
|
compilerContext,
|
||||||
|
property.type,
|
||||||
|
property.genericIndex,
|
||||||
|
genericGetter
|
||||||
|
)
|
||||||
|
val (functionToCall, args: List<IrExpression>) = if (innerSerial != null) whenHaveSerializer(innerSerial, sti) else whenDoNot(sti)
|
||||||
|
val typeArgs = if (functionToCall.descriptor.typeParameters.isNotEmpty()) listOf(property.type) else listOf()
|
||||||
|
return irInvoke(encoder, functionToCall, typeArguments = typeArgs, valueArguments = args, returnTypeHint = returnTypeHint)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.callSerializerFromCompanion(
|
||||||
|
thisIrType: IrType,
|
||||||
|
typeArgs: List<IrType>,
|
||||||
|
args: List<IrExpression>
|
||||||
|
): IrExpression? {
|
||||||
|
val baseClass = thisIrType.getClass() ?: return null
|
||||||
|
val companionClass = baseClass.companionObject() ?: return null
|
||||||
|
val serializerProviderFunction = companionClass.declarations.singleOrNull {
|
||||||
|
it is IrFunction && it.name == SerialEntityNames.SERIALIZER_PROVIDER_NAME && it.valueParameters.size == baseClass.typeParameters.size
|
||||||
|
} ?: return null
|
||||||
|
|
||||||
|
val adjustedArgs: List<IrExpression> =
|
||||||
|
// if typeArgs.size == args.size then the serializer is custom - we need to use the actual serializers from the arguments
|
||||||
|
if ((typeArgs.size != args.size) && (baseClass.descriptor.isSealed() || baseClass.descriptor.modality == Modality.ABSTRACT)) {
|
||||||
|
val serializer = findStandardKotlinTypeSerializer(compilerContext, context.irBuiltIns.unitType)!!
|
||||||
|
// workaround for sealed and abstract classes - the `serializer` function expects non-null serializers, but does not use them, so serializers of any type can be passed
|
||||||
|
List(baseClass.typeParameters.size) { irGetObject(serializer) }
|
||||||
|
} else {
|
||||||
|
args
|
||||||
|
}
|
||||||
|
|
||||||
|
with(serializerProviderFunction as IrFunction) {
|
||||||
|
// Note that [typeArgs] may be unused if we short-cut to e.g. SealedClassSerializer
|
||||||
|
return irInvoke(
|
||||||
|
irGetObject(companionClass),
|
||||||
|
symbol,
|
||||||
|
typeArgs.takeIf { it.size == typeParameters.size }.orEmpty(),
|
||||||
|
adjustedArgs.takeIf { it.size == valueParameters.size }.orEmpty()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does not use sti and therefore does not perform encoder calls optimization
|
||||||
|
fun IrBuilderWithScope.serializerTower(
|
||||||
|
generator: SerializerIrGenerator,
|
||||||
|
dispatchReceiverParameter: IrValueParameter,
|
||||||
|
property: IrSerializableProperty
|
||||||
|
): IrExpression? {
|
||||||
|
val nullableSerClass = compilerContext.referenceProperties(SerialEntityNames.wrapIntoNullableCallableId).single()
|
||||||
|
val serializer =
|
||||||
|
property.serializableWith(compilerContext)
|
||||||
|
?: if (!property.type.isTypeParameter()) generator.findTypeSerializerOrContext(
|
||||||
|
compilerContext,
|
||||||
|
property.type
|
||||||
|
) else null
|
||||||
|
return serializerInstance(
|
||||||
|
serializer,
|
||||||
|
compilerContext,
|
||||||
|
property.type,
|
||||||
|
genericIndex = property.genericIndex
|
||||||
|
) { it, _ ->
|
||||||
|
val (_, ir) = generator.localSerializersFieldsDescriptors[it]
|
||||||
|
irGetField(irGet(dispatchReceiverParameter), ir.backingField!!)
|
||||||
|
}?.let { expr -> wrapWithNullableSerializerIfNeeded(property.type, expr, nullableSerClass) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrBuilderWithScope.wrapWithNullableSerializerIfNeeded(
|
||||||
|
type: IrType,
|
||||||
|
expression: IrExpression,
|
||||||
|
nullableProp: IrPropertySymbol
|
||||||
|
): IrExpression = if (type.isMarkedNullable()) {
|
||||||
|
val resultType = type.makeNotNull()
|
||||||
|
val typeArguments = listOf(resultType)
|
||||||
|
val callee = nullableProp.owner.getter!!
|
||||||
|
|
||||||
|
val returnType = callee.returnType.substitute(callee.typeParameters, typeArguments)
|
||||||
|
|
||||||
|
irInvoke(
|
||||||
|
callee = callee.symbol,
|
||||||
|
typeArguments = typeArguments,
|
||||||
|
valueArguments = emptyList(),
|
||||||
|
returnTypeHint = returnType
|
||||||
|
).apply { extensionReceiver = expression }
|
||||||
|
} else {
|
||||||
|
expression
|
||||||
|
}
|
||||||
|
|
||||||
|
fun wrapIrTypeIntoKSerializerIrType(
|
||||||
|
type: IrType,
|
||||||
|
variance: Variance = Variance.INVARIANT
|
||||||
|
): IrType {
|
||||||
|
val kSerClass = compilerContext.referenceClass(ClassId(SerializationPackages.packageFqName, SerialEntityNames.KSERIALIZER_NAME))
|
||||||
|
?: error("Couldn't find class ${SerialEntityNames.KSERIALIZER_NAME}")
|
||||||
|
return IrSimpleTypeImpl(
|
||||||
|
kSerClass, hasQuestionMark = false, arguments = listOf(
|
||||||
|
makeTypeProjection(type, variance)
|
||||||
|
), annotations = emptyList()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.serializerInstance(
|
||||||
|
serializerClassOriginal: IrClassSymbol?,
|
||||||
|
pluginContext: SerializationPluginContext,
|
||||||
|
kType: IrType,
|
||||||
|
genericIndex: Int? = null,
|
||||||
|
genericGetter: ((Int, IrType) -> IrExpression)? = null
|
||||||
|
): IrExpression? {
|
||||||
|
val nullableSerClass = compilerContext.referenceProperties(SerialEntityNames.wrapIntoNullableCallableId).single()
|
||||||
|
if (serializerClassOriginal == null) {
|
||||||
|
if (genericIndex == null) return null
|
||||||
|
return genericGetter?.invoke(genericIndex, kType)
|
||||||
|
}
|
||||||
|
if (serializerClassOriginal.owner.kind == ClassKind.OBJECT) {
|
||||||
|
return irGetObject(serializerClassOriginal)
|
||||||
|
}
|
||||||
|
fun instantiate(serializer: IrClassSymbol?, type: IrType): IrExpression? {
|
||||||
|
val expr = serializerInstance(
|
||||||
|
serializer,
|
||||||
|
pluginContext,
|
||||||
|
type,
|
||||||
|
type.genericIndex,
|
||||||
|
genericGetter
|
||||||
|
) ?: return null
|
||||||
|
return wrapWithNullableSerializerIfNeeded(type, expr, nullableSerClass)
|
||||||
|
}
|
||||||
|
|
||||||
|
var serializerClass = serializerClassOriginal
|
||||||
|
var args: List<IrExpression>
|
||||||
|
var typeArgs: List<IrType>
|
||||||
|
val thisIrType = (kType as? IrSimpleType) ?: error("Don't know how to work with type ${kType::class}")
|
||||||
|
var needToCopyAnnotations = false
|
||||||
|
|
||||||
|
when (serializerClassOriginal.owner.classId) {
|
||||||
|
polymorphicSerializerId -> {
|
||||||
|
needToCopyAnnotations = true
|
||||||
|
args = listOf(classReference(kType))
|
||||||
|
typeArgs = listOf(thisIrType)
|
||||||
|
}
|
||||||
|
contextSerializerId -> {
|
||||||
|
args = listOf(classReference(kType))
|
||||||
|
typeArgs = listOf(thisIrType)
|
||||||
|
|
||||||
|
val hasNewCtxSerCtor = compilerContext.referenceConstructors(contextSerializerId).any { it.owner.valueParameters.size == 3 }
|
||||||
|
|
||||||
|
if (hasNewCtxSerCtor) {
|
||||||
|
// new signature of context serializer
|
||||||
|
args = args + mutableListOf<IrExpression>().apply {
|
||||||
|
val fallbackDefaultSerializer = findTypeSerializer(pluginContext, kType)
|
||||||
|
add(instantiate(fallbackDefaultSerializer, kType) ?: irNull())
|
||||||
|
add(
|
||||||
|
createArrayOfExpression(
|
||||||
|
wrapIrTypeIntoKSerializerIrType(
|
||||||
|
thisIrType,
|
||||||
|
variance = Variance.OUT_VARIANCE
|
||||||
|
),
|
||||||
|
thisIrType.arguments.map {
|
||||||
|
val argSer = findTypeSerializerOrContext(
|
||||||
|
compilerContext,
|
||||||
|
it.typeOrNull!! //todo: handle star projections here?
|
||||||
|
)
|
||||||
|
instantiate(argSer, it.typeOrNull!!)!!
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
objectSerializerId -> {
|
||||||
|
needToCopyAnnotations = true
|
||||||
|
args = listOf(irString(kType.serialName()), irGetObject(kType.classOrNull!!))
|
||||||
|
typeArgs = listOf(thisIrType)
|
||||||
|
}
|
||||||
|
sealedSerializerId -> {
|
||||||
|
needToCopyAnnotations = true
|
||||||
|
args = mutableListOf<IrExpression>().apply {
|
||||||
|
add(irString(kType.serialName()))
|
||||||
|
add(classReference(kType))
|
||||||
|
val (subclasses, subSerializers) = allSealedSerializableSubclassesFor(
|
||||||
|
kType.classOrNull!!.owner,
|
||||||
|
pluginContext
|
||||||
|
)
|
||||||
|
val projectedOutCurrentKClass =
|
||||||
|
compilerContext.irBuiltIns.kClassClass.typeWithArguments(
|
||||||
|
listOf(makeTypeProjection(thisIrType, Variance.OUT_VARIANCE))
|
||||||
|
)
|
||||||
|
add(
|
||||||
|
createArrayOfExpression(
|
||||||
|
projectedOutCurrentKClass,
|
||||||
|
subclasses.map { classReference(it) }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
add(
|
||||||
|
createArrayOfExpression(
|
||||||
|
wrapIrTypeIntoKSerializerIrType(thisIrType, variance = Variance.OUT_VARIANCE),
|
||||||
|
subSerializers.mapIndexed { i, serializer ->
|
||||||
|
val type = subclasses[i]
|
||||||
|
val expr = serializerInstance(
|
||||||
|
serializer,
|
||||||
|
pluginContext,
|
||||||
|
type,
|
||||||
|
type.genericIndex
|
||||||
|
) { _, genericType ->
|
||||||
|
serializerInstance(
|
||||||
|
pluginContext.referenceClass(polymorphicSerializerId),
|
||||||
|
pluginContext,
|
||||||
|
(genericType.classifierOrNull as IrTypeParameterSymbol).owner.representativeUpperBound
|
||||||
|
)!!
|
||||||
|
}!!
|
||||||
|
wrapWithNullableSerializerIfNeeded(type, expr, nullableSerClass)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
typeArgs = listOf(thisIrType)
|
||||||
|
}
|
||||||
|
enumSerializerId -> {
|
||||||
|
serializerClass = pluginContext.referenceClass(enumSerializerId)
|
||||||
|
val enumDescriptor = kType.classOrNull!!
|
||||||
|
typeArgs = listOf(thisIrType)
|
||||||
|
// instantiate serializer only inside enum Companion
|
||||||
|
if (this@BaseIrGenerator !is SerializableCompanionIrGenerator) {
|
||||||
|
// otherwise call Companion.serializer()
|
||||||
|
callSerializerFromCompanion(thisIrType, typeArgs, emptyList())?.let { return it }
|
||||||
|
}
|
||||||
|
|
||||||
|
val enumArgs = mutableListOf(
|
||||||
|
irString(thisIrType.serialName()),
|
||||||
|
irCall(enumDescriptor.owner.findEnumValuesMethod()),
|
||||||
|
)
|
||||||
|
|
||||||
|
val enumSerializerFactoryFunc = enumSerializerFactoryFunc
|
||||||
|
val markedEnumSerializerFactoryFunc = markedEnumSerializerFactoryFunc
|
||||||
|
if (enumSerializerFactoryFunc != null && markedEnumSerializerFactoryFunc != null) {
|
||||||
|
// runtime contains enum serializer factory functions
|
||||||
|
val factoryFunc: IrSimpleFunctionSymbol = if (enumDescriptor.owner.isEnumWithSerialInfoAnnotation()) {
|
||||||
|
// need to store SerialInfo annotation in descriptor
|
||||||
|
val enumEntries = enumDescriptor.owner.enumEntries()
|
||||||
|
val entriesNames = enumEntries.map { it.annotations.serialNameValue?.let { n -> irString(n) } ?: irNull() }
|
||||||
|
val entriesAnnotations = enumEntries.map {
|
||||||
|
val annotationConstructors = it.annotations.map { a ->
|
||||||
|
a.deepCopyWithVariables()
|
||||||
|
}
|
||||||
|
val annotationsConstructors = copyAnnotationsFrom(annotationConstructors)
|
||||||
|
if (annotationsConstructors.isEmpty()) {
|
||||||
|
irNull()
|
||||||
|
} else {
|
||||||
|
createArrayOfExpression(compilerContext.irBuiltIns.annotationType, annotationsConstructors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val annotationArrayType =
|
||||||
|
compilerContext.irBuiltIns.arrayClass.typeWith(compilerContext.irBuiltIns.annotationType.makeNullable())
|
||||||
|
|
||||||
|
enumArgs += createArrayOfExpression(compilerContext.irBuiltIns.stringType.makeNullable(), entriesNames)
|
||||||
|
enumArgs += createArrayOfExpression(annotationArrayType, entriesAnnotations)
|
||||||
|
|
||||||
|
markedEnumSerializerFactoryFunc
|
||||||
|
} else {
|
||||||
|
enumSerializerFactoryFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
val factoryReturnType = factoryFunc.owner.returnType.substitute(factoryFunc.owner.typeParameters, typeArgs)
|
||||||
|
return irInvoke(null, factoryFunc, typeArgs, enumArgs, factoryReturnType)
|
||||||
|
} else {
|
||||||
|
// support legacy serializer instantiation by constructor for old runtimes
|
||||||
|
args = enumArgs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
args = kType.arguments.map {
|
||||||
|
val argSer = findTypeSerializerOrContext(
|
||||||
|
pluginContext,
|
||||||
|
it.typeOrNull!! // todo: stars?
|
||||||
|
)
|
||||||
|
instantiate(argSer, it.typeOrNull!!) ?: return null
|
||||||
|
}
|
||||||
|
typeArgs = kType.arguments.map { it.typeOrNull!! }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (serializerClassOriginal.owner.classId == referenceArraySerializerId) {
|
||||||
|
args = listOf(wrapperClassReference(kType.arguments.single().typeOrNull!!)) + args
|
||||||
|
typeArgs = listOf(typeArgs[0].makeNotNull()) + typeArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
// If KType is interface, .classSerializer always yields PolymorphicSerializer, which may be unavailable for interfaces from other modules
|
||||||
|
if (!kType.isInterface() && serializerClassOriginal == kType.classOrNull!!.owner.classSerializer(pluginContext) && this@BaseIrGenerator !is SerializableCompanionIrGenerator) {
|
||||||
|
// This is default type serializer, we can shortcut through Companion.serializer()
|
||||||
|
// BUT not during generation of this method itself
|
||||||
|
callSerializerFromCompanion(thisIrType, typeArgs, args)?.let { return it }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val serializable = serializerClass?.owner?.let { getSerializableClassDescriptorBySerializer(it) }
|
||||||
|
requireNotNull(serializerClass)
|
||||||
|
val ctor = if (serializable?.typeParameters?.isNotEmpty() == true) {
|
||||||
|
requireNotNull(
|
||||||
|
findSerializerConstructorForTypeArgumentsSerializers(serializerClass.owner)
|
||||||
|
) { "Generated serializer does not have constructor with required number of arguments" }
|
||||||
|
} else {
|
||||||
|
val constructors = serializerClass.constructors
|
||||||
|
// search for new signature of polymorphic/sealed/contextual serializer
|
||||||
|
if (!needToCopyAnnotations) {
|
||||||
|
constructors.single { it.owner.isPrimary }
|
||||||
|
} else {
|
||||||
|
constructors.find { it.owner.lastArgumentIsAnnotationArray() } ?: run {
|
||||||
|
// not found - we are using old serialization runtime without this feature
|
||||||
|
// todo: optimize allocating an empty array when no annotations defined, maybe use old constructor?
|
||||||
|
needToCopyAnnotations = false
|
||||||
|
constructors.single { it.owner.isPrimary }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Return type should be correctly substituted
|
||||||
|
assert(ctor.isBound)
|
||||||
|
val ctorDecl = ctor.owner
|
||||||
|
if (needToCopyAnnotations) {
|
||||||
|
val classAnnotations = copyAnnotationsFrom(thisIrType.getClass()?.let { collectSerialInfoAnnotations(it) }.orEmpty())
|
||||||
|
args = args + createArrayOfExpression(compilerContext.irBuiltIns.annotationType, classAnnotations)
|
||||||
|
}
|
||||||
|
|
||||||
|
val typeParameters = ctorDecl.parentAsClass.typeParameters
|
||||||
|
val substitutedReturnType = ctorDecl.returnType.substitute(typeParameters, typeArgs)
|
||||||
|
return irInvoke(
|
||||||
|
null,
|
||||||
|
ctor,
|
||||||
|
// User may declare serializer with fixed type arguments, e.g. class SomeSerializer : KSerializer<ClosedRange<Float>>
|
||||||
|
typeArguments = typeArgs.takeIf { it.size == ctorDecl.typeParameters.size }.orEmpty(),
|
||||||
|
valueArguments = args.takeIf { it.size == ctorDecl.valueParameters.size }.orEmpty(),
|
||||||
|
returnTypeHint = substitutedReturnType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+126
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 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.ValueParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irGet
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irGetField
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||||
|
import org.jetbrains.kotlin.ir.deepCopyWithVariables
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.constructors
|
||||||
|
import org.jetbrains.kotlin.ir.util.properties
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.getProperty(receiver: IrExpression, property: IrProperty): IrExpression {
|
||||||
|
return if (property.getter != null)
|
||||||
|
irGet(property.getter!!.returnType, receiver, property.getter!!.symbol)
|
||||||
|
else
|
||||||
|
irGetField(receiver, property.backingField!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create a function that creates `get property value expressions` for given corresponded constructor's param
|
||||||
|
(constructor_params) -> get_property_value_expression
|
||||||
|
*/
|
||||||
|
fun IrBuilderWithScope.createPropertyByParamReplacer(
|
||||||
|
irClass: IrClass,
|
||||||
|
serialProperties: List<IrSerializableProperty>,
|
||||||
|
instance: IrValueParameter
|
||||||
|
): (ValueParameterDescriptor) -> IrExpression? {
|
||||||
|
fun IrSerializableProperty.irGet(): IrExpression {
|
||||||
|
val ownerType = instance.symbol.owner.type
|
||||||
|
return getProperty(
|
||||||
|
irGet(
|
||||||
|
type = ownerType,
|
||||||
|
variable = instance.symbol
|
||||||
|
), ir
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val serialPropertiesMap = serialProperties.associateBy { it.ir }
|
||||||
|
|
||||||
|
val transientPropertiesSet =
|
||||||
|
irClass.declarations.asSequence()
|
||||||
|
.filterIsInstance<IrProperty>()
|
||||||
|
.filter { it.backingField != null }
|
||||||
|
.filter { !serialPropertiesMap.containsKey(it) }
|
||||||
|
.toSet()
|
||||||
|
|
||||||
|
return { vpd ->
|
||||||
|
val propertyDescriptor = irClass.properties.find { it.name == vpd.name }
|
||||||
|
if (propertyDescriptor != null) {
|
||||||
|
val value = serialPropertiesMap[propertyDescriptor]
|
||||||
|
value?.irGet() ?: run {
|
||||||
|
if (propertyDescriptor in transientPropertiesSet)
|
||||||
|
getProperty(
|
||||||
|
irGet(instance),
|
||||||
|
propertyDescriptor
|
||||||
|
)
|
||||||
|
else null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Creates an initializer adapter function that can replace IR expressions of getting constructor parameter value by some other expression.
|
||||||
|
Also adapter may replace IR expression of getting `this` value by another expression.
|
||||||
|
*/
|
||||||
|
fun createInitializerAdapter(
|
||||||
|
irClass: IrClass,
|
||||||
|
paramGetReplacer: (ValueParameterDescriptor) -> IrExpression?,
|
||||||
|
thisGetReplacer: Pair<IrValueSymbol, () -> IrExpression>? = null
|
||||||
|
): (IrExpressionBody) -> IrExpression {
|
||||||
|
val initializerTransformer = object : IrElementTransformerVoid() {
|
||||||
|
// try to replace `get some value` expression
|
||||||
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
|
val symbol = expression.symbol
|
||||||
|
if (thisGetReplacer != null && thisGetReplacer.first == symbol) {
|
||||||
|
// replace `get this value` expression
|
||||||
|
return thisGetReplacer.second()
|
||||||
|
}
|
||||||
|
|
||||||
|
val descriptor = symbol.descriptor
|
||||||
|
if (descriptor is ValueParameterDescriptor) {
|
||||||
|
// replace `get parameter value` expression
|
||||||
|
paramGetReplacer(descriptor)?.let { return it }
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise leave expression as it is
|
||||||
|
return super.visitGetValue(expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val defaultsMap = extractDefaultValuesFromConstructor(irClass)
|
||||||
|
return fun(initializer: IrExpressionBody): IrExpression {
|
||||||
|
val rawExpression = initializer.expression
|
||||||
|
val expression =
|
||||||
|
if (rawExpression.isInitializePropertyFromParameter()) {
|
||||||
|
// this is a primary constructor property, use corresponding default of value parameter
|
||||||
|
defaultsMap.getValue((rawExpression as IrGetValue).symbol)!!
|
||||||
|
} else {
|
||||||
|
rawExpression
|
||||||
|
}
|
||||||
|
return expression.deepCopyWithVariables().transform(initializerTransformer, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractDefaultValuesFromConstructor(irClass: IrClass?): Map<IrValueSymbol, IrExpression?> {
|
||||||
|
if (irClass == null) return emptyMap()
|
||||||
|
val original = irClass.constructors.singleOrNull { it.isPrimary }
|
||||||
|
// default arguments of original constructor
|
||||||
|
val defaultsMap: Map<IrValueSymbol, IrExpression?> =
|
||||||
|
original?.valueParameters?.associate { it.symbol to it.defaultValue?.expression } ?: emptyMap()
|
||||||
|
return defaultsMap + extractDefaultValuesFromConstructor(irClass.getSuperClassNotAny())
|
||||||
|
}
|
||||||
+7
-2
@@ -11,8 +11,8 @@ import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||||
|
import org.jetbrains.kotlin.ir.util.constructors
|
||||||
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
||||||
|
|
||||||
// TODO KT-53096
|
// TODO KT-53096
|
||||||
@@ -38,4 +38,9 @@ fun IrPluginContext.generateBodyForDefaultConstructor(declaration: IrConstructor
|
|||||||
return irFactory.createBlockBody(-1, -1, listOf(delegatingAnyCall, initializerCall))
|
return irFactory.createBlockBody(-1, -1, listOf(delegatingAnyCall, initializerCall))
|
||||||
}
|
}
|
||||||
|
|
||||||
val Sequence<IrConstructor>.primary get() = find { it.isPrimary } ?: error("Expected to have a primary constructor")
|
val Sequence<IrConstructor>.primary get() = find { it.isPrimary } ?: error("Expected to have a primary constructor")
|
||||||
|
|
||||||
|
fun IrClass.addDefaultConstructorIfAbsent(ctx: IrPluginContext) {
|
||||||
|
val declaration = constructors.primary
|
||||||
|
if (declaration.body == null) declaration.body = ctx.generateBodyForDefaultConstructor(declaration)
|
||||||
|
}
|
||||||
-1367
File diff suppressed because it is too large
Load Diff
+569
@@ -0,0 +1,569 @@
|
|||||||
|
/*
|
||||||
|
* 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.ir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.extensions.FirIncompatiblePluginAPI
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.builtins.StandardNames
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.deepCopyWithVariables
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies.LAZY_FQ
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies.LAZY_MODE_FQ
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies.LAZY_PUBLICATION_MODE_NAME
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.hasSerializableOrMetaAnnotation
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.isInheritableSerialInfoAnnotation
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.isSerialInfoAnnotation
|
||||||
|
|
||||||
|
|
||||||
|
interface IrBuilderWithPluginContext {
|
||||||
|
val compilerContext: SerializationPluginContext
|
||||||
|
|
||||||
|
fun <F: IrFunction> addFunctionBody(function: F, bodyGen: IrBlockBodyBuilder.(F) -> Unit) {
|
||||||
|
val parentClass = function.parent
|
||||||
|
val startOffset = function.startOffset.takeIf { it >= 0 } ?: parentClass.startOffset
|
||||||
|
val endOffset = function.endOffset.takeIf { it >= 0 } ?: parentClass.endOffset
|
||||||
|
function.body = DeclarationIrBuilder(compilerContext, function.symbol, startOffset, endOffset).irBlockBody(
|
||||||
|
startOffset,
|
||||||
|
endOffset
|
||||||
|
) { bodyGen(function) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrClass.createLambdaExpression(
|
||||||
|
type: IrType,
|
||||||
|
bodyGen: IrBlockBodyBuilder.() -> Unit
|
||||||
|
): IrFunctionExpression {
|
||||||
|
val function = compilerContext.irFactory.buildFun {
|
||||||
|
this.startOffset = this@createLambdaExpression.startOffset
|
||||||
|
this.endOffset = this@createLambdaExpression.endOffset
|
||||||
|
this.returnType = type
|
||||||
|
name = Name.identifier("<anonymous>")
|
||||||
|
visibility = DescriptorVisibilities.LOCAL
|
||||||
|
origin = SERIALIZABLE_PLUGIN_ORIGIN
|
||||||
|
}
|
||||||
|
function.body =
|
||||||
|
DeclarationIrBuilder(compilerContext, function.symbol, startOffset, endOffset).irBlockBody(startOffset, endOffset, bodyGen)
|
||||||
|
function.parent = this
|
||||||
|
|
||||||
|
val f0Type = compilerContext.irBuiltIns.functionN(0)
|
||||||
|
val f0ParamSymbol = f0Type.typeParameters[0].symbol
|
||||||
|
val f0IrType = f0Type.defaultType.substitute(mapOf(f0ParamSymbol to type))
|
||||||
|
|
||||||
|
return IrFunctionExpressionImpl(
|
||||||
|
startOffset,
|
||||||
|
endOffset,
|
||||||
|
f0IrType,
|
||||||
|
function,
|
||||||
|
IrStatementOrigin.LAMBDA
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createLazyProperty(
|
||||||
|
containingClass: IrClass,
|
||||||
|
targetIrType: IrType,
|
||||||
|
name: Name,
|
||||||
|
initializerBuilder: IrBlockBodyBuilder.() -> Unit
|
||||||
|
): IrProperty {
|
||||||
|
val lazySafeModeClassDescriptor = compilerContext.referenceClass(ClassId.topLevel(LAZY_MODE_FQ))!!.owner
|
||||||
|
val lazyFunctionSymbol = compilerContext.referenceFunctions(CallableId(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, Name.identifier("lazy"))).single {
|
||||||
|
it.owner.valueParameters.size == 2 && it.owner.valueParameters[0].type == lazySafeModeClassDescriptor.defaultType
|
||||||
|
}
|
||||||
|
val publicationEntryDescriptor = lazySafeModeClassDescriptor.enumEntries().single { it.name == LAZY_PUBLICATION_MODE_NAME }
|
||||||
|
|
||||||
|
val lazyIrClass = compilerContext.referenceClass(ClassId.topLevel(LAZY_FQ))!!.owner
|
||||||
|
val lazyIrType = lazyIrClass.defaultType.substitute(mapOf(lazyIrClass.typeParameters[0].symbol to targetIrType))
|
||||||
|
|
||||||
|
val propertyDescriptor =
|
||||||
|
KSerializerDescriptorResolver.createValPropertyDescriptor(
|
||||||
|
Name.identifier(name.asString() + "\$delegate"),
|
||||||
|
containingClass.descriptor,
|
||||||
|
lazyIrType.toKotlinType(),
|
||||||
|
createGetter = true
|
||||||
|
)
|
||||||
|
|
||||||
|
return generateSimplePropertyWithBackingField(propertyDescriptor, containingClass).apply {
|
||||||
|
val builder = DeclarationIrBuilder(compilerContext, containingClass.symbol, startOffset, endOffset)
|
||||||
|
val initializerBody = builder.run {
|
||||||
|
val enumElement = IrGetEnumValueImpl(
|
||||||
|
startOffset,
|
||||||
|
endOffset,
|
||||||
|
lazySafeModeClassDescriptor.defaultType,
|
||||||
|
publicationEntryDescriptor.symbol
|
||||||
|
)
|
||||||
|
|
||||||
|
val lambdaExpression = containingClass.createLambdaExpression(targetIrType, initializerBuilder)
|
||||||
|
|
||||||
|
irExprBody(
|
||||||
|
irInvoke(null, lazyFunctionSymbol, listOf(targetIrType), listOf(enumElement, lambdaExpression), lazyIrType)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
backingField!!.initializer = initializerBody
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createCompanionValProperty(
|
||||||
|
companionClass: IrClass,
|
||||||
|
type: IrType,
|
||||||
|
name: Name,
|
||||||
|
initializerBuilder: IrBlockBodyBuilder.() -> Unit
|
||||||
|
): IrProperty {
|
||||||
|
val targetKotlinType = type.toKotlinType()
|
||||||
|
val propertyDescriptor =
|
||||||
|
KSerializerDescriptorResolver.createValPropertyDescriptor(name, companionClass.descriptor, targetKotlinType)
|
||||||
|
|
||||||
|
return generateSimplePropertyWithBackingField(propertyDescriptor, companionClass, name).apply {
|
||||||
|
companionClass.contributeAnonymousInitializer {
|
||||||
|
val irBlockBody = irBlockBody(startOffset, endOffset, initializerBuilder)
|
||||||
|
irBlockBody.statements.dropLast(1).forEach { +it }
|
||||||
|
val expression = irBlockBody.statements.last() as? IrExpression
|
||||||
|
?: throw AssertionError("Last statement in property initializer builder is not an a expression")
|
||||||
|
+irSetField(irGetObject(companionClass), backingField!!, expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrClass.contributeAnonymousInitializer(bodyGen: IrBlockBodyBuilder.() -> Unit) {
|
||||||
|
val symbol = IrAnonymousInitializerSymbolImpl(descriptor)
|
||||||
|
factory.createAnonymousInitializer(startOffset, endOffset, SERIALIZABLE_PLUGIN_ORIGIN, symbol).also {
|
||||||
|
it.parent = this
|
||||||
|
declarations.add(it)
|
||||||
|
it.body = DeclarationIrBuilder(compilerContext, symbol, startOffset, endOffset).irBlockBody(startOffset, endOffset, bodyGen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBlockBodyBuilder.getLazyValueExpression(thisParam: IrValueParameter, property: IrProperty, type: IrType): IrExpression {
|
||||||
|
val lazyIrClass = compilerContext.referenceClass(ClassId.topLevel(LAZY_FQ))!!.owner
|
||||||
|
val valueGetter = lazyIrClass.getPropertyGetter("value")!!
|
||||||
|
|
||||||
|
val propertyGetter = property.getter!!
|
||||||
|
|
||||||
|
return irInvoke(
|
||||||
|
irGet(propertyGetter.returnType, irGet(thisParam), propertyGetter.symbol),
|
||||||
|
valueGetter,
|
||||||
|
typeHint = type
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irInvoke(
|
||||||
|
dispatchReceiver: IrExpression? = null,
|
||||||
|
callee: IrFunctionSymbol,
|
||||||
|
vararg args: IrExpression,
|
||||||
|
typeHint: IrType? = null
|
||||||
|
): IrMemberAccessExpression<*> {
|
||||||
|
assert(callee.isBound) { "Symbol $callee expected to be bound" }
|
||||||
|
val returnType = typeHint ?: callee.owner.returnType
|
||||||
|
val call = irCall(callee, type = returnType)
|
||||||
|
call.dispatchReceiver = dispatchReceiver
|
||||||
|
args.forEachIndexed(call::putValueArgument)
|
||||||
|
return call
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irInvoke(
|
||||||
|
dispatchReceiver: IrExpression? = null,
|
||||||
|
callee: IrFunctionSymbol,
|
||||||
|
typeArguments: List<IrType?>,
|
||||||
|
valueArguments: List<IrExpression>,
|
||||||
|
returnTypeHint: IrType? = null
|
||||||
|
): IrMemberAccessExpression<*> =
|
||||||
|
irInvoke(
|
||||||
|
dispatchReceiver,
|
||||||
|
callee,
|
||||||
|
*valueArguments.toTypedArray(),
|
||||||
|
typeHint = returnTypeHint
|
||||||
|
).also { call -> typeArguments.forEachIndexed(call::putTypeArgument) }
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.createArrayOfExpression(
|
||||||
|
arrayElementType: IrType,
|
||||||
|
arrayElements: List<IrExpression>
|
||||||
|
): IrExpression {
|
||||||
|
|
||||||
|
val arrayType = compilerContext.irBuiltIns.arrayClass.typeWith(arrayElementType)
|
||||||
|
val arg0 = IrVarargImpl(startOffset, endOffset, arrayType, arrayElementType, arrayElements)
|
||||||
|
val typeArguments = listOf(arrayElementType)
|
||||||
|
|
||||||
|
return irCall(compilerContext.irBuiltIns.arrayOf, arrayType, typeArguments = typeArguments).apply {
|
||||||
|
putValueArgument(0, arg0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.createPrimitiveArrayOfExpression(
|
||||||
|
elementPrimitiveType: IrType,
|
||||||
|
arrayElements: List<IrExpression>
|
||||||
|
): IrExpression {
|
||||||
|
val arrayType = compilerContext.irBuiltIns.primitiveArrayForType.getValue(elementPrimitiveType).defaultType
|
||||||
|
val arg0 = IrVarargImpl(startOffset, endOffset, arrayType, elementPrimitiveType, arrayElements)
|
||||||
|
val typeArguments = listOf(elementPrimitiveType)
|
||||||
|
|
||||||
|
return irCall(compilerContext.irBuiltIns.arrayOf, arrayType, typeArguments = typeArguments).apply {
|
||||||
|
putValueArgument(0, arg0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irBinOp(name: Name, lhs: IrExpression, rhs: IrExpression): IrExpression {
|
||||||
|
val classFqName = (lhs.type as IrSimpleType).classOrNull!!.owner.fqNameWhenAvailable!!
|
||||||
|
val symbol = compilerContext.referenceFunctions(CallableId(ClassId.topLevel(classFqName), name)).single()
|
||||||
|
return irInvoke(lhs, symbol, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irGetObject(irObject: IrClass) =
|
||||||
|
IrGetObjectValueImpl(
|
||||||
|
startOffset,
|
||||||
|
endOffset,
|
||||||
|
irObject.defaultType,
|
||||||
|
irObject.symbol
|
||||||
|
)
|
||||||
|
|
||||||
|
fun <T : IrDeclaration> T.buildWithScope(builder: (T) -> Unit): T =
|
||||||
|
also { irDeclaration ->
|
||||||
|
compilerContext.symbolTable.withReferenceScope(irDeclaration) {
|
||||||
|
builder(irDeclaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BranchBuilder(
|
||||||
|
val irWhen: IrWhen,
|
||||||
|
context: IrGeneratorContext,
|
||||||
|
scope: Scope,
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int
|
||||||
|
) : IrBuilderWithScope(context, scope, startOffset, endOffset) {
|
||||||
|
operator fun IrBranch.unaryPlus() {
|
||||||
|
irWhen.branches.add(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irWhen(typeHint: IrType? = null, block: BranchBuilder.() -> Unit): IrWhen {
|
||||||
|
val whenExpr = IrWhenImpl(startOffset, endOffset, typeHint ?: compilerContext.irBuiltIns.unitType)
|
||||||
|
val builder = BranchBuilder(whenExpr, context, scope, startOffset, endOffset)
|
||||||
|
builder.block()
|
||||||
|
return whenExpr
|
||||||
|
}
|
||||||
|
|
||||||
|
fun BranchBuilder.elseBranch(result: IrExpression): IrElseBranch =
|
||||||
|
IrElseBranchImpl(
|
||||||
|
IrConstImpl.boolean(result.startOffset, result.endOffset, compilerContext.irBuiltIns.booleanType, true),
|
||||||
|
result
|
||||||
|
)
|
||||||
|
|
||||||
|
@FirIncompatiblePluginAPI
|
||||||
|
fun KotlinType.toIrType() = compilerContext.typeTranslator.translateType(this)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.setProperty(receiver: IrExpression, property: IrProperty, value: IrExpression): IrExpression {
|
||||||
|
return if (property.setter != null)
|
||||||
|
irSet(property.setter!!.returnType, receiver, property.setter!!.symbol, value)
|
||||||
|
else
|
||||||
|
irSetField(receiver, property.backingField!!, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.generateAnySuperConstructorCall(toBuilder: IrBlockBodyBuilder) {
|
||||||
|
val anyConstructor = compilerContext.irBuiltIns.anyClass.owner.declarations.single { it is IrConstructor } as IrConstructor
|
||||||
|
with(toBuilder) {
|
||||||
|
+IrDelegatingConstructorCallImpl.fromSymbolDescriptor(
|
||||||
|
startOffset, endOffset,
|
||||||
|
compilerContext.irBuiltIns.unitType,
|
||||||
|
anyConstructor.symbol
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <reified T : IrDeclaration> IrClass.searchForDeclaration(descriptor: DeclarationDescriptor): T? {
|
||||||
|
return declarations.singleOrNull { it.descriptor == descriptor } as? T
|
||||||
|
}
|
||||||
|
|
||||||
|
fun generateSimplePropertyWithBackingField(
|
||||||
|
propertyDescriptor: PropertyDescriptor,
|
||||||
|
propertyParent: IrClass,
|
||||||
|
fieldName: Name = propertyDescriptor.name,
|
||||||
|
): IrProperty {
|
||||||
|
val irProperty = propertyParent.searchForDeclaration(propertyDescriptor) ?: run {
|
||||||
|
with(propertyDescriptor) {
|
||||||
|
propertyParent.factory.createProperty(
|
||||||
|
propertyParent.startOffset, propertyParent.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrPropertySymbolImpl(propertyDescriptor),
|
||||||
|
name, visibility, modality, isVar, isConst, isLateInit, isDelegated, isExternal
|
||||||
|
).also {
|
||||||
|
it.parent = propertyParent
|
||||||
|
propertyParent.addMember(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
propertyParent.generatePropertyBackingFieldIfNeeded(propertyDescriptor, irProperty, fieldName)
|
||||||
|
val fieldSymbol = irProperty.backingField!!.symbol
|
||||||
|
irProperty.getter = propertyDescriptor.getter?.let {
|
||||||
|
propertyParent.generatePropertyAccessor(propertyDescriptor, irProperty, it, fieldSymbol, isGetter = true)
|
||||||
|
}?.apply { parent = propertyParent }
|
||||||
|
irProperty.setter = propertyDescriptor.setter?.let {
|
||||||
|
propertyParent.generatePropertyAccessor(propertyDescriptor, irProperty, it, fieldSymbol, isGetter = false)
|
||||||
|
}?.apply { parent = propertyParent }
|
||||||
|
return irProperty
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrType.kClassToJClassIfNeeded(): IrType = this
|
||||||
|
|
||||||
|
fun kClassExprToJClassIfNeeded(startOffset: Int, endOffset: Int, irExpression: IrExpression): IrExpression = irExpression
|
||||||
|
|
||||||
|
private fun IrClass.generatePropertyBackingFieldIfNeeded(
|
||||||
|
propertyDescriptor: PropertyDescriptor,
|
||||||
|
originProperty: IrProperty,
|
||||||
|
name: Name,
|
||||||
|
) {
|
||||||
|
if (originProperty.backingField != null) return
|
||||||
|
|
||||||
|
val field = with(propertyDescriptor) {
|
||||||
|
@OptIn(FirIncompatiblePluginAPI::class)// should be called only with old FE
|
||||||
|
originProperty.factory.createField(
|
||||||
|
originProperty.startOffset, originProperty.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrFieldSymbolImpl(propertyDescriptor), name, type.toIrType(),
|
||||||
|
visibility, !isVar, isEffectivelyExternal(), dispatchReceiverParameter == null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
field.apply {
|
||||||
|
parent = this@generatePropertyBackingFieldIfNeeded
|
||||||
|
correspondingPropertySymbol = originProperty.symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
originProperty.backingField = field
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrClass.generatePropertyAccessor(
|
||||||
|
propertyDescriptor: PropertyDescriptor,
|
||||||
|
property: IrProperty,
|
||||||
|
descriptor: PropertyAccessorDescriptor,
|
||||||
|
fieldSymbol: IrFieldSymbol,
|
||||||
|
isGetter: Boolean,
|
||||||
|
): IrSimpleFunction {
|
||||||
|
val irAccessor: IrSimpleFunction = when (isGetter) {
|
||||||
|
true -> searchForDeclaration<IrProperty>(propertyDescriptor)?.getter
|
||||||
|
false -> searchForDeclaration<IrProperty>(propertyDescriptor)?.setter
|
||||||
|
} ?: run {
|
||||||
|
with(descriptor) {
|
||||||
|
@OptIn(FirIncompatiblePluginAPI::class) // should never be called after FIR frontend
|
||||||
|
property.factory.createFunction(
|
||||||
|
fieldSymbol.owner.startOffset, fieldSymbol.owner.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrSimpleFunctionSymbolImpl(descriptor),
|
||||||
|
name, visibility, modality, returnType!!.toIrType(),
|
||||||
|
isInline, isEffectivelyExternal(), isTailrec, isSuspend, isOperator, isInfix, isExpect
|
||||||
|
)
|
||||||
|
}.also { f ->
|
||||||
|
generateOverriddenFunctionSymbols(f, compilerContext.symbolTable)
|
||||||
|
f.createParameterDeclarations(descriptor)
|
||||||
|
@OptIn(FirIncompatiblePluginAPI::class) // should never be called after FIR frontend
|
||||||
|
f.returnType = descriptor.returnType!!.toIrType()
|
||||||
|
f.correspondingPropertySymbol = fieldSymbol.owner.correspondingPropertySymbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
irAccessor.body = when (isGetter) {
|
||||||
|
true -> generateDefaultGetterBody(irAccessor)
|
||||||
|
false -> generateDefaultSetterBody(irAccessor)
|
||||||
|
}
|
||||||
|
|
||||||
|
return irAccessor
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateDefaultGetterBody(
|
||||||
|
irAccessor: IrSimpleFunction
|
||||||
|
): IrBlockBody {
|
||||||
|
val irProperty = irAccessor.correspondingPropertySymbol?.owner ?: error("Expected corresponding property for accessor ${irAccessor.render()}")
|
||||||
|
|
||||||
|
val startOffset = irAccessor.startOffset
|
||||||
|
val endOffset = irAccessor.endOffset
|
||||||
|
val irBody = irAccessor.factory.createBlockBody(startOffset, endOffset)
|
||||||
|
|
||||||
|
val receiver = generateReceiverExpressionForFieldAccess(irAccessor.dispatchReceiverParameter!!.symbol)
|
||||||
|
|
||||||
|
val propertyIrType = irAccessor.returnType
|
||||||
|
irBody.statements.add(
|
||||||
|
IrReturnImpl(
|
||||||
|
startOffset, endOffset, compilerContext.irBuiltIns.nothingType,
|
||||||
|
irAccessor.symbol,
|
||||||
|
IrGetFieldImpl(
|
||||||
|
startOffset, endOffset,
|
||||||
|
irProperty.backingField?.symbol ?: error("Property expected to have backing field"),
|
||||||
|
propertyIrType,
|
||||||
|
receiver
|
||||||
|
).let {
|
||||||
|
if (propertyIrType.isKClass()) {
|
||||||
|
irAccessor.returnType = irAccessor.returnType.kClassToJClassIfNeeded()
|
||||||
|
kClassExprToJClassIfNeeded(startOffset, endOffset, it)
|
||||||
|
} else it
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return irBody
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateDefaultSetterBody(
|
||||||
|
irAccessor: IrSimpleFunction
|
||||||
|
): IrBlockBody {
|
||||||
|
val irProperty = irAccessor.correspondingPropertySymbol?.owner ?: error("Expected corresponding property for accessor ${irAccessor.render()}")
|
||||||
|
val startOffset = irAccessor.startOffset
|
||||||
|
val endOffset = irAccessor.endOffset
|
||||||
|
val irBody = irAccessor.factory.createBlockBody(startOffset, endOffset)
|
||||||
|
|
||||||
|
val receiver = generateReceiverExpressionForFieldAccess(irAccessor.dispatchReceiverParameter!!.symbol)
|
||||||
|
|
||||||
|
val irValueParameter = irAccessor.valueParameters.single()
|
||||||
|
irBody.statements.add(
|
||||||
|
IrSetFieldImpl(
|
||||||
|
startOffset, endOffset,
|
||||||
|
irProperty.backingField?.symbol ?: error("Property ${irProperty.render()} expected to have backing field"),
|
||||||
|
receiver,
|
||||||
|
IrGetValueImpl(startOffset, endOffset, irValueParameter.type, irValueParameter.symbol),
|
||||||
|
compilerContext.irBuiltIns.unitType
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return irBody
|
||||||
|
}
|
||||||
|
|
||||||
|
fun generateReceiverExpressionForFieldAccess(
|
||||||
|
ownerSymbol: IrValueSymbol
|
||||||
|
): IrExpression = IrGetValueImpl(
|
||||||
|
ownerSymbol.owner.startOffset, ownerSymbol.owner.endOffset,
|
||||||
|
ownerSymbol
|
||||||
|
)
|
||||||
|
|
||||||
|
fun IrFunction.createParameterDeclarations(
|
||||||
|
descriptor: FunctionDescriptor,
|
||||||
|
overwriteValueParameters: Boolean = false,
|
||||||
|
copyTypeParameters: Boolean = true
|
||||||
|
) {
|
||||||
|
val function = this
|
||||||
|
fun irValueParameter(descriptor: ParameterDescriptor): IrValueParameter = with(descriptor) {
|
||||||
|
@OptIn(FirIncompatiblePluginAPI::class) // should never be called after FIR frontend
|
||||||
|
factory.createValueParameter(
|
||||||
|
function.startOffset, function.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrValueParameterSymbolImpl(this),
|
||||||
|
name, indexOrMinusOne, type.toIrType(), varargElementType?.toIrType(), isCrossinline, isNoinline,
|
||||||
|
isHidden = false, isAssignable = false
|
||||||
|
).also {
|
||||||
|
it.parent = function
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copyTypeParameters) {
|
||||||
|
assert(typeParameters.isEmpty())
|
||||||
|
copyTypeParamsFromDescriptor(descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchReceiverParameter = descriptor.dispatchReceiverParameter?.let { irValueParameter(it) }
|
||||||
|
extensionReceiverParameter = descriptor.extensionReceiverParameter?.let { irValueParameter(it) }
|
||||||
|
|
||||||
|
if (!overwriteValueParameters)
|
||||||
|
assert(valueParameters.isEmpty())
|
||||||
|
|
||||||
|
valueParameters = descriptor.valueParameters.map { irValueParameter(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrFunction.copyTypeParamsFromDescriptor(descriptor: FunctionDescriptor) {
|
||||||
|
val newTypeParameters = descriptor.typeParameters.map {
|
||||||
|
factory.createTypeParameter(
|
||||||
|
startOffset, endOffset,
|
||||||
|
SERIALIZABLE_PLUGIN_ORIGIN,
|
||||||
|
IrTypeParameterSymbolImpl(it),
|
||||||
|
it.name, it.index, it.isReified, it.variance
|
||||||
|
).also { typeParameter ->
|
||||||
|
typeParameter.parent = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@OptIn(FirIncompatiblePluginAPI::class) // should never be called after FIR frontend
|
||||||
|
newTypeParameters.forEach { typeParameter ->
|
||||||
|
typeParameter.superTypes = typeParameter.descriptor.upperBounds.map { it.toIrType() }
|
||||||
|
}
|
||||||
|
|
||||||
|
typeParameters = newTypeParameters
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createClassReference(classType: IrType, startOffset: Int, endOffset: Int): IrClassReference {
|
||||||
|
return IrClassReferenceImpl(
|
||||||
|
startOffset,
|
||||||
|
endOffset,
|
||||||
|
compilerContext.irBuiltIns.kClassClass.starProjectedType,
|
||||||
|
classType.classifierOrFail,
|
||||||
|
classType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.classReference(classSymbol: IrType): IrClassReference =
|
||||||
|
createClassReference(classSymbol, startOffset, endOffset)
|
||||||
|
|
||||||
|
fun collectSerialInfoAnnotations(irClass: IrClass): List<IrConstructorCall> {
|
||||||
|
if (!(irClass.isInterface || irClass.descriptor.hasSerializableOrMetaAnnotation)) return emptyList()
|
||||||
|
val annotationByFq: MutableMap<FqName, IrConstructorCall> =
|
||||||
|
irClass.annotations.associateBy { it.symbol.owner.parentAsClass.descriptor.fqNameSafe }.toMutableMap()
|
||||||
|
for (clazz in irClass.getAllSuperclasses()) {
|
||||||
|
val annotations = clazz.annotations
|
||||||
|
.mapNotNull {
|
||||||
|
val descriptor = it.symbol.owner.parentAsClass.descriptor
|
||||||
|
if (descriptor.isInheritableSerialInfoAnnotation) descriptor.fqNameSafe to it else null
|
||||||
|
}
|
||||||
|
annotations.forEach { (fqname, call) ->
|
||||||
|
if (fqname !in annotationByFq) {
|
||||||
|
annotationByFq[fqname] = call
|
||||||
|
} else {
|
||||||
|
// SerializationPluginDeclarationChecker already reported inconsistency
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return annotationByFq.values.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.copyAnnotationsFrom(annotations: List<IrConstructorCall>): List<IrExpression> =
|
||||||
|
annotations.mapNotNull { annotationCall ->
|
||||||
|
val annotationClass = annotationCall.symbol.owner.parentAsClass
|
||||||
|
if (!annotationClass.descriptor.isSerialInfoAnnotation) return@mapNotNull null
|
||||||
|
|
||||||
|
if (compilerContext.platform.isJvm()) {
|
||||||
|
val implClass = compilerContext.serialInfoImplJvmIrGenerator.getImplClass(annotationClass)
|
||||||
|
val ctor = implClass.constructors.singleOrNull { it.valueParameters.size == annotationCall.valueArgumentsCount }
|
||||||
|
?: error("No constructor args found for SerialInfo annotation Impl class: ${implClass.render()}")
|
||||||
|
irCall(ctor).apply {
|
||||||
|
for (i in 0 until annotationCall.valueArgumentsCount) {
|
||||||
|
val argument = annotationCall.getValueArgument(i)
|
||||||
|
?: annotationClass.primaryConstructor!!.valueParameters[i].defaultValue?.expression
|
||||||
|
putValueArgument(i, argument!!.deepCopyWithVariables())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
annotationCall.deepCopyWithVariables()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.wrapperClassReference(classType: IrType): IrClassReference {
|
||||||
|
if (compilerContext.platform.isJvm()) {
|
||||||
|
// "Byte::class" -> "java.lang.Byte::class"
|
||||||
|
// TODO: get rid of descriptor
|
||||||
|
val wrapperFqName = KotlinBuiltIns.getPrimitiveType(classType.classOrNull!!.descriptor)?.let(JvmPrimitiveType::get)?.wrapperFqName
|
||||||
|
if (wrapperFqName != null) {
|
||||||
|
val wrapperClass = compilerContext.referenceClass(ClassId.topLevel(wrapperFqName))
|
||||||
|
?: error("Primitive wrapper class for $classType not found: $wrapperFqName")
|
||||||
|
return classReference(wrapperClass.defaultType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return classReference(classType)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrClass.getSuperClassOrAny(): IrClass = getSuperClassNotAny() ?: compilerContext.irBuiltIns.anyClass.owner
|
||||||
|
}
|
||||||
+202
@@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 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.backend.jvm.ir.getStringConstArgument
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrGetEnumValue
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.fir.SerializationPluginKey
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages
|
||||||
|
|
||||||
|
internal fun IrType.isKSerializer(): Boolean {
|
||||||
|
val simpleType = this as? IrSimpleType ?: return false
|
||||||
|
val classifier = simpleType.classifier as? IrClassSymbol ?: return false
|
||||||
|
val fqName = classifier.owner.fqNameWhenAvailable
|
||||||
|
return fqName == SerialEntityNames.KSERIALIZER_NAME_FQ || fqName == SerialEntityNames.GENERATED_SERIALIZER_FQ
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val IrClass.isInternalSerializable: Boolean
|
||||||
|
get() {
|
||||||
|
if (kind != ClassKind.CLASS) return false
|
||||||
|
return hasSerializableOrMetaAnnotationWithoutArgs()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val IrClass.isAbstractOrSealedSerializableClass: Boolean get() = isInternalSerializable && (modality == Modality.ABSTRACT || modality == Modality.SEALED)
|
||||||
|
|
||||||
|
internal val IrClass.isStaticSerializable: Boolean get() = this.typeParameters.isEmpty()
|
||||||
|
|
||||||
|
|
||||||
|
internal val IrClass.hasCompanionObjectAsSerializer: Boolean
|
||||||
|
get() = isInternallySerializableObject || companionObject()?.serializerForClass == this.symbol
|
||||||
|
|
||||||
|
internal val IrClass.isInternallySerializableObject: Boolean
|
||||||
|
get() = kind == ClassKind.OBJECT && hasSerializableOrMetaAnnotationWithoutArgs()
|
||||||
|
|
||||||
|
|
||||||
|
internal fun IrClass.findPluginGeneratedMethod(name: String): IrSimpleFunction? {
|
||||||
|
return this.functions.find {
|
||||||
|
it.name.asString() == name && it.isFromPlugin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun IrClass.isEnumWithLegacyGeneratedSerializer(): Boolean = isInternallySerializableEnum() && useGeneratedEnumSerializer
|
||||||
|
|
||||||
|
internal val IrClass.useGeneratedEnumSerializer: Boolean
|
||||||
|
get() = true // FIXME This would break if we try to use this new IR compiler with pre-1.4.1 serialization versions. I think we just need to raise min runtime version.
|
||||||
|
|
||||||
|
internal val IrClass.isSealedSerializableInterface: Boolean
|
||||||
|
get() = kind == ClassKind.INTERFACE && modality == Modality.SEALED && hasSerializableOrMetaAnnotation()
|
||||||
|
|
||||||
|
internal fun IrClass.isInternallySerializableEnum(): Boolean =
|
||||||
|
kind == ClassKind.ENUM_CLASS && hasSerializableOrMetaAnnotationWithoutArgs()
|
||||||
|
|
||||||
|
fun IrType.isGeneratedSerializableObject(): Boolean {
|
||||||
|
return classOrNull?.run { owner.kind == ClassKind.OBJECT && owner.hasSerializableOrMetaAnnotationWithoutArgs() } == true
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val IrClass.isSerializableObject: Boolean
|
||||||
|
get() = kind == ClassKind.OBJECT && hasSerializableOrMetaAnnotation()
|
||||||
|
|
||||||
|
internal fun IrClass.hasSerializableOrMetaAnnotationWithoutArgs(): Boolean = checkSerializableOrMetaAnnotationArgs(mustDoNotHaveArgs = true)
|
||||||
|
|
||||||
|
fun IrClass.hasSerializableOrMetaAnnotation() = checkSerializableOrMetaAnnotationArgs(mustDoNotHaveArgs = false)
|
||||||
|
|
||||||
|
private fun IrClass.checkSerializableOrMetaAnnotationArgs(mustDoNotHaveArgs: Boolean): Boolean {
|
||||||
|
val annot = getAnnotation(SerializationAnnotations.serializableAnnotationFqName)
|
||||||
|
if (annot != null) { // @Serializable have higher priority
|
||||||
|
if (!mustDoNotHaveArgs) return true
|
||||||
|
if (annot.getValueArgument(0) != null) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return annotations
|
||||||
|
.map { it.annotationClass.annotations }
|
||||||
|
.any { it.hasAnnotation(SerializationAnnotations.metaSerializableAnnotationFqName) }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val IrClass.isSerialInfoAnnotation: Boolean
|
||||||
|
get() = annotations.hasAnnotation(SerializationAnnotations.serialInfoFqName)
|
||||||
|
|| annotations.hasAnnotation(SerializationAnnotations.inheritableSerialInfoFqName)
|
||||||
|
|| annotations.hasAnnotation(SerializationAnnotations.metaSerializableAnnotationFqName)
|
||||||
|
|
||||||
|
internal val IrClass.shouldHaveGeneratedSerializer: Boolean
|
||||||
|
get() = (isInternalSerializable && (modality == Modality.FINAL || modality == Modality.OPEN))
|
||||||
|
|| isEnumWithLegacyGeneratedSerializer()
|
||||||
|
|
||||||
|
internal val IrClass.shouldHaveGeneratedMethodsInCompanion: Boolean
|
||||||
|
get() = this.isSerializableObject || this.isSerializableEnum() || (this.kind == ClassKind.CLASS && hasSerializableOrMetaAnnotation()) || this.isSealedSerializableInterface
|
||||||
|
|
||||||
|
internal fun IrClass.isSerializableEnum(): Boolean = kind == ClassKind.ENUM_CLASS && hasSerializableOrMetaAnnotation()
|
||||||
|
|
||||||
|
internal val IrType.genericIndex: Int?
|
||||||
|
get() = (this.classifierOrNull as? IrTypeParameterSymbol)?.owner?.index
|
||||||
|
|
||||||
|
fun IrType.serialName(): String = this.classOrNull!!.owner.serialName()
|
||||||
|
|
||||||
|
fun IrClass.serialName(): String {
|
||||||
|
return annotations.serialNameValue ?: fqNameWhenAvailable?.asString() ?: error("${this.render()} does not have fqName")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrClass.findEnumValuesMethod() = this.functions.singleOrNull { f ->
|
||||||
|
f.name == Name.identifier("values") && f.valueParameters.isEmpty() && f.extensionReceiverParameter == null
|
||||||
|
} ?: throw AssertionError("Enum class does not have single .values() function")
|
||||||
|
|
||||||
|
internal fun IrClass.enumEntries(): List<IrEnumEntry> {
|
||||||
|
check(this.kind == ClassKind.ENUM_CLASS)
|
||||||
|
return declarations.filterIsInstance<IrEnumEntry>().toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun IrClass.isEnumWithSerialInfoAnnotation(): Boolean {
|
||||||
|
if (kind != ClassKind.ENUM_CLASS) return false
|
||||||
|
if (annotations.hasAnySerialAnnotation) return true
|
||||||
|
return enumEntries().any { (it.annotations.hasAnySerialAnnotation) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrClass.findWriteSelfMethod(): IrSimpleFunction? =
|
||||||
|
functions.singleOrNull { it.name == SerialEntityNames.WRITE_SELF_NAME && !it.isFakeOverride }
|
||||||
|
|
||||||
|
fun IrClass.getSuperClassNotAny(): IrClass? {
|
||||||
|
val parentClass =
|
||||||
|
superTypes
|
||||||
|
.mapNotNull { it.classOrNull?.owner }
|
||||||
|
.singleOrNull { it.kind == ClassKind.CLASS || it.kind == ClassKind.ENUM_CLASS } ?: return null
|
||||||
|
return if (parentClass.defaultType.isAny()) null else parentClass
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun IrDeclaration.isFromPlugin(): Boolean =
|
||||||
|
this.origin == IrDeclarationOrigin.GeneratedByPlugin(SerializationPluginKey) || (this.descriptor as? CallableMemberDescriptor)?.kind == CallableMemberDescriptor.Kind.SYNTHESIZED // old FE doesn't specify origin
|
||||||
|
|
||||||
|
internal fun IrConstructor.isSerializationCtor(): Boolean {
|
||||||
|
/*kind == CallableMemberDescriptor.Kind.SYNTHESIZED does not work because DeserializedClassConstructorDescriptor loses its kind*/
|
||||||
|
return valueParameters.lastOrNull()?.run {
|
||||||
|
name == SerialEntityNames.dummyParamName && type.classFqName == SerializationPackages.internalPackageFqName.child(
|
||||||
|
SerialEntityNames.SERIAL_CTOR_MARKER_NAME
|
||||||
|
)
|
||||||
|
} == true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal fun IrConstructor.lastArgumentIsAnnotationArray(): Boolean {
|
||||||
|
val lastArgType = valueParameters.lastOrNull()?.type
|
||||||
|
if (lastArgType == null || !lastArgType.isArray()) return false
|
||||||
|
return ((lastArgType as? IrSimpleType)?.arguments?.firstOrNull()?.typeOrNull?.classFqName?.toString() == "kotlin.Annotation")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrClass.serializableSyntheticConstructor(): IrConstructorSymbol? { // FIXME: remove nullability W/A when FIR plugin will add proper deserialization ctor
|
||||||
|
return declarations.filterIsInstance<IrConstructor>().singleOrNull { it.isSerializationCtor() }?.symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun IrExpression.isInitializePropertyFromParameter(): Boolean =
|
||||||
|
this is IrGetValueImpl && this.origin == IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER
|
||||||
|
|
||||||
|
internal val IrConstructorCall.annotationClass
|
||||||
|
get() = this.symbol.owner.constructedClass
|
||||||
|
|
||||||
|
internal val List<IrConstructorCall>.hasAnySerialAnnotation: Boolean
|
||||||
|
get() = serialNameValue != null || any { it.annotationClass.isSerialInfoAnnotation == true }
|
||||||
|
|
||||||
|
internal val List<IrConstructorCall>.serialNameValue: String?
|
||||||
|
get() = findAnnotation(SerializationAnnotations.serialNameAnnotationFqName)?.getStringConstArgument(0) // @SerialName("foo")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True — ALWAYS
|
||||||
|
* False — NEVER
|
||||||
|
* null — not specified
|
||||||
|
*/
|
||||||
|
fun IrProperty.getEncodeDefaultAnnotationValue(): Boolean? {
|
||||||
|
val call = annotations.findAnnotation(SerializationAnnotations.encodeDefaultFqName) ?: return null
|
||||||
|
val arg = call.getValueArgument(0) ?: return true // ALWAYS by default
|
||||||
|
val argValue = (arg as? IrGetEnumValue
|
||||||
|
?: error("Argument of enum constructor expected to implement IrGetEnumValue, got $arg")).symbol.owner.name.toString()
|
||||||
|
return when (argValue) {
|
||||||
|
"ALWAYS" -> true
|
||||||
|
"NEVER" -> false
|
||||||
|
else -> error("Unknown EncodeDefaultMode enum value: $argValue")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findSerializerConstructorForTypeArgumentsSerializers(serializer: IrClass): IrConstructorSymbol? {
|
||||||
|
val typeParamsCount = ((serializer.superTypes.find { it.isKSerializer() } as IrSimpleType).arguments.first().typeOrNull!! as IrSimpleType).arguments.size
|
||||||
|
if (typeParamsCount == 0) return null //don't need it
|
||||||
|
|
||||||
|
return serializer.constructors.singleOrNull {
|
||||||
|
it.valueParameters.let { vps -> vps.size == typeParamsCount && vps.all { vp -> vp.type.isKSerializer() } }
|
||||||
|
}?.symbol
|
||||||
|
}
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 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.DescriptorVisibilities
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||||
|
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||||
|
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||||
|
import org.jetbrains.kotlin.ir.util.hasDefaultValue
|
||||||
|
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
||||||
|
import org.jetbrains.kotlin.ir.util.properties
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||||
|
|
||||||
|
class IrSerializableProperty(
|
||||||
|
val ir: IrProperty,
|
||||||
|
override val isConstructorParameterWithDefault: Boolean,
|
||||||
|
hasBackingField: Boolean,
|
||||||
|
declaresDefaultValue: Boolean
|
||||||
|
) : ISerializableProperty {
|
||||||
|
override val name = ir.annotations.serialNameValue ?: ir.name.asString()
|
||||||
|
override val originalDescriptorName: Name = ir.name
|
||||||
|
val type = ir.getter!!.returnType as IrSimpleType
|
||||||
|
val genericIndex = type.genericIndex
|
||||||
|
fun serializableWith(ctx: SerializationPluginContext) = ir.annotations.serializableWith() ?: analyzeSpecialSerializers(ctx, ir.annotations)
|
||||||
|
override val optional = !ir.annotations.hasAnnotation(SerializationAnnotations.requiredAnnotationFqName) && declaresDefaultValue
|
||||||
|
override val transient = ir.annotations.hasAnnotation(SerializationAnnotations.serialTransientFqName) || !hasBackingField
|
||||||
|
}
|
||||||
|
|
||||||
|
class IrSerializableProperties(
|
||||||
|
override val serializableProperties: List<IrSerializableProperty>,
|
||||||
|
override val isExternallySerializable: Boolean,
|
||||||
|
override val serializableConstructorProperties: List<IrSerializableProperty>,
|
||||||
|
override val serializableStandaloneProperties: List<IrSerializableProperty>
|
||||||
|
) : ISerializableProperties<IrSerializableProperty>
|
||||||
|
|
||||||
|
internal fun serializablePropertiesForIrBackend(
|
||||||
|
irClass: IrClass,
|
||||||
|
serializationDescriptorSerializer: SerializationDescriptorSerializerPlugin? = null
|
||||||
|
): IrSerializableProperties {
|
||||||
|
val properties = irClass.properties.toList()
|
||||||
|
val primaryConstructorParams = irClass.primaryConstructor?.valueParameters.orEmpty()
|
||||||
|
val primaryParamsAsProps = properties.associateBy { it.name }.let { namesMap ->
|
||||||
|
primaryConstructorParams.mapNotNull {
|
||||||
|
if (it.name !in namesMap) null else namesMap.getValue(it.name) to it.hasDefaultValue()
|
||||||
|
}.toMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isPropSerializable(it: IrProperty) =
|
||||||
|
if (irClass.isInternalSerializable) !it.annotations.hasAnnotation(SerializationAnnotations.serialTransientFqName)
|
||||||
|
else !DescriptorVisibilities.isPrivate(it.visibility) && ((it.isVar && !it.annotations.hasAnnotation(SerializationAnnotations.serialTransientFqName)) || primaryParamsAsProps.contains(
|
||||||
|
it
|
||||||
|
))
|
||||||
|
|
||||||
|
val (primaryCtorSerializableProps, bodySerializableProps) = properties
|
||||||
|
.asSequence()
|
||||||
|
.filter { !it.isFakeOverride && !it.isDelegated }
|
||||||
|
.filter(::isPropSerializable)
|
||||||
|
.map {
|
||||||
|
val isConstructorParameterWithDefault = primaryParamsAsProps[it] ?: false
|
||||||
|
// FIXME: workaround because IrLazyProperty doesn't deserialize information about backing fields. Fallback to descriptor won't work with FIR.
|
||||||
|
val isPropertyFromAnotherModuleDeclaresDefaultValue = it.descriptor is DeserializedPropertyDescriptor && it.descriptor.declaresDefaultValue()
|
||||||
|
val isPropertyWithBackingFieldFromAnotherModule = it.descriptor is DeserializedPropertyDescriptor && (it.descriptor.backingField != null || isPropertyFromAnotherModuleDeclaresDefaultValue)
|
||||||
|
IrSerializableProperty(
|
||||||
|
it,
|
||||||
|
isConstructorParameterWithDefault,
|
||||||
|
it.backingField != null || isPropertyWithBackingFieldFromAnotherModule,
|
||||||
|
it.backingField?.initializer.let { init -> init != null && !init.expression.isInitializePropertyFromParameter() } || isConstructorParameterWithDefault
|
||||||
|
|| isPropertyFromAnotherModuleDeclaresDefaultValue
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.filterNot { it.transient }
|
||||||
|
.partition { primaryParamsAsProps.contains(it.ir) }
|
||||||
|
|
||||||
|
var serializableProps = run {
|
||||||
|
val supers = irClass.getSuperClassNotAny()
|
||||||
|
if (supers == null || !supers.isInternalSerializable)
|
||||||
|
primaryCtorSerializableProps + bodySerializableProps
|
||||||
|
else
|
||||||
|
serializablePropertiesForIrBackend(
|
||||||
|
supers,
|
||||||
|
serializationDescriptorSerializer
|
||||||
|
).serializableProperties + primaryCtorSerializableProps + bodySerializableProps
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: since descriptor from FIR does not have classProto in it(?), this line won't do anything
|
||||||
|
serializableProps = restoreCorrectOrderFromClassProtoExtension(irClass.descriptor, serializableProps)
|
||||||
|
|
||||||
|
val isExternallySerializable =
|
||||||
|
irClass.isInternallySerializableEnum() || primaryConstructorParams.size == primaryParamsAsProps.size
|
||||||
|
|
||||||
|
return IrSerializableProperties(serializableProps, isExternallySerializable, primaryCtorSerializableProps, bodySerializableProps)
|
||||||
|
}
|
||||||
+1
-1
@@ -42,7 +42,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
|
|||||||
class SerialInfoImplJvmIrGenerator(
|
class SerialInfoImplJvmIrGenerator(
|
||||||
private val context: SerializationPluginContext,
|
private val context: SerializationPluginContext,
|
||||||
private val moduleFragment: IrModuleFragment,
|
private val moduleFragment: IrModuleFragment,
|
||||||
) : IrBuilderExtension {
|
) : IrBuilderWithPluginContext {
|
||||||
override val compilerContext: SerializationPluginContext
|
override val compilerContext: SerializationPluginContext
|
||||||
get() = context
|
get() = context
|
||||||
|
|
||||||
|
|||||||
+27
-35
@@ -6,7 +6,6 @@
|
|||||||
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
||||||
import org.jetbrains.kotlin.ir.builders.irGet
|
import org.jetbrains.kotlin.ir.builders.irGet
|
||||||
import org.jetbrains.kotlin.ir.builders.irInt
|
import org.jetbrains.kotlin.ir.builders.irInt
|
||||||
@@ -21,41 +20,37 @@ import org.jetbrains.kotlin.ir.util.*
|
|||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.AbstractIrGenerator
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerializableClassByCompanion
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.isKSerializer
|
|
||||||
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.SerialEntityNames
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.needSerializerFactory
|
||||||
|
|
||||||
class SerializableCompanionIrGenerator(
|
class SerializableCompanionIrGenerator(
|
||||||
val irClass: IrClass,
|
val irClass: IrClass,
|
||||||
val serializableIrClass: IrClass,
|
val serializableIrClass: IrClass,
|
||||||
override val compilerContext: SerializationPluginContext,
|
compilerContext: SerializationPluginContext,
|
||||||
) : AbstractIrGenerator(irClass), IrBuilderExtension {
|
) : BaseIrGenerator(irClass, compilerContext) {
|
||||||
|
|
||||||
private val serializableDescriptor = serializableIrClass.descriptor
|
private fun getSerializerGetterFunction(): IrSimpleFunction {
|
||||||
|
|
||||||
private fun getSerializerGetterDescriptor(): FunctionDescriptor {
|
|
||||||
return irClass.findDeclaration<IrSimpleFunction> {
|
return irClass.findDeclaration<IrSimpleFunction> {
|
||||||
(it.valueParameters.size == serializableDescriptor.declaredTypeParameters.size
|
(it.valueParameters.size == serializableIrClass.typeParameters.size
|
||||||
&& it.valueParameters.all { p -> isKSerializer(p.type) }) && isKSerializer(it.returnType)
|
&& it.valueParameters.all { p -> p.type.isKSerializer() }) && it.returnType.isKSerializer()
|
||||||
}?.descriptor ?: throw IllegalStateException(
|
} ?: throw IllegalStateException(
|
||||||
"Can't find synthesized 'Companion.serializer()' function to generate, " +
|
"Can't find synthesized 'Companion.serializer()' function to generate, " +
|
||||||
"probably clash with user-defined function has occurred"
|
"probably clash with user-defined function has occurred"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generate() {
|
fun generate() {
|
||||||
val serializerGetterDescriptor = getSerializerGetterDescriptor()
|
val serializerGetterFunction = getSerializerGetterFunction()
|
||||||
|
|
||||||
if (serializableDescriptor.isSerializableObject
|
if (serializableIrClass.isSerializableObject
|
||||||
|| serializableDescriptor.isAbstractOrSealedSerializableClass()
|
|| serializableIrClass.isAbstractOrSealedSerializableClass
|
||||||
|| serializableDescriptor.isSerializableEnum()
|
|| serializableIrClass.isSerializableEnum()
|
||||||
) {
|
) {
|
||||||
generateLazySerializerGetter(serializerGetterDescriptor)
|
generateLazySerializerGetter(serializerGetterFunction)
|
||||||
} else {
|
} else {
|
||||||
generateSerializerGetter(serializerGetterDescriptor)
|
generateSerializerGetter(serializerGetterFunction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,12 +59,11 @@ class SerializableCompanionIrGenerator(
|
|||||||
irClass: IrClass,
|
irClass: IrClass,
|
||||||
context: SerializationPluginContext,
|
context: SerializationPluginContext,
|
||||||
) {
|
) {
|
||||||
val companionDescriptor = irClass.descriptor
|
val companionDescriptor = irClass
|
||||||
val serializableClass = getSerializableClassDescriptorByCompanion(companionDescriptor) ?: return
|
val serializableClass = getSerializableClassByCompanion(companionDescriptor) ?: return
|
||||||
if (serializableClass.shouldHaveGeneratedMethodsInCompanion) {
|
if (serializableClass.shouldHaveGeneratedMethodsInCompanion) {
|
||||||
SerializableCompanionIrGenerator(irClass, getSerializableClassByCompanion(irClass)!!, context).generate()
|
SerializableCompanionIrGenerator(irClass, getSerializableClassByCompanion(irClass)!!, context).generate()
|
||||||
val declaration = irClass.constructors.primary // todo: move to appropriate place
|
irClass.addDefaultConstructorIfAbsent(context)
|
||||||
if (declaration.body == null) declaration.body = context.generateBodyForDefaultConstructor(declaration)
|
|
||||||
irClass.patchDeclarationParents(irClass.parent)
|
irClass.patchDeclarationParents(irClass.parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,7 +104,7 @@ class SerializableCompanionIrGenerator(
|
|||||||
irSerializableClass.annotations += annotationCtorCall
|
irSerializableClass.annotations += annotationCtorCall
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateLazySerializerGetter(methodDescriptor: FunctionDescriptor) {
|
fun generateLazySerializerGetter(methodDescriptor: IrSimpleFunction) {
|
||||||
val serializer = requireNotNull(
|
val serializer = requireNotNull(
|
||||||
findTypeSerializer(
|
findTypeSerializer(
|
||||||
compilerContext,
|
compilerContext,
|
||||||
@@ -124,21 +118,20 @@ class SerializableCompanionIrGenerator(
|
|||||||
|
|
||||||
val property = createLazyProperty(irClass, targetIrType, SerialEntityNames.CACHED_SERIALIZER_PROPERTY_NAME) {
|
val property = createLazyProperty(irClass, targetIrType, SerialEntityNames.CACHED_SERIALIZER_PROPERTY_NAME) {
|
||||||
val expr = serializerInstance(
|
val expr = serializerInstance(
|
||||||
this@SerializableCompanionIrGenerator,
|
|
||||||
serializer, compilerContext, serializableIrClass.defaultType
|
serializer, compilerContext, serializableIrClass.defaultType
|
||||||
)
|
)
|
||||||
patchSerializableClassWithMarkerAnnotation(kSerializerIrClass)
|
patchSerializableClassWithMarkerAnnotation(kSerializerIrClass)
|
||||||
+irReturn(requireNotNull(expr))
|
+irReturn(requireNotNull(expr))
|
||||||
}
|
}
|
||||||
|
|
||||||
irClass.contributeFunction(methodDescriptor) {
|
addFunctionBody(methodDescriptor) {
|
||||||
+irReturn(getLazyValueExpression(it.dispatchReceiverParameter!!, property, targetIrType))
|
+irReturn(getLazyValueExpression(it.dispatchReceiverParameter!!, property, targetIrType))
|
||||||
}
|
}
|
||||||
generateSerializerFactoryIfNeeded(methodDescriptor)
|
generateSerializerFactoryIfNeeded(methodDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
|
fun generateSerializerGetter(methodDescriptor: IrSimpleFunction) {
|
||||||
irClass.contributeFunction(methodDescriptor) { getter ->
|
addFunctionBody(methodDescriptor) { getter ->
|
||||||
val serializer = requireNotNull(
|
val serializer = requireNotNull(
|
||||||
findTypeSerializer(
|
findTypeSerializer(
|
||||||
compilerContext,
|
compilerContext,
|
||||||
@@ -147,7 +140,6 @@ class SerializableCompanionIrGenerator(
|
|||||||
)
|
)
|
||||||
val args: List<IrExpression> = getter.valueParameters.map { irGet(it) }
|
val args: List<IrExpression> = getter.valueParameters.map { irGet(it) }
|
||||||
val expr = serializerInstance(
|
val expr = serializerInstance(
|
||||||
this@SerializableCompanionIrGenerator,
|
|
||||||
serializer, compilerContext,
|
serializer, compilerContext,
|
||||||
serializableIrClass.defaultType
|
serializableIrClass.defaultType
|
||||||
) { it, _ -> args[it] }
|
) { it, _ -> args[it] }
|
||||||
@@ -157,25 +149,25 @@ class SerializableCompanionIrGenerator(
|
|||||||
generateSerializerFactoryIfNeeded(methodDescriptor)
|
generateSerializerFactoryIfNeeded(methodDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateSerializerFactoryIfNeeded(getterDescriptor: FunctionDescriptor) {
|
private fun generateSerializerFactoryIfNeeded(getterDescriptor: IrSimpleFunction) {
|
||||||
if (!irClass.descriptor.needSerializerFactory()) return
|
if (!irClass.descriptor.needSerializerFactory()) return
|
||||||
val serialFactoryDescriptor = irClass.findDeclaration<IrSimpleFunction> {
|
val serialFactoryDescriptor = irClass.findDeclaration<IrSimpleFunction> {
|
||||||
it.valueParameters.size == 1
|
it.valueParameters.size == 1
|
||||||
&& it.valueParameters.first().isVararg
|
&& it.valueParameters.first().isVararg
|
||||||
// && it.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
|
&& it.returnType.isKSerializer()
|
||||||
&& isKSerializer(it.returnType)
|
&& it.isFromPlugin()
|
||||||
} ?: return
|
} ?: return
|
||||||
addFunctionBody(serialFactoryDescriptor) { factory ->
|
addFunctionBody(serialFactoryDescriptor) { factory ->
|
||||||
val kSerializerStarType = factory.returnType
|
val kSerializerStarType = factory.returnType
|
||||||
val array = factory.valueParameters.first()
|
val array = factory.valueParameters.first()
|
||||||
val argsSize = serializableDescriptor.declaredTypeParameters.size
|
val argsSize = serializableIrClass.typeParameters.size
|
||||||
val arrayGet = compilerContext.irBuiltIns.arrayClass.owner.declarations.filterIsInstance<IrSimpleFunction>()
|
val arrayGet = compilerContext.irBuiltIns.arrayClass.owner.declarations.filterIsInstance<IrSimpleFunction>()
|
||||||
.single { it.name.asString() == "get" }
|
.single { it.name.asString() == "get" }
|
||||||
|
|
||||||
val serializers: List<IrExpression> = (0 until argsSize).map {
|
val serializers: List<IrExpression> = (0 until argsSize).map {
|
||||||
irInvoke(irGet(array), arrayGet.symbol, irInt(it), typeHint = kSerializerStarType)
|
irInvoke(irGet(array), arrayGet.symbol, irInt(it), typeHint = kSerializerStarType)
|
||||||
}
|
}
|
||||||
val serializerCall = compilerContext.symbolTable.referenceSimpleFunction(getterDescriptor)
|
val serializerCall = getterDescriptor.symbol
|
||||||
val call = irInvoke(
|
val call = irInvoke(
|
||||||
IrGetValueImpl(startOffset, endOffset, factory.dispatchReceiverParameter!!.symbol),
|
IrGetValueImpl(startOffset, endOffset, factory.dispatchReceiverParameter!!.symbol),
|
||||||
serializerCall,
|
serializerCall,
|
||||||
|
|||||||
+12
-14
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.name.ClassId
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
import org.jetbrains.kotlin.utils.getOrPutNullable
|
import org.jetbrains.kotlin.utils.getOrPutNullable
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless
|
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless
|
||||||
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.*
|
||||||
@@ -36,8 +35,8 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SE
|
|||||||
|
|
||||||
class SerializableIrGenerator(
|
class SerializableIrGenerator(
|
||||||
val irClass: IrClass,
|
val irClass: IrClass,
|
||||||
override val compilerContext: SerializationPluginContext
|
compilerContext: SerializationPluginContext
|
||||||
) : AbstractIrGenerator(irClass), IrBuilderExtension {
|
) : BaseIrGenerator(irClass, compilerContext) {
|
||||||
|
|
||||||
protected val properties = serializablePropertiesForIrBackend(irClass)
|
protected val properties = serializablePropertiesForIrBackend(irClass)
|
||||||
|
|
||||||
@@ -65,7 +64,7 @@ class SerializableIrGenerator(
|
|||||||
val thiz = irClass.thisReceiver!!
|
val thiz = irClass.thisReceiver!!
|
||||||
val serializableProperties = properties.serializableProperties
|
val serializableProperties = properties.serializableProperties
|
||||||
|
|
||||||
val serialDescs = serializableProperties.map { it.descriptor }.toSet()
|
val serialDescs = serializableProperties.map { it.ir }.toSet()
|
||||||
|
|
||||||
val propertyByParamReplacer: (ValueParameterDescriptor) -> IrExpression? =
|
val propertyByParamReplacer: (ValueParameterDescriptor) -> IrExpression? =
|
||||||
createPropertyByParamReplacer(irClass, serializableProperties, thiz)
|
createPropertyByParamReplacer(irClass, serializableProperties, thiz)
|
||||||
@@ -137,19 +136,19 @@ class SerializableIrGenerator(
|
|||||||
val paramRef = ctor.valueParameters[index + seenVarsOffset]
|
val paramRef = ctor.valueParameters[index + seenVarsOffset]
|
||||||
// Assign this.a = a in else branch
|
// Assign this.a = a in else branch
|
||||||
// Set field directly w/o setter to match behavior of old backend plugin
|
// Set field directly w/o setter to match behavior of old backend plugin
|
||||||
val backingFieldToAssign = prop.descriptor.backingField!!
|
val backingFieldToAssign = prop.ir.backingField!!
|
||||||
val assignParamExpr = irSetField(irGet(thiz), backingFieldToAssign, irGet(paramRef))
|
val assignParamExpr = irSetField(irGet(thiz), backingFieldToAssign, irGet(paramRef))
|
||||||
|
|
||||||
val ifNotSeenExpr: IrExpression = if (prop.optional) {
|
val ifNotSeenExpr: IrExpression = if (prop.optional) {
|
||||||
val initializerBody =
|
val initializerBody =
|
||||||
requireNotNull(initializerAdapter(prop.irField?.initializer!!)) { "Optional value without an initializer" } // todo: filter abstract here
|
requireNotNull(initializerAdapter(prop.ir.backingField?.initializer!!)) { "Optional value without an initializer" } // todo: filter abstract here
|
||||||
irSetField(irGet(thiz), backingFieldToAssign, initializerBody)
|
irSetField(irGet(thiz), backingFieldToAssign, initializerBody)
|
||||||
} else {
|
} else {
|
||||||
// property required
|
// property required
|
||||||
if (useFieldMissingOptimization()) {
|
if (useFieldMissingOptimization()) {
|
||||||
// field definitely not empty as it's checked before - no need another IF, only assign property from param
|
// field definitely not empty as it's checked before - no need another IF, only assign property from param
|
||||||
+assignParamExpr
|
+assignParamExpr
|
||||||
statementsAfterSerializableProperty[prop.descriptor]?.forEach { +it }
|
statementsAfterSerializableProperty[prop.ir]?.forEach { +it }
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
irThrow(irInvoke(null, exceptionCtorRef, irString(prop.name), typeHint = exceptionType))
|
irThrow(irInvoke(null, exceptionCtorRef, irString(prop.name), typeHint = exceptionType))
|
||||||
@@ -168,7 +167,7 @@ class SerializableIrGenerator(
|
|||||||
|
|
||||||
+irIfThenElse(compilerContext.irBuiltIns.unitType, propNotSeenTest, ifNotSeenExpr, assignParamExpr)
|
+irIfThenElse(compilerContext.irBuiltIns.unitType, propNotSeenTest, ifNotSeenExpr, assignParamExpr)
|
||||||
|
|
||||||
statementsAfterSerializableProperty[prop.descriptor]?.forEach { +it }
|
statementsAfterSerializableProperty[prop.ir]?.forEach { +it }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle function-intialized interface delegates
|
// Handle function-intialized interface delegates
|
||||||
@@ -219,7 +218,7 @@ class SerializableIrGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun IrBlockBodyBuilder.getInstantiateDescriptorExpr(): IrExpression {
|
private fun IrBlockBodyBuilder.getInstantiateDescriptorExpr(): IrExpression {
|
||||||
val classConstructors = serialDescriptorImplClass.constructors //todo: remove reference
|
val classConstructors = serialDescriptorImplClass.constructors
|
||||||
val serialClassDescImplCtor = classConstructors.single { it.isPrimary }.symbol
|
val serialClassDescImplCtor = classConstructors.single { it.isPrimary }.symbol
|
||||||
return irInvoke(
|
return irInvoke(
|
||||||
null, serialClassDescImplCtor,
|
null, serialClassDescImplCtor,
|
||||||
@@ -271,7 +270,7 @@ class SerializableIrGenerator(
|
|||||||
propertiesStart: Int
|
propertiesStart: Int
|
||||||
): Int {
|
): Int {
|
||||||
check(superClass.isInternalSerializable)
|
check(superClass.isInternalSerializable)
|
||||||
val superCtorRef = serializableSyntheticConstructor(superClass)!!
|
val superCtorRef = superClass.serializableSyntheticConstructor()!!
|
||||||
val superProperties = serializablePropertiesForIrBackend(superClass).serializableProperties
|
val superProperties = serializablePropertiesForIrBackend(superClass).serializableProperties
|
||||||
val superSlots = superProperties.bitMaskSlotCount()
|
val superSlots = superProperties.bitMaskSlotCount()
|
||||||
val arguments = allValueParameters.subList(0, superSlots) +
|
val arguments = allValueParameters.subList(0, superSlots) +
|
||||||
@@ -332,7 +331,6 @@ class SerializableIrGenerator(
|
|||||||
val genericIdx = irClass.defaultType.arguments.indexOf(arg).let { if (it == -1) null else it }
|
val genericIdx = irClass.defaultType.arguments.indexOf(arg).let { if (it == -1) null else it }
|
||||||
val serial = findTypeSerializerOrContext(compilerContext, arg.typeOrNull!!)
|
val serial = findTypeSerializerOrContext(compilerContext, arg.typeOrNull!!)
|
||||||
serializerInstance(
|
serializerInstance(
|
||||||
this@SerializableIrGenerator,
|
|
||||||
serial,
|
serial,
|
||||||
compilerContext,
|
compilerContext,
|
||||||
arg.typeOrNull!!,
|
arg.typeOrNull!!,
|
||||||
@@ -346,9 +344,9 @@ class SerializableIrGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
serializeAllProperties(
|
serializeAllProperties(
|
||||||
this@SerializableIrGenerator, irClass, serializableProperties,
|
serializableProperties, objectToSerialize,
|
||||||
objectToSerialize, localOutput, localSerialDesc,
|
localOutput, localSerialDesc, kOutputClass,
|
||||||
kOutputClass, ignoreIndexTo, initializerAdapter
|
ignoreIndexTo, initializerAdapter
|
||||||
) { it, _ ->
|
) { it, _ ->
|
||||||
irGet(writeSelfFunction.valueParameters[3 + it])
|
irGet(writeSelfFunction.valueParameters[3 + it])
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-9
@@ -7,8 +7,6 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.functionByName
|
import org.jetbrains.kotlin.backend.jvm.functionByName
|
||||||
import org.jetbrains.kotlin.builtins.StandardNames
|
import org.jetbrains.kotlin.builtins.StandardNames
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
@@ -23,14 +21,9 @@ import org.jetbrains.kotlin.ir.util.defaultType
|
|||||||
import org.jetbrains.kotlin.ir.util.functions
|
import org.jetbrains.kotlin.ir.util.functions
|
||||||
import org.jetbrains.kotlin.ir.util.properties
|
import org.jetbrains.kotlin.ir.util.properties
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.enumEntries
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getClassFromInternalSerializationPackage
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getClassFromRuntime
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.serialNameValue
|
|
||||||
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.CallingConventions
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
|
||||||
|
|
||||||
class SerializerForEnumsGenerator(
|
class SerializerForEnumsGenerator(
|
||||||
irClass: IrClass,
|
irClass: IrClass,
|
||||||
|
|||||||
+3
-10
@@ -6,8 +6,6 @@
|
|||||||
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.functionByName
|
import org.jetbrains.kotlin.backend.jvm.functionByName
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
@@ -18,12 +16,9 @@ import org.jetbrains.kotlin.ir.types.IrSimpleType
|
|||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.types.typeOrNull
|
import org.jetbrains.kotlin.ir.types.typeOrNull
|
||||||
import org.jetbrains.kotlin.ir.util.constructors
|
import org.jetbrains.kotlin.ir.util.constructors
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getClassFromInternalSerializationPackage
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getClassFromRuntime
|
|
||||||
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.CallingConventions
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
|
||||||
|
|
||||||
class SerializerForInlineClassGenerator(
|
class SerializerForInlineClassGenerator(
|
||||||
irClass: IrClass,
|
irClass: IrClass,
|
||||||
@@ -44,7 +39,7 @@ class SerializerForInlineClassGenerator(
|
|||||||
val inlineEncoder = irTemporary(encodeInlineCall, nameHint = "inlineEncoder")
|
val inlineEncoder = irTemporary(encodeInlineCall, nameHint = "inlineEncoder")
|
||||||
|
|
||||||
val property = serializableProperties.first()
|
val property = serializableProperties.first()
|
||||||
val value = getFromBox(irGet(saveFunc.valueParameters[1]), property)
|
val value = getProperty(irGet(saveFunc.valueParameters[1]), property.ir)
|
||||||
|
|
||||||
// inlineEncoder.encodeInt/String/SerializableValue
|
// inlineEncoder.encodeInt/String/SerializableValue
|
||||||
val elementCall = formEncodeDecodePropertyCall(irGet(inlineEncoder), saveFunc.dispatchReceiverParameter!!, property, {innerSerial, sti ->
|
val elementCall = formEncodeDecodePropertyCall(irGet(inlineEncoder), saveFunc.dispatchReceiverParameter!!, property, {innerSerial, sti ->
|
||||||
@@ -109,6 +104,4 @@ class SerializerForInlineClassGenerator(
|
|||||||
listOf(expression)
|
listOf(expression)
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun IrBlockBodyBuilder.getFromBox(expression: IrExpression, serializableProperty: IrSerializableProperty): IrExpression =
|
|
||||||
getProperty(expression, serializableProperty.descriptor)
|
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-29
@@ -33,11 +33,9 @@ import org.jetbrains.kotlin.ir.types.*
|
|||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
|
|
||||||
import org.jetbrains.kotlin.resolve.isInlineClass
|
import org.jetbrains.kotlin.resolve.isInlineClass
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
|
|
||||||
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.*
|
||||||
@@ -55,10 +53,10 @@ internal typealias FunctionWithArgs = Pair<IrFunctionSymbol, List<IrExpression>>
|
|||||||
|
|
||||||
open class SerializerIrGenerator(
|
open class SerializerIrGenerator(
|
||||||
val irClass: IrClass,
|
val irClass: IrClass,
|
||||||
final override val compilerContext: SerializationPluginContext,
|
compilerContext: SerializationPluginContext,
|
||||||
metadataPlugin: SerializationDescriptorSerializerPlugin?,
|
metadataPlugin: SerializationDescriptorSerializerPlugin?,
|
||||||
private val serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
|
private val serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
|
||||||
) : AbstractIrGenerator(irClass), IrBuilderExtension {
|
) : BaseIrGenerator(irClass, compilerContext) {
|
||||||
protected val serializableIrClass = getSerializableClassDescriptorBySerializer(irClass)!!
|
protected val serializableIrClass = getSerializableClassDescriptorBySerializer(irClass)!!
|
||||||
|
|
||||||
protected val serialName: String = serializableIrClass.serialName()
|
protected val serialName: String = serializableIrClass.serialName()
|
||||||
@@ -91,7 +89,7 @@ open class SerializerIrGenerator(
|
|||||||
if (count == 0) return emptyList()
|
if (count == 0) return emptyList()
|
||||||
val propNames = (0 until count).map { "${SerialEntityNames.typeArgPrefix}$it" }
|
val propNames = (0 until count).map { "${SerialEntityNames.typeArgPrefix}$it" }
|
||||||
return propNames.mapNotNull { name ->
|
return propNames.mapNotNull { name ->
|
||||||
getProperty(name) { isKSerializer(it.getter!!.returnType) }
|
getProperty(name) { it.getter!!.returnType.isKSerializer() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,8 +142,7 @@ open class SerializerIrGenerator(
|
|||||||
// save local descriptor to field
|
// save local descriptor to field
|
||||||
+irSetField(
|
+irSetField(
|
||||||
generateReceiverExpressionForFieldAccess(
|
generateReceiverExpressionForFieldAccess(
|
||||||
thisAsReceiverParameter.symbol,
|
thisAsReceiverParameter.symbol
|
||||||
generatedSerialDescPropertyDescriptor.descriptor
|
|
||||||
),
|
),
|
||||||
prop.backingField!!,
|
prop.backingField!!,
|
||||||
irGet(localDesc)
|
irGet(localDesc)
|
||||||
@@ -184,7 +181,7 @@ open class SerializerIrGenerator(
|
|||||||
if (classProp.transient) continue
|
if (classProp.transient) continue
|
||||||
+addFieldCall(classProp)
|
+addFieldCall(classProp)
|
||||||
// add property annotations
|
// add property annotations
|
||||||
val property = classProp.descriptor//.getIrPropertyFrom(serializableIrClass)
|
val property = classProp.ir//.getIrPropertyFrom(serializableIrClass)
|
||||||
copySerialInfoAnnotationsToDescriptor(
|
copySerialInfoAnnotationsToDescriptor(
|
||||||
property.annotations,
|
property.annotations,
|
||||||
localDescriptor,
|
localDescriptor,
|
||||||
@@ -224,8 +221,7 @@ open class SerializerIrGenerator(
|
|||||||
val localSerial = localSerializersFieldsDescriptors[index].second.backingField!!
|
val localSerial = localSerializersFieldsDescriptors[index].second.backingField!!
|
||||||
+irSetField(
|
+irSetField(
|
||||||
generateReceiverExpressionForFieldAccess(
|
generateReceiverExpressionForFieldAccess(
|
||||||
thisAsReceiverParameter.symbol,
|
thisAsReceiverParameter.symbol
|
||||||
localSerializersFieldsDescriptors[index].first
|
|
||||||
), localSerial, irGet(param)
|
), localSerial, irGet(param)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -305,8 +301,8 @@ open class SerializerIrGenerator(
|
|||||||
createInitializerAdapter(serializableIrClass, propertyByParamReplacer, thisSymbol to { irGet(objectToSerialize) })
|
createInitializerAdapter(serializableIrClass, propertyByParamReplacer, thisSymbol to { irGet(objectToSerialize) })
|
||||||
|
|
||||||
serializeAllProperties(
|
serializeAllProperties(
|
||||||
this@SerializerIrGenerator, serializableIrClass, serializableProperties, objectToSerialize,
|
serializableProperties, objectToSerialize, localOutput,
|
||||||
localOutput, localSerialDesc, kOutputClass, ignoreIndexTo = -1, initializerAdapter
|
localSerialDesc, kOutputClass, ignoreIndexTo = -1, initializerAdapter
|
||||||
) { it, _ ->
|
) { it, _ ->
|
||||||
val (_, ir) = localSerializersFieldsDescriptors[it]
|
val (_, ir) = localSerializersFieldsDescriptors[it]
|
||||||
irGetField(irGet(saveFunc.dispatchReceiverParameter!!), ir.backingField!!)
|
irGetField(irGet(saveFunc.dispatchReceiverParameter!!), ir.backingField!!)
|
||||||
@@ -326,7 +322,6 @@ open class SerializerIrGenerator(
|
|||||||
whenDoNot: (sti: IrSerialTypeInfo) -> FunctionWithArgs,
|
whenDoNot: (sti: IrSerialTypeInfo) -> FunctionWithArgs,
|
||||||
returnTypeHint: IrType? = null
|
returnTypeHint: IrType? = null
|
||||||
): IrExpression = formEncodeDecodePropertyCall(
|
): IrExpression = formEncodeDecodePropertyCall(
|
||||||
this@SerializerIrGenerator,
|
|
||||||
encoder,
|
encoder,
|
||||||
property,
|
property,
|
||||||
whenHaveSerializer,
|
whenHaveSerializer,
|
||||||
@@ -385,7 +380,7 @@ open class SerializerIrGenerator(
|
|||||||
|
|
||||||
val serialPropertiesIndexes = serializableProperties
|
val serialPropertiesIndexes = serializableProperties
|
||||||
.mapIndexed { i, property -> property to i }
|
.mapIndexed { i, property -> property to i }
|
||||||
.associate { (p, i) -> p.descriptor to i }
|
.associate { (p, i) -> p.ir to i }
|
||||||
|
|
||||||
val transients = serializableIrClass.declarations.asSequence()
|
val transients = serializableIrClass.declarations.asSequence()
|
||||||
.filterIsInstance<IrProperty>()
|
.filterIsInstance<IrProperty>()
|
||||||
@@ -395,7 +390,7 @@ open class SerializerIrGenerator(
|
|||||||
// var bitMask0 = 0, bitMask1 = 0...
|
// var bitMask0 = 0, bitMask1 = 0...
|
||||||
val bitMasks = (0 until blocksCnt).map { irTemporary(irInt(0), "bitMask$it", isMutable = true) }
|
val bitMasks = (0 until blocksCnt).map { irTemporary(irInt(0), "bitMask$it", isMutable = true) }
|
||||||
// var local0 = null, local1 = null ...
|
// var local0 = null, local1 = null ...
|
||||||
val serialPropertiesMap = serializableProperties.mapIndexed { i, prop -> i to prop.descriptor }.associate { (i, descriptor) ->
|
val serialPropertiesMap = serializableProperties.mapIndexed { i, prop -> i to prop.ir }.associate { (i, descriptor) ->
|
||||||
val (expr, type) = defaultValueAndType(descriptor)
|
val (expr, type) = defaultValueAndType(descriptor)
|
||||||
descriptor to irTemporary(expr, "local$i", type, isMutable = true)
|
descriptor to irTemporary(expr, "local$i", type, isMutable = true)
|
||||||
}
|
}
|
||||||
@@ -425,7 +420,7 @@ open class SerializerIrGenerator(
|
|||||||
it.owner.name.asString() == "${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}" &&
|
it.owner.name.asString() == "${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}" &&
|
||||||
it.owner.valueParameters.size == 4
|
it.owner.valueParameters.size == 4
|
||||||
} to listOf(
|
} to listOf(
|
||||||
localSerialDesc.get(), irInt(index), innerSerial, serialPropertiesMap.getValue(property.descriptor).get()
|
localSerialDesc.get(), irInt(index), innerSerial, serialPropertiesMap.getValue(property.ir).get()
|
||||||
)
|
)
|
||||||
}, {sti ->
|
}, {sti ->
|
||||||
inputClass.functions.single {
|
inputClass.functions.single {
|
||||||
@@ -435,7 +430,7 @@ open class SerializerIrGenerator(
|
|||||||
}, returnTypeHint = property.type)
|
}, returnTypeHint = property.type)
|
||||||
// local$i = localInput.decode...(...)
|
// local$i = localInput.decode...(...)
|
||||||
+irSet(
|
+irSet(
|
||||||
serialPropertiesMap.getValue(property.descriptor).symbol,
|
serialPropertiesMap.getValue(property.ir).symbol,
|
||||||
decodeFuncToCall
|
decodeFuncToCall
|
||||||
)
|
)
|
||||||
// bitMask[i] |= 1 << x
|
// bitMask[i] |= 1 << x
|
||||||
@@ -492,9 +487,9 @@ open class SerializerIrGenerator(
|
|||||||
)
|
)
|
||||||
|
|
||||||
val typeArgs = (loadFunc.returnType as IrSimpleType).arguments.map { (it as IrTypeProjection).type }
|
val typeArgs = (loadFunc.returnType as IrSimpleType).arguments.map { (it as IrTypeProjection).type }
|
||||||
val deserCtor: IrConstructorSymbol? = serializableSyntheticConstructor(serializableIrClass)
|
val deserCtor: IrConstructorSymbol? = serializableIrClass.serializableSyntheticConstructor()
|
||||||
if (serializableIrClass.isInternalSerializable && deserCtor != null) {
|
if (serializableIrClass.isInternalSerializable && deserCtor != null) {
|
||||||
var args: List<IrExpression> = serializableProperties.map { serialPropertiesMap.getValue(it.descriptor).get() }
|
var args: List<IrExpression> = serializableProperties.map { serialPropertiesMap.getValue(it.ir).get() }
|
||||||
args = bitMasks.map { irGet(it) } + args + irNull()
|
args = bitMasks.map { irGet(it) } + args + irNull()
|
||||||
+irReturn(irInvoke(null, deserCtor, typeArgs, args))
|
+irReturn(irInvoke(null, deserCtor, typeArgs, args))
|
||||||
} else {
|
} else {
|
||||||
@@ -526,14 +521,13 @@ open class SerializerIrGenerator(
|
|||||||
|
|
||||||
// constructor args:
|
// constructor args:
|
||||||
val ctorArgs = params.map { parameter ->
|
val ctorArgs = params.map { parameter ->
|
||||||
val propertyDescriptor = serializableIrClass.properties.find { it.name == parameter.name }!! // todo: check with tests
|
val propertyDescriptor = serializableIrClass.properties.find { it.name == parameter.name }!!
|
||||||
val parameterDescriptor = parameter.descriptor as ValueParameterDescriptor // TODO: remove descriptor here
|
|
||||||
val serialProperty = serialPropertiesMap[propertyDescriptor]
|
val serialProperty = serialPropertiesMap[propertyDescriptor]
|
||||||
|
|
||||||
// null if transient
|
// null if transient
|
||||||
if (serialProperty != null) {
|
if (serialProperty != null) {
|
||||||
val index = serialPropertiesIndexes.getValue(propertyDescriptor)
|
val index = serialPropertiesIndexes.getValue(propertyDescriptor)
|
||||||
if (parameterDescriptor.hasDefaultValue()) {
|
if (parameter.hasDefaultValue()) {
|
||||||
val propNotSeenTest =
|
val propNotSeenTest =
|
||||||
irEquals(
|
irEquals(
|
||||||
irInt(0),
|
irInt(0),
|
||||||
@@ -552,7 +546,7 @@ open class SerializerIrGenerator(
|
|||||||
serialProperty.get()
|
serialProperty.get()
|
||||||
} else {
|
} else {
|
||||||
val transientVar = transientsPropertiesMap.getValue(propertyDescriptor)
|
val transientVar = transientsPropertiesMap.getValue(propertyDescriptor)
|
||||||
if (parameterDescriptor.hasDefaultValue()) {
|
if (parameter.hasDefaultValue()) {
|
||||||
val defaultValueExp = parameter.defaultValue!!
|
val defaultValueExp = parameter.defaultValue!!
|
||||||
val expr = initializerAdapter(defaultValueExp)
|
val expr = initializerAdapter(defaultValueExp)
|
||||||
+irSet(transientVar.symbol, expr)
|
+irSet(transientVar.symbol, expr)
|
||||||
@@ -574,9 +568,9 @@ open class SerializerIrGenerator(
|
|||||||
bitMasks: List<IrVariable>
|
bitMasks: List<IrVariable>
|
||||||
) {
|
) {
|
||||||
for (property in properties.serializableStandaloneProperties) {
|
for (property in properties.serializableStandaloneProperties) {
|
||||||
val localPropIndex = propIndexes(property.descriptor)
|
val localPropIndex = propIndexes(property.ir)
|
||||||
// generate setter call
|
// generate setter call
|
||||||
val setter = property.descriptor.setter!!
|
val setter = property.ir.setter!!
|
||||||
val propSeenTest =
|
val propSeenTest =
|
||||||
irNotEquals(
|
irNotEquals(
|
||||||
irInt(0),
|
irInt(0),
|
||||||
@@ -587,13 +581,12 @@ open class SerializerIrGenerator(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val setterInvokeExpr = irSet(setter.returnType, irGet(serializableVar), setter.symbol, irGet(propVars(property.descriptor)))
|
val setterInvokeExpr = irSet(setter.returnType, irGet(serializableVar), setter.symbol, irGet(propVars(property.ir)))
|
||||||
|
|
||||||
+irIfThen(propSeenTest, setterInvokeExpr)
|
+irIfThen(propSeenTest, setterInvokeExpr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// !!! TODO: this doesn't work with OLD FE !!!
|
|
||||||
fun generate() {
|
fun generate() {
|
||||||
val prop = generatedSerialDescPropertyDescriptor?.let { generateSerializableClassProperty(it); true } ?: false
|
val prop = generatedSerialDescPropertyDescriptor?.let { generateSerializableClassProperty(it); true } ?: false
|
||||||
if (prop)
|
if (prop)
|
||||||
@@ -631,8 +624,7 @@ open class SerializerIrGenerator(
|
|||||||
else -> SerializerIrGenerator(irClass, context, metadataPlugin, serialInfoJvmGenerator)
|
else -> SerializerIrGenerator(irClass, context, metadataPlugin, serialInfoJvmGenerator)
|
||||||
}
|
}
|
||||||
generator.generate()
|
generator.generate()
|
||||||
val declaration = irClass.constructors.primary // todo: move to appropriate place
|
irClass.addDefaultConstructorIfAbsent(context)
|
||||||
if (declaration.body == null) declaration.body = context.generateBodyForDefaultConstructor(declaration)
|
|
||||||
irClass.patchDeclarationParents(irClass.parent)
|
irClass.patchDeclarationParents(irClass.parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+108
-194
@@ -3,31 +3,79 @@
|
|||||||
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlinx.serialization.compiler.backend.common
|
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.getStringConstArgument
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findStandardKotlinTypeSerializer
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.*
|
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.*
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.fir.SerializationPluginKey
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SpecialBuiltins
|
||||||
|
|
||||||
fun AbstractIrGenerator.findTypeSerializerOrContextUnchecked(
|
class IrSerialTypeInfo(
|
||||||
|
val property: IrSerializableProperty,
|
||||||
|
val elementMethodPrefix: String,
|
||||||
|
val serializer: IrClassSymbol? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
fun BaseIrGenerator.getIrSerialTypeInfo(property: IrSerializableProperty, ctx: SerializationPluginContext): IrSerialTypeInfo {
|
||||||
|
fun SerializableInfo(serializer: IrClassSymbol?) =
|
||||||
|
IrSerialTypeInfo(property, if (property.type.isNullable()) "Nullable" else "", serializer)
|
||||||
|
|
||||||
|
val T = property.type
|
||||||
|
property.serializableWith(ctx)?.let { return SerializableInfo(it) }
|
||||||
|
findAddOnSerializer(T, ctx)?.let { return SerializableInfo(it) }
|
||||||
|
T.overridenSerializer?.let { return SerializableInfo(it) }
|
||||||
|
return when {
|
||||||
|
T.isTypeParameter() -> IrSerialTypeInfo(property, if (property.type.isMarkedNullable()) "Nullable" else "", null)
|
||||||
|
T.isPrimitiveType() -> IrSerialTypeInfo(
|
||||||
|
property,
|
||||||
|
T.classFqName!!.asString().removePrefix("kotlin.")
|
||||||
|
)
|
||||||
|
T.isString() -> IrSerialTypeInfo(property, "String")
|
||||||
|
T.isArray() -> {
|
||||||
|
val serializer = property.serializableWith(ctx) ?: ctx.getClassFromInternalSerializationPackage(SpecialBuiltins.referenceArraySerializer)
|
||||||
|
SerializableInfo(serializer)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val serializer =
|
||||||
|
findTypeSerializerOrContext(ctx, property.type)
|
||||||
|
SerializableInfo(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun BaseIrGenerator.findAddOnSerializer(propertyType: IrType, ctx: SerializationPluginContext): IrClassSymbol? {
|
||||||
|
val classSymbol = propertyType.classOrNull ?: return null
|
||||||
|
additionalSerializersInScopeOfCurrentFile[classSymbol to propertyType.isNullable()]?.let { return it }
|
||||||
|
if (classSymbol in contextualKClassListInCurrentFile)
|
||||||
|
return ctx.getClassFromRuntime(SpecialBuiltins.contextSerializer)
|
||||||
|
if (classSymbol.owner.annotations.hasAnnotation(SerializationAnnotations.polymorphicFqName))
|
||||||
|
return ctx.getClassFromRuntime(SpecialBuiltins.polymorphicSerializer)
|
||||||
|
if (propertyType.isNullable()) return findAddOnSerializer(propertyType.makeNotNull(), ctx)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun BaseIrGenerator.findTypeSerializerOrContext(
|
||||||
|
context: SerializationPluginContext, kType: IrType
|
||||||
|
): IrClassSymbol? {
|
||||||
|
if (kType.isTypeParameter()) return null
|
||||||
|
return findTypeSerializerOrContextUnchecked(context, kType) ?: error("Serializer for element of type ${kType.render()} has not been found")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun BaseIrGenerator.findTypeSerializerOrContextUnchecked(
|
||||||
context: SerializationPluginContext, kType: IrType
|
context: SerializationPluginContext, kType: IrType
|
||||||
): IrClassSymbol? {
|
): IrClassSymbol? {
|
||||||
val annotations = kType.annotations
|
val annotations = kType.annotations
|
||||||
@@ -53,12 +101,6 @@ fun analyzeSpecialSerializers(
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun AbstractIrGenerator.findTypeSerializerOrContext(
|
|
||||||
context: SerializationPluginContext, kType: IrType
|
|
||||||
): IrClassSymbol? {
|
|
||||||
if (kType.isTypeParameter()) return null
|
|
||||||
return findTypeSerializerOrContextUnchecked(context, kType) ?: error("Serializer for element of type ${kType.render()} has not been found")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun findTypeSerializer(context: SerializationPluginContext, type: IrType): IrClassSymbol? {
|
fun findTypeSerializer(context: SerializationPluginContext, type: IrType): IrClassSymbol? {
|
||||||
type.overridenSerializer?.let { return it }
|
type.overridenSerializer?.let { return it }
|
||||||
@@ -73,6 +115,12 @@ fun findTypeSerializer(context: SerializationPluginContext, type: IrType): IrCla
|
|||||||
)
|
)
|
||||||
return type.classOrNull?.owner.classSerializer(context) // check for serializer defined on the type
|
return type.classOrNull?.owner.classSerializer(context) // check for serializer defined on the type
|
||||||
}
|
}
|
||||||
|
fun findEnumTypeSerializer(context: SerializationPluginContext, type: IrType): IrClassSymbol? {
|
||||||
|
val classSymbol = type.classOrNull?.owner ?: return null
|
||||||
|
return if (classSymbol.kind == ClassKind.ENUM_CLASS && !classSymbol.isEnumWithLegacyGeneratedSerializer())
|
||||||
|
context.referenceClass(enumSerializerId)
|
||||||
|
else null
|
||||||
|
}
|
||||||
|
|
||||||
internal fun IrClass?.classSerializer(context: SerializationPluginContext): IrClassSymbol? = this?.let {
|
internal fun IrClass?.classSerializer(context: SerializationPluginContext): IrClassSymbol? = this?.let {
|
||||||
// serializer annotation on class?
|
// serializer annotation on class?
|
||||||
@@ -91,15 +139,6 @@ internal fun IrClass?.classSerializer(context: SerializationPluginContext): IrCl
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private val IrClass.isSerialInfoAnnotation: Boolean
|
|
||||||
get() = annotations.hasAnnotation(SerializationAnnotations.serialInfoFqName)
|
|
||||||
|| annotations.hasAnnotation(SerializationAnnotations.inheritableSerialInfoFqName)
|
|
||||||
|| annotations.hasAnnotation(SerializationAnnotations.metaSerializableAnnotationFqName)
|
|
||||||
|
|
||||||
internal val IrClass.shouldHaveGeneratedSerializer: Boolean
|
|
||||||
get() = (isInternalSerializable && (modality == Modality.FINAL || modality == Modality.OPEN))
|
|
||||||
|| isEnumWithLegacyGeneratedSerializer()
|
|
||||||
|
|
||||||
internal fun IrClass.polymorphicSerializerIfApplicableAutomatically(context: SerializationPluginContext): IrClassSymbol? {
|
internal fun IrClass.polymorphicSerializerIfApplicableAutomatically(context: SerializationPluginContext): IrClassSymbol? {
|
||||||
val serializer = when {
|
val serializer = when {
|
||||||
kind == ClassKind.INTERFACE && modality == Modality.SEALED -> SpecialBuiltins.sealedSerializer
|
kind == ClassKind.INTERFACE && modality == Modality.SEALED -> SpecialBuiltins.sealedSerializer
|
||||||
@@ -117,45 +156,20 @@ internal fun IrClass.polymorphicSerializerIfApplicableAutomatically(context: Ser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val IrClass.isInternalSerializable: Boolean
|
internal val IrType.overridenSerializer: IrClassSymbol?
|
||||||
get() {
|
get() {
|
||||||
if (kind != ClassKind.CLASS) return false
|
val desc = this.classOrNull ?: return null
|
||||||
return hasSerializableOrMetaAnnotationWithoutArgs()
|
desc.owner.serializableWith?.let { return it }
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val IrClass.isAbstractOrSealedSerializableClass: Boolean get() = isInternalSerializable && (modality == Modality.ABSTRACT || modality == Modality.SEALED)
|
internal val IrClass.serializableWith: IrClassSymbol?
|
||||||
|
get() = annotations.serializableWith()
|
||||||
internal val IrClass.isStaticSerializable: Boolean get() = this.typeParameters.isEmpty()
|
|
||||||
|
|
||||||
|
|
||||||
internal val IrClass.hasCompanionObjectAsSerializer: Boolean
|
|
||||||
get() = isInternallySerializableObject || companionObject()?.serializerForClass == this.symbol
|
|
||||||
|
|
||||||
internal val IrClass.isInternallySerializableObject: Boolean
|
|
||||||
get() = kind == ClassKind.OBJECT && hasSerializableOrMetaAnnotationWithoutArgs()
|
|
||||||
|
|
||||||
internal val IrClass.serializerForClass: IrClassSymbol?
|
internal val IrClass.serializerForClass: IrClassSymbol?
|
||||||
get() = (annotations.findAnnotation(SerializationAnnotations.serializerAnnotationFqName)
|
get() = (annotations.findAnnotation(SerializationAnnotations.serializerAnnotationFqName)
|
||||||
?.getValueArgument(0) as? IrClassReference)?.symbol as? IrClassSymbol
|
?.getValueArgument(0) as? IrClassReference)?.symbol as? IrClassSymbol
|
||||||
|
|
||||||
fun findEnumTypeSerializer(context: SerializationPluginContext, type: IrType): IrClassSymbol? {
|
|
||||||
val classSymbol = type.classOrNull?.owner ?: return null
|
|
||||||
return if (classSymbol.kind == ClassKind.ENUM_CLASS && !classSymbol.isEnumWithLegacyGeneratedSerializer())
|
|
||||||
context.referenceClass(enumSerializerId)
|
|
||||||
else null
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun IrClass.isEnumWithLegacyGeneratedSerializer(): Boolean = isInternallySerializableEnum() && useGeneratedEnumSerializer
|
|
||||||
|
|
||||||
internal val IrClass.useGeneratedEnumSerializer: Boolean
|
|
||||||
get() = true // FIXME This would break if we try to use this new IR compiler with pre-1.4.1 serialization versions. I think we just need to raise min runtime version.
|
|
||||||
|
|
||||||
internal val IrClass.isSealedSerializableInterface: Boolean
|
|
||||||
get() = kind == ClassKind.INTERFACE && modality == Modality.SEALED && hasSerializableOrMetaAnnotation()
|
|
||||||
|
|
||||||
internal fun IrClass.isInternallySerializableEnum(): Boolean =
|
|
||||||
kind == ClassKind.ENUM_CLASS && hasSerializableOrMetaAnnotationWithoutArgs()
|
|
||||||
|
|
||||||
fun findStandardKotlinTypeSerializer(context: SerializationPluginContext, type: IrType): IrClassSymbol? {
|
fun findStandardKotlinTypeSerializer(context: SerializationPluginContext, type: IrType): IrClassSymbol? {
|
||||||
val typeName = type.classFqName?.toString()
|
val typeName = type.classFqName?.toString()
|
||||||
val name = when (typeName) {
|
val name = when (typeName) {
|
||||||
@@ -173,26 +187,47 @@ fun findStandardKotlinTypeSerializer(context: SerializationPluginContext, type:
|
|||||||
return context.getClassFromRuntimeOrNull(name, SerializationPackages.internalPackageFqName, SerializationPackages.packageFqName)
|
return context.getClassFromRuntimeOrNull(name, SerializationPackages.internalPackageFqName, SerializationPackages.packageFqName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrType.isGeneratedSerializableObject(): Boolean {
|
// @Serializable(X::class) -> X
|
||||||
return classOrNull?.run { owner.kind == ClassKind.OBJECT && owner.hasSerializableOrMetaAnnotationWithoutArgs() } == true
|
internal fun List<IrConstructorCall>.serializableWith(): IrClassSymbol? {
|
||||||
|
val annotation = findAnnotation(SerializationAnnotations.serializableAnnotationFqName) ?: return null
|
||||||
|
val arg = annotation.getValueArgument(0) as? IrClassReference ?: return null
|
||||||
|
return arg.symbol as? IrClassSymbol
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val IrClass.isSerializableObject: Boolean
|
internal fun getSerializableClassByCompanion(companionClass: IrClass): IrClass? {
|
||||||
get() = kind == ClassKind.OBJECT && hasSerializableOrMetaAnnotation()
|
if (companionClass.isSerializableObject) return companionClass
|
||||||
|
if (!companionClass.isCompanion) return null
|
||||||
|
val classDescriptor = (companionClass.parent as? IrClass) ?: return null
|
||||||
|
if (!classDescriptor.shouldHaveGeneratedMethodsInCompanion) return null
|
||||||
|
return classDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
// todo: optimize & unify with hasSerializableOrMeta
|
fun BaseIrGenerator.allSealedSerializableSubclassesFor(
|
||||||
internal fun IrClass.hasSerializableOrMetaAnnotationWithoutArgs(): Boolean {
|
irClass: IrClass,
|
||||||
val annot = getAnnotation(SerializationAnnotations.serializableAnnotationFqName)
|
context: SerializationPluginContext
|
||||||
if (annot != null) {
|
): Pair<List<IrSimpleType>, List<IrClassSymbol>> {
|
||||||
for (i in 0 until annot.valueArgumentsCount) {
|
assert(irClass.modality == Modality.SEALED)
|
||||||
if (annot.getValueArgument(i) != null) return false
|
fun recursiveSealed(klass: IrClass): Collection<IrClass> {
|
||||||
}
|
return klass.sealedSubclasses.map { it.owner }.flatMap { if (it.modality == Modality.SEALED) recursiveSealed(it) else setOf(it) }
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
val metaAnnotation = annotations
|
|
||||||
.flatMap { it.symbol.owner.constructedClass.annotations }
|
val serializableSubtypes = recursiveSealed(irClass).map { it.defaultType }
|
||||||
.find { it.isAnnotation(SerializationAnnotations.metaSerializableAnnotationFqName) }
|
return serializableSubtypes.mapNotNull { subtype ->
|
||||||
return metaAnnotation != null
|
findTypeSerializerOrContextUnchecked(context, subtype)?.let { Pair(subtype, it) }
|
||||||
|
}.unzip()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun getSerializableClassDescriptorBySerializer(serializer: IrClass): IrClass? {
|
||||||
|
val serializerForClass = serializer.serializerForClass
|
||||||
|
if (serializerForClass != null) return serializerForClass.owner
|
||||||
|
if (serializer.name !in setOf(
|
||||||
|
SerialEntityNames.SERIALIZER_CLASS_NAME,
|
||||||
|
SerialEntityNames.GENERATED_SERIALIZER_CLASS
|
||||||
|
)
|
||||||
|
) return null
|
||||||
|
val classDescriptor = (serializer.parent as? IrClass) ?: return null
|
||||||
|
if (!classDescriptor.shouldHaveGeneratedSerializer) return null
|
||||||
|
return classDescriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
fun SerializationPluginContext.getClassFromRuntimeOrNull(className: String, vararg packages: FqName): IrClassSymbol? {
|
fun SerializationPluginContext.getClassFromRuntimeOrNull(className: String, vararg packages: FqName): IrClassSymbol? {
|
||||||
@@ -214,124 +249,3 @@ fun SerializationPluginContext.getClassFromInternalSerializationPackage(classNam
|
|||||||
getClassFromRuntimeOrNull(className, SerializationPackages.internalPackageFqName)
|
getClassFromRuntimeOrNull(className, SerializationPackages.internalPackageFqName)
|
||||||
?: error("Class $className wasn't found in ${SerializationPackages.internalPackageFqName}. Check that you have correct version of serialization runtime in classpath.")
|
?: error("Class $className wasn't found in ${SerializationPackages.internalPackageFqName}. Check that you have correct version of serialization runtime in classpath.")
|
||||||
|
|
||||||
|
|
||||||
internal val IrType.overridenSerializer: IrClassSymbol?
|
|
||||||
get() {
|
|
||||||
val desc = this.classOrNull ?: return null
|
|
||||||
desc.owner.serializableWith?.let { return it }
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
internal val IrClass.serializableWith: IrClassSymbol?
|
|
||||||
get() = annotations.serializableWith()
|
|
||||||
|
|
||||||
|
|
||||||
// @Serializable(X::class) -> X
|
|
||||||
internal fun List<IrConstructorCall>.serializableWith(): IrClassSymbol? {
|
|
||||||
val annotation = findAnnotation(SerializationAnnotations.serializableAnnotationFqName) ?: return null
|
|
||||||
val arg = annotation.getValueArgument(0) as? IrClassReference ?: return null
|
|
||||||
return arg.symbol as? IrClassSymbol
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun getSerializableClassByCompanion(companionClass: IrClass): IrClass? {
|
|
||||||
if (companionClass.isSerializableObject) return companionClass
|
|
||||||
if (!companionClass.isCompanion) return null
|
|
||||||
val classDescriptor = (companionClass.parent as? IrClass) ?: return null
|
|
||||||
if (!classDescriptor.shouldHaveGeneratedMethodsInCompanion) return null
|
|
||||||
return classDescriptor
|
|
||||||
}
|
|
||||||
|
|
||||||
internal val IrClass.shouldHaveGeneratedMethodsInCompanion: Boolean
|
|
||||||
get() = this.isSerializableObject || this.isSerializableEnum() || (this.kind == ClassKind.CLASS && hasSerializableOrMetaAnnotation()) || this.isSealedSerializableInterface
|
|
||||||
|
|
||||||
internal fun IrClass.isSerializableEnum(): Boolean = kind == ClassKind.ENUM_CLASS && hasSerializableOrMetaAnnotation()
|
|
||||||
|
|
||||||
fun IrClass.hasSerializableOrMetaAnnotation() = descriptor.hasSerializableOrMetaAnnotation // TODO
|
|
||||||
|
|
||||||
internal val IrType.genericIndex: Int?
|
|
||||||
get() = (this.classifierOrNull as? IrTypeParameterSymbol)?.owner?.index
|
|
||||||
|
|
||||||
fun IrType.serialName(): String = this.classOrNull!!.owner.serialName()
|
|
||||||
fun IrClass.serialName(): String {
|
|
||||||
return annotations.serialNameValue ?: fqNameWhenAvailable?.asString() ?: error("${this.render()} does not have fqName")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun AbstractIrGenerator.allSealedSerializableSubclassesFor(
|
|
||||||
irClass: IrClass,
|
|
||||||
context: SerializationPluginContext
|
|
||||||
): Pair<List<IrSimpleType>, List<IrClassSymbol>> {
|
|
||||||
assert(irClass.modality == Modality.SEALED)
|
|
||||||
fun recursiveSealed(klass: IrClass): Collection<IrClass> {
|
|
||||||
return klass.sealedSubclasses.map { it.owner }.flatMap { if (it.modality == Modality.SEALED) recursiveSealed(it) else setOf(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
val serializableSubtypes = recursiveSealed(irClass).map { it.defaultType }
|
|
||||||
return serializableSubtypes.mapNotNull { subtype ->
|
|
||||||
findTypeSerializerOrContextUnchecked(context, subtype)?.let { Pair(subtype, it) }
|
|
||||||
}.unzip()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun IrClass.findEnumValuesMethod() = this.functions.singleOrNull { f ->
|
|
||||||
f.name == Name.identifier("values") && f.valueParameters.isEmpty() && f.extensionReceiverParameter == null
|
|
||||||
} ?: throw AssertionError("Enum class does not have single .values() function")
|
|
||||||
|
|
||||||
internal fun IrClass.enumEntries(): List<IrEnumEntry> {
|
|
||||||
check(this.kind == ClassKind.ENUM_CLASS)
|
|
||||||
return declarations.filterIsInstance<IrEnumEntry>().toList()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun IrClass.isEnumWithSerialInfoAnnotation(): Boolean {
|
|
||||||
if (kind != ClassKind.ENUM_CLASS) return false
|
|
||||||
if (annotations.hasAnySerialAnnotation) return true
|
|
||||||
return enumEntries().any { (it.annotations.hasAnySerialAnnotation) }
|
|
||||||
}
|
|
||||||
|
|
||||||
internal val List<IrConstructorCall>.hasAnySerialAnnotation: Boolean
|
|
||||||
get() = serialNameValue != null || any { it.annotationClass.isSerialInfoAnnotation == true }
|
|
||||||
|
|
||||||
internal val List<IrConstructorCall>.serialNameValue: String?
|
|
||||||
get() = findAnnotation(SerializationAnnotations.serialNameAnnotationFqName)?.getStringConstArgument(0) // @SerialName("foo")
|
|
||||||
|
|
||||||
internal fun getSerializableClassDescriptorBySerializer(serializer: IrClass): IrClass? {
|
|
||||||
val serializerForClass = serializer.serializerForClass
|
|
||||||
if (serializerForClass != null) return serializerForClass.owner
|
|
||||||
if (serializer.name !in setOf(
|
|
||||||
SerialEntityNames.SERIALIZER_CLASS_NAME,
|
|
||||||
SerialEntityNames.GENERATED_SERIALIZER_CLASS
|
|
||||||
)
|
|
||||||
) return null
|
|
||||||
val classDescriptor = (serializer.parent as? IrClass) ?: return null
|
|
||||||
if (!classDescriptor.shouldHaveGeneratedSerializer) return null
|
|
||||||
return classDescriptor
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun isKSerializer(type: IrType): Boolean {
|
|
||||||
val simpleType = type as? IrSimpleType ?: return false
|
|
||||||
val classifier = simpleType.classifier as? IrClassSymbol ?: return false
|
|
||||||
val fqName = classifier.owner.fqNameWhenAvailable
|
|
||||||
return fqName == SerialEntityNames.KSERIALIZER_NAME_FQ || fqName == SerialEntityNames.GENERATED_SERIALIZER_FQ
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun IrClass.findPluginGeneratedMethod(name: String): IrSimpleFunction? {
|
|
||||||
return this.functions.find {
|
|
||||||
it.name.asString() == name && it.isFromPlugin()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun IrDeclaration.isFromPlugin(): Boolean =
|
|
||||||
this.origin == IrDeclarationOrigin.GeneratedByPlugin(SerializationPluginKey) || (this.descriptor as? CallableMemberDescriptor)?.kind == CallableMemberDescriptor.Kind.SYNTHESIZED // old FE doesn't specify origin
|
|
||||||
|
|
||||||
internal fun IrConstructor.isSerializationCtor(): Boolean {
|
|
||||||
/*kind == CallableMemberDescriptor.Kind.SYNTHESIZED does not work because DeserializedClassConstructorDescriptor loses its kind*/
|
|
||||||
return valueParameters.lastOrNull()?.run {
|
|
||||||
name == SerialEntityNames.dummyParamName && type.classFqName == SerializationPackages.internalPackageFqName.child(
|
|
||||||
SerialEntityNames.SERIAL_CTOR_MARKER_NAME
|
|
||||||
)
|
|
||||||
} == true
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun IrExpression.isInitializePropertyFromParameter(): Boolean =
|
|
||||||
this is IrGetValueImpl && this.origin == IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER
|
|
||||||
|
|
||||||
internal val IrConstructorCall.annotationClass
|
|
||||||
get() = this.symbol.owner.constructedClass
|
|
||||||
-39
@@ -1,39 +0,0 @@
|
|||||||
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
|
||||||
import org.jetbrains.kotlin.descriptors.impl.FieldDescriptorImpl
|
|
||||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple property descriptor with backing field without getters/setters for ir generation purposes
|
|
||||||
*/
|
|
||||||
class SimpleSyntheticPropertyDescriptor(
|
|
||||||
owner: ClassDescriptor,
|
|
||||||
name: String,
|
|
||||||
type: KotlinType,
|
|
||||||
isVar: Boolean = false,
|
|
||||||
visibility: DescriptorVisibility = DescriptorVisibilities.PRIVATE
|
|
||||||
) : PropertyDescriptorImpl(
|
|
||||||
owner,
|
|
||||||
null,
|
|
||||||
Annotations.EMPTY,
|
|
||||||
Modality.FINAL,
|
|
||||||
visibility,
|
|
||||||
isVar,
|
|
||||||
Name.identifier(name),
|
|
||||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
|
||||||
owner.source,
|
|
||||||
false, false, false, false, false, false
|
|
||||||
) {
|
|
||||||
|
|
||||||
private val _backingField = FieldDescriptorImpl(Annotations.EMPTY, this)
|
|
||||||
|
|
||||||
init {
|
|
||||||
super.setType(type, emptyList(), owner.thisAsReceiverParameter, null, emptyList())
|
|
||||||
super.initialize(null, null, _backingField, null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+8
-93
@@ -6,15 +6,6 @@
|
|||||||
package org.jetbrains.kotlinx.serialization.compiler.resolve
|
package org.jetbrains.kotlinx.serialization.compiler.resolve
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.lazy.IrMaybeDeserializedClass
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
|
||||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
|
||||||
import org.jetbrains.kotlin.ir.types.isAny
|
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtDeclarationWithInitializer
|
import org.jetbrains.kotlin.psi.KtDeclarationWithInitializer
|
||||||
import org.jetbrains.kotlin.psi.KtParameter
|
import org.jetbrains.kotlin.psi.KtParameter
|
||||||
@@ -26,16 +17,11 @@ import org.jetbrains.kotlin.resolve.source.getPsi
|
|||||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
|
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.getName
|
import org.jetbrains.kotlin.serialization.deserialization.getName
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.isInterface
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.isInitializePropertyFromParameter
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.isInternalSerializable
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.isInternallySerializableEnum
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.SERIALIZABLE_PROPERTIES
|
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.SERIALIZABLE_PROPERTIES
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
|
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginMetadataExtensions
|
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginMetadataExtensions
|
||||||
|
|
||||||
interface ISerializableProperties<D, T, S : ISerializableProperty<D, T>> {
|
interface ISerializableProperties<S : ISerializableProperty> {
|
||||||
val serializableProperties: List<S>
|
val serializableProperties: List<S>
|
||||||
val isExternallySerializable: Boolean
|
val isExternallySerializable: Boolean
|
||||||
val serializableConstructorProperties: List<S>
|
val serializableConstructorProperties: List<S>
|
||||||
@@ -43,7 +29,7 @@ interface ISerializableProperties<D, T, S : ISerializableProperty<D, T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) :
|
class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) :
|
||||||
ISerializableProperties<PropertyDescriptor, KotlinType, SerializableProperty> {
|
ISerializableProperties<SerializableProperty> {
|
||||||
private val primaryConstructorParameters: List<ValueParameterDescriptor> =
|
private val primaryConstructorParameters: List<ValueParameterDescriptor> =
|
||||||
serializableClass.unsubstitutedPrimaryConstructor?.valueParameters ?: emptyList()
|
serializableClass.unsubstitutedPrimaryConstructor?.valueParameters ?: emptyList()
|
||||||
|
|
||||||
@@ -91,7 +77,7 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
|
|||||||
else
|
else
|
||||||
SerializableProperties(supers, bindingContext).serializableProperties + first + second
|
SerializableProperties(supers, bindingContext).serializableProperties + first + second
|
||||||
}
|
}
|
||||||
.let { unsort(serializableClass, it) }
|
.let { restoreCorrectOrderFromClassProtoExtension(serializableClass, it) }
|
||||||
|
|
||||||
isExternallySerializable =
|
isExternallySerializable =
|
||||||
serializableClass.isInternallySerializableEnum() || primaryConstructorParameters.size == primaryConstructorProperties.size
|
serializableClass.isInternallySerializableEnum() || primaryConstructorParameters.size == primaryConstructorProperties.size
|
||||||
@@ -134,7 +120,7 @@ fun PropertyDescriptor.declaresDefaultValue(): Boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal val ISerializableProperties<*, *, *>.goldenMask: Int
|
internal val ISerializableProperties<*>.goldenMask: Int
|
||||||
get() {
|
get() {
|
||||||
var goldenMask = 0
|
var goldenMask = 0
|
||||||
var requiredBit = 1
|
var requiredBit = 1
|
||||||
@@ -147,7 +133,7 @@ internal val ISerializableProperties<*, *, *>.goldenMask: Int
|
|||||||
return goldenMask
|
return goldenMask
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val ISerializableProperties<*, *, *>.goldenMaskList: List<Int>
|
internal val ISerializableProperties<*>.goldenMaskList: List<Int>
|
||||||
get() {
|
get() {
|
||||||
val maskSlotCount = serializableProperties.bitMaskSlotCount()
|
val maskSlotCount = serializableProperties.bitMaskSlotCount()
|
||||||
val goldenMaskList = MutableList(maskSlotCount) { 0 }
|
val goldenMaskList = MutableList(maskSlotCount) { 0 }
|
||||||
@@ -162,7 +148,7 @@ internal val ISerializableProperties<*, *, *>.goldenMaskList: List<Int>
|
|||||||
return goldenMaskList
|
return goldenMaskList
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun List<ISerializableProperty<*, *>>.bitMaskSlotCount() = size / 32 + 1
|
internal fun List<ISerializableProperty>.bitMaskSlotCount() = size / 32 + 1
|
||||||
internal fun bitMaskSlotAt(propertyIndex: Int) = propertyIndex / 32
|
internal fun bitMaskSlotAt(propertyIndex: Int) = propertyIndex / 32
|
||||||
|
|
||||||
internal fun BindingContext.serializablePropertiesFor(
|
internal fun BindingContext.serializablePropertiesFor(
|
||||||
@@ -174,81 +160,10 @@ internal fun BindingContext.serializablePropertiesFor(
|
|||||||
return props
|
return props
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unsort(descriptor: ClassDescriptor, props: List<SerializableProperty>): List<SerializableProperty> {
|
internal fun <P: ISerializableProperty> restoreCorrectOrderFromClassProtoExtension(descriptor: ClassDescriptor, props: List<P>): List<P> {
|
||||||
if (descriptor !is DeserializedClassDescriptor) return props
|
if (descriptor !is DeserializedClassDescriptor) return props
|
||||||
val correctOrder: List<Name> = descriptor.classProto.getExtension(SerializationPluginMetadataExtensions.propertiesNamesInProgramOrder)
|
val correctOrder: List<Name> = descriptor.classProto.getExtension(SerializationPluginMetadataExtensions.propertiesNamesInProgramOrder)
|
||||||
.map { descriptor.c.nameResolver.getName(it) }
|
.map { descriptor.c.nameResolver.getName(it) }
|
||||||
val propsMap = props.associateBy { it.descriptor.name }
|
val propsMap = props.associateBy { it.originalDescriptorName }
|
||||||
return correctOrder.map { propsMap.getValue(it) }
|
return correctOrder.map { propsMap.getValue(it) }
|
||||||
}
|
|
||||||
|
|
||||||
class IrSerializableProperties(
|
|
||||||
override val serializableProperties: List<IrSerializableProperty>,
|
|
||||||
override val isExternallySerializable: Boolean,
|
|
||||||
override val serializableConstructorProperties: List<IrSerializableProperty>,
|
|
||||||
override val serializableStandaloneProperties: List<IrSerializableProperty>
|
|
||||||
) : ISerializableProperties<IrProperty, IrSimpleType, IrSerializableProperty> {
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun serializablePropertiesForIrBackend(
|
|
||||||
classDescriptor: IrClass,
|
|
||||||
serializationDescriptorSerializer: SerializationDescriptorSerializerPlugin? = null
|
|
||||||
): IrSerializableProperties {
|
|
||||||
val properties = classDescriptor.properties.toList()
|
|
||||||
val primaryConstructorParams = classDescriptor.primaryConstructor?.valueParameters.orEmpty()
|
|
||||||
val primaryParamsAsProps = properties.associateBy { it.name }.let { namesMap ->
|
|
||||||
primaryConstructorParams.mapNotNull {
|
|
||||||
if (it.name !in namesMap) null else namesMap.getValue(it.name) to it.hasDefaultValue()
|
|
||||||
}.toMap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isPropSerializable(it: IrProperty) =
|
|
||||||
if (classDescriptor.isInternalSerializable) !it.annotations.hasAnnotation(SerializationAnnotations.serialTransientFqName)
|
|
||||||
else !DescriptorVisibilities.isPrivate(it.visibility) && ((it.isVar && !it.annotations.hasAnnotation(SerializationAnnotations.serialTransientFqName)) || primaryParamsAsProps.contains(
|
|
||||||
it
|
|
||||||
))
|
|
||||||
|
|
||||||
val (primaryCtorSerializableProps, bodySerializableProps) = properties
|
|
||||||
.asSequence()
|
|
||||||
.filter { !it.isFakeOverride && !it.isDelegated }
|
|
||||||
.filter(::isPropSerializable)
|
|
||||||
.map {
|
|
||||||
val isConstructorParameterWithDefault = primaryParamsAsProps[it] ?: false
|
|
||||||
// FIXME: workaround because IrLazyProperty doesn't deserialize information about backing fields. Fallback to descriptor won't work with FIR.
|
|
||||||
val isPropertyFromAnotherModuleDeclaresDefaultValue = it.descriptor is DeserializedPropertyDescriptor && it.descriptor.declaresDefaultValue()
|
|
||||||
val isPropertyWithBackingFieldFromAnotherModule = it.descriptor is DeserializedPropertyDescriptor && (it.descriptor.backingField != null || isPropertyFromAnotherModuleDeclaresDefaultValue)
|
|
||||||
IrSerializableProperty(
|
|
||||||
it,
|
|
||||||
isConstructorParameterWithDefault,
|
|
||||||
it.backingField != null || isPropertyWithBackingFieldFromAnotherModule,
|
|
||||||
it.backingField?.initializer.let { init -> init != null && !init.expression.isInitializePropertyFromParameter() } || isConstructorParameterWithDefault
|
|
||||||
|| isPropertyFromAnotherModuleDeclaresDefaultValue
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.filterNot { it.transient }
|
|
||||||
.partition { primaryParamsAsProps.contains(it.descriptor) }
|
|
||||||
|
|
||||||
val serializableProps = run {
|
|
||||||
val supers = classDescriptor.getParentClassNotAny()
|
|
||||||
if (supers == null || !supers.isInternalSerializable)
|
|
||||||
primaryCtorSerializableProps + bodySerializableProps
|
|
||||||
else
|
|
||||||
serializablePropertiesForIrBackend(
|
|
||||||
supers,
|
|
||||||
serializationDescriptorSerializer
|
|
||||||
).serializableProperties + primaryCtorSerializableProps + bodySerializableProps
|
|
||||||
} // todo: implement unsorting
|
|
||||||
|
|
||||||
val isExternallySerializable =
|
|
||||||
classDescriptor.isInternallySerializableEnum() || primaryConstructorParams.size == primaryParamsAsProps.size
|
|
||||||
|
|
||||||
return IrSerializableProperties(serializableProps, isExternallySerializable, primaryCtorSerializableProps, bodySerializableProps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun IrClass.getParentClassNotAny(): IrClass? {
|
|
||||||
val parentClass =
|
|
||||||
superTypes
|
|
||||||
.mapNotNull { it.classOrNull?.owner }
|
|
||||||
.singleOrNull { it.kind == ClassKind.CLASS || it.kind == ClassKind.ENUM_CLASS } ?: return null
|
|
||||||
return if (parentClass.defaultType.isAny()) null else parentClass
|
|
||||||
}
|
}
|
||||||
+15
-41
@@ -16,58 +16,32 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlinx.serialization.compiler.resolve
|
package org.jetbrains.kotlinx.serialization.compiler.resolve
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
|
||||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
|
||||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
|
||||||
import org.jetbrains.kotlin.psi.ValueArgument
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.analyzeSpecialSerializers
|
import org.jetbrains.kotlinx.serialization.compiler.backend.common.analyzeSpecialSerializers
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.genericIndex
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.serialNameValue
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.serializableWith
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
|
||||||
|
|
||||||
class SerializableProperty(
|
interface ISerializableProperty {
|
||||||
override val descriptor: PropertyDescriptor,
|
|
||||||
override val isConstructorParameterWithDefault: Boolean,
|
|
||||||
hasBackingField: Boolean,
|
|
||||||
declaresDefaultValue: Boolean
|
|
||||||
) : ISerializableProperty<PropertyDescriptor, KotlinType> {
|
|
||||||
override val name = descriptor.annotations.serialNameValue ?: descriptor.name.asString()
|
|
||||||
override val type = descriptor.type
|
|
||||||
override val genericIndex = type.genericIndex
|
|
||||||
val module = descriptor.module
|
|
||||||
val serializableWith = descriptor.serializableWith ?: analyzeSpecialSerializers(module, descriptor.annotations)?.defaultType
|
|
||||||
override val optional = !descriptor.annotations.serialRequired && declaresDefaultValue
|
|
||||||
override val transient = descriptor.annotations.serialTransient || !hasBackingField
|
|
||||||
val annotationsWithArguments: List<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> =
|
|
||||||
descriptor.annotationsWithArguments()
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ISerializableProperty<D, T> {
|
|
||||||
val descriptor: D
|
|
||||||
val isConstructorParameterWithDefault: Boolean
|
val isConstructorParameterWithDefault: Boolean
|
||||||
val name: String
|
val name: String
|
||||||
val type: T
|
val originalDescriptorName: Name
|
||||||
val genericIndex: Int?
|
|
||||||
val optional: Boolean
|
val optional: Boolean
|
||||||
val transient: Boolean
|
val transient: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrSerializableProperty(
|
class SerializableProperty(
|
||||||
override val descriptor: IrProperty,
|
val descriptor: PropertyDescriptor,
|
||||||
override val isConstructorParameterWithDefault: Boolean,
|
override val isConstructorParameterWithDefault: Boolean,
|
||||||
hasBackingField: Boolean,
|
hasBackingField: Boolean,
|
||||||
declaresDefaultValue: Boolean
|
declaresDefaultValue: Boolean
|
||||||
) : ISerializableProperty<IrProperty, IrSimpleType> {
|
) : ISerializableProperty {
|
||||||
override val name = descriptor.annotations.serialNameValue ?: descriptor.name.asString()
|
override val name = descriptor.annotations.serialNameValue ?: descriptor.name.asString()
|
||||||
override val type = descriptor.getter!!.returnType as IrSimpleType
|
override val originalDescriptorName: Name = descriptor.name
|
||||||
override val genericIndex = type.genericIndex
|
val type = descriptor.type
|
||||||
fun serializableWith(ctx: SerializationPluginContext) = descriptor.annotations.serializableWith() ?: analyzeSpecialSerializers(ctx, descriptor.annotations)
|
val genericIndex = type.genericIndex
|
||||||
override val optional = !descriptor.annotations.hasAnnotation(SerializationAnnotations.requiredAnnotationFqName) && declaresDefaultValue
|
val module = descriptor.module
|
||||||
override val transient = descriptor.annotations.hasAnnotation(SerializationAnnotations.serialTransientFqName) || !hasBackingField
|
val serializableWith = descriptor.serializableWith ?: analyzeSpecialSerializers(module, descriptor.annotations)?.defaultType
|
||||||
}
|
override val optional = !descriptor.annotations.serialRequired && declaresDefaultValue
|
||||||
|
override val transient = descriptor.annotations.serialTransient || !hasBackingField
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -6,9 +6,10 @@
|
|||||||
package org.jetbrains.kotlinx.serialization;
|
package org.jetbrains.kotlinx.serialization;
|
||||||
|
|
||||||
import com.intellij.testFramework.TestDataPath;
|
import com.intellij.testFramework.TestDataPath;
|
||||||
|
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||||
import org.jetbrains.kotlin.test.TargetBackend;
|
import org.jetbrains.kotlin.test.TargetBackend;
|
||||||
import org.jetbrains.kotlin.test.TestMetadata;
|
import org.jetbrains.kotlin.test.TestMetadata;
|
||||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|||||||
+15
-5
@@ -326,7 +326,9 @@ final class Result$Companion$$cachedSerializer$delegate$1 : kotlin/jvm/internal/
|
|||||||
DUP
|
DUP
|
||||||
LDC (Result.Err)
|
LDC (Result.Err)
|
||||||
GETSTATIC (Result$Err, INSTANCE, LResult$Err;)
|
GETSTATIC (Result$Err, INSTANCE, LResult$Err;)
|
||||||
INVOKESPECIAL (kotlinx/serialization/internal/ObjectSerializer, <init>, (Ljava/lang/String;Ljava/lang/Object;)V)
|
ICONST_0
|
||||||
|
ANEWARRAY (java/lang/annotation/Annotation)
|
||||||
|
INVOKESPECIAL (kotlinx/serialization/internal/ObjectSerializer, <init>, (Ljava/lang/String;Ljava/lang/Object;[Ljava/lang/annotation/Annotation;)V)
|
||||||
CHECKCAST (kotlinx/serialization/KSerializer)
|
CHECKCAST (kotlinx/serialization/KSerializer)
|
||||||
AASTORE
|
AASTORE
|
||||||
ALOAD (1)
|
ALOAD (1)
|
||||||
@@ -335,7 +337,9 @@ final class Result$Companion$$cachedSerializer$delegate$1 : kotlin/jvm/internal/
|
|||||||
CHECKCAST (kotlinx/serialization/KSerializer)
|
CHECKCAST (kotlinx/serialization/KSerializer)
|
||||||
AASTORE
|
AASTORE
|
||||||
ALOAD (1)
|
ALOAD (1)
|
||||||
INVOKESPECIAL (kotlinx/serialization/SealedClassSerializer, <init>, (Ljava/lang/String;Lkotlin/reflect/KClass;[Lkotlin/reflect/KClass;[Lkotlinx/serialization/KSerializer;)V)
|
ICONST_0
|
||||||
|
ANEWARRAY (java/lang/annotation/Annotation)
|
||||||
|
INVOKESPECIAL (kotlinx/serialization/SealedClassSerializer, <init>, (Ljava/lang/String;Lkotlin/reflect/KClass;[Lkotlin/reflect/KClass;[Lkotlinx/serialization/KSerializer;[Ljava/lang/annotation/Annotation;)V)
|
||||||
CHECKCAST (kotlinx/serialization/KSerializer)
|
CHECKCAST (kotlinx/serialization/KSerializer)
|
||||||
ARETURN
|
ARETURN
|
||||||
LABEL (L1)
|
LABEL (L1)
|
||||||
@@ -410,7 +414,9 @@ final class Result$Err$$cachedSerializer$delegate$1 : kotlin/jvm/internal/Lambda
|
|||||||
DUP
|
DUP
|
||||||
LDC (Result.Err)
|
LDC (Result.Err)
|
||||||
GETSTATIC (Result$Err, INSTANCE, LResult$Err;)
|
GETSTATIC (Result$Err, INSTANCE, LResult$Err;)
|
||||||
INVOKESPECIAL (kotlinx/serialization/internal/ObjectSerializer, <init>, (Ljava/lang/String;Ljava/lang/Object;)V)
|
ICONST_0
|
||||||
|
ANEWARRAY (java/lang/annotation/Annotation)
|
||||||
|
INVOKESPECIAL (kotlinx/serialization/internal/ObjectSerializer, <init>, (Ljava/lang/String;Ljava/lang/Object;[Ljava/lang/annotation/Annotation;)V)
|
||||||
CHECKCAST (kotlinx/serialization/KSerializer)
|
CHECKCAST (kotlinx/serialization/KSerializer)
|
||||||
ARETURN
|
ARETURN
|
||||||
LABEL (L1)
|
LABEL (L1)
|
||||||
@@ -859,7 +865,9 @@ public final class X$Companion : java/lang/Object {
|
|||||||
DUP
|
DUP
|
||||||
LDC (Result.Err)
|
LDC (Result.Err)
|
||||||
GETSTATIC (Result$Err, INSTANCE, LResult$Err;)
|
GETSTATIC (Result$Err, INSTANCE, LResult$Err;)
|
||||||
INVOKESPECIAL (kotlinx/serialization/internal/ObjectSerializer, <init>, (Ljava/lang/String;Ljava/lang/Object;)V)
|
ICONST_0
|
||||||
|
ANEWARRAY (java/lang/annotation/Annotation)
|
||||||
|
INVOKESPECIAL (kotlinx/serialization/internal/ObjectSerializer, <init>, (Ljava/lang/String;Ljava/lang/Object;[Ljava/lang/annotation/Annotation;)V)
|
||||||
CHECKCAST (kotlinx/serialization/KSerializer)
|
CHECKCAST (kotlinx/serialization/KSerializer)
|
||||||
AASTORE
|
AASTORE
|
||||||
ALOAD (1)
|
ALOAD (1)
|
||||||
@@ -868,7 +876,9 @@ public final class X$Companion : java/lang/Object {
|
|||||||
CHECKCAST (kotlinx/serialization/KSerializer)
|
CHECKCAST (kotlinx/serialization/KSerializer)
|
||||||
AASTORE
|
AASTORE
|
||||||
ALOAD (1)
|
ALOAD (1)
|
||||||
INVOKESPECIAL (kotlinx/serialization/SealedClassSerializer, <init>, (Ljava/lang/String;Lkotlin/reflect/KClass;[Lkotlin/reflect/KClass;[Lkotlinx/serialization/KSerializer;)V)
|
ICONST_0
|
||||||
|
ANEWARRAY (java/lang/annotation/Annotation)
|
||||||
|
INVOKESPECIAL (kotlinx/serialization/SealedClassSerializer, <init>, (Ljava/lang/String;Lkotlin/reflect/KClass;[Lkotlin/reflect/KClass;[Lkotlinx/serialization/KSerializer;[Ljava/lang/annotation/Annotation;)V)
|
||||||
CHECKCAST (kotlinx/serialization/KSerializer)
|
CHECKCAST (kotlinx/serialization/KSerializer)
|
||||||
ARETURN
|
ARETURN
|
||||||
LABEL (L1)
|
LABEL (L1)
|
||||||
|
|||||||
Reference in New Issue
Block a user