Remove BindingContext, KotlinType and *Descriptor from IR plugin dependencies

This commit is contained in:
Leonid Startsev
2022-06-22 21:58:59 +02:00
committed by Space
parent 6f6342dafc
commit cefc372632
27 changed files with 1185 additions and 504 deletions
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
@@ -41,6 +42,7 @@ class Fir2IrPluginContext(private val components: Fir2IrComponents) : IrPluginCo
override val moduleDescriptor: ModuleDescriptor override val moduleDescriptor: ModuleDescriptor
get() = error(ERROR_MESSAGE) get() = error(ERROR_MESSAGE)
@Suppress("OVERRIDE_DEPRECATION")
@ObsoleteDescriptorBasedAPI @ObsoleteDescriptorBasedAPI
override val bindingContext: BindingContext override val bindingContext: BindingContext
get() = error(ERROR_MESSAGE) get() = error(ERROR_MESSAGE)
@@ -67,7 +69,8 @@ class Fir2IrPluginContext(private val components: Fir2IrComponents) : IrPluginCo
get() = components.session.symbolProvider get() = components.session.symbolProvider
override fun referenceClass(classId: ClassId): IrClassSymbol? { override fun referenceClass(classId: ClassId): IrClassSymbol? {
return referenceClassLikeSymbol(classId, symbolProvider::getClassLikeSymbolByClassId, symbolTable::referenceClass) val firSymbol = symbolProvider.getClassLikeSymbolByClassId(classId) as? FirClassSymbol<*> ?: return null
return components.classifierStorage.getIrClassSymbol(firSymbol)
} }
override fun referenceTypeAlias(classId: ClassId): IrTypeAliasSymbol? { override fun referenceTypeAlias(classId: ClassId): IrTypeAliasSymbol? {
@@ -135,6 +138,8 @@ class Fir2IrPluginContext(private val components: Fir2IrComponents) : IrPluginCo
error(ERROR_MESSAGE) error(ERROR_MESSAGE)
} }
@Deprecated("Use classId overload instead")
override fun referenceClass(fqName: FqName): IrClassSymbol? { override fun referenceClass(fqName: FqName): IrClassSymbol? {
error(ERROR_MESSAGE) error(ERROR_MESSAGE)
} }
@@ -147,10 +152,12 @@ class Fir2IrPluginContext(private val components: Fir2IrComponents) : IrPluginCo
error(ERROR_MESSAGE) error(ERROR_MESSAGE)
} }
@Deprecated("Use callableId overload instead")
override fun referenceFunctions(fqName: FqName): Collection<IrSimpleFunctionSymbol> { override fun referenceFunctions(fqName: FqName): Collection<IrSimpleFunctionSymbol> {
error(ERROR_MESSAGE) error(ERROR_MESSAGE)
} }
@Deprecated("Use callableId overload instead")
override fun referenceProperties(fqName: FqName): Collection<IrPropertySymbol> { override fun referenceProperties(fqName: FqName): Collection<IrPropertySymbol> {
error(ERROR_MESSAGE) error(ERROR_MESSAGE)
} }
@@ -29,11 +29,13 @@ interface IrPluginContext : IrGeneratorContext {
val moduleDescriptor: ModuleDescriptor val moduleDescriptor: ModuleDescriptor
@ObsoleteDescriptorBasedAPI @ObsoleteDescriptorBasedAPI
@Deprecated("", level = DeprecationLevel.ERROR)
val bindingContext: BindingContext val bindingContext: BindingContext
val symbolTable: ReferenceSymbolTable val symbolTable: ReferenceSymbolTable
@ObsoleteDescriptorBasedAPI @ObsoleteDescriptorBasedAPI
// @Deprecated("", level = DeprecationLevel.ERROR)
val typeTranslator: TypeTranslator val typeTranslator: TypeTranslator
val symbols: BuiltinSymbolsBase val symbols: BuiltinSymbolsBase
@@ -49,10 +51,13 @@ interface IrPluginContext : IrGeneratorContext {
fun createDiagnosticReporter(pluginId: String): IrMessageLogger fun createDiagnosticReporter(pluginId: String): IrMessageLogger
// The following API is experimental // The following API is experimental
@Deprecated("Use classId overload instead")
fun referenceClass(fqName: FqName): IrClassSymbol? fun referenceClass(fqName: FqName): IrClassSymbol?
fun referenceTypeAlias(fqName: FqName): IrTypeAliasSymbol? fun referenceTypeAlias(fqName: FqName): IrTypeAliasSymbol?
fun referenceConstructors(classFqn: FqName): Collection<IrConstructorSymbol> fun referenceConstructors(classFqn: FqName): Collection<IrConstructorSymbol>
@Deprecated("Use callableId overload instead")
fun referenceFunctions(fqName: FqName): Collection<IrSimpleFunctionSymbol> fun referenceFunctions(fqName: FqName): Collection<IrSimpleFunctionSymbol>
@Deprecated("Use callableId overload instead")
fun referenceProperties(fqName: FqName): Collection<IrPropertySymbol> fun referenceProperties(fqName: FqName): Collection<IrPropertySymbol>
// This one is experimental too // This one is experimental too
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
open class IrPluginContextImpl constructor( open class IrPluginContextImpl constructor(
private val module: ModuleDescriptor, private val module: ModuleDescriptor,
@Deprecated("", level = DeprecationLevel.ERROR)
@OptIn(ObsoleteDescriptorBasedAPI::class) @OptIn(ObsoleteDescriptorBasedAPI::class)
override val bindingContext: BindingContext, override val bindingContext: BindingContext,
override val languageVersionSettings: LanguageVersionSettings, override val languageVersionSettings: LanguageVersionSettings,
@@ -97,6 +98,7 @@ open class IrPluginContextImpl constructor(
return symbols return symbols
} }
@Deprecated("Use classId overload instead")
@OptIn(ObsoleteDescriptorBasedAPI::class) @OptIn(ObsoleteDescriptorBasedAPI::class)
override fun referenceClass(fqName: FqName): IrClassSymbol? { override fun referenceClass(fqName: FqName): IrClassSymbol? {
assert(!fqName.isRoot) assert(!fqName.isRoot)
@@ -120,10 +122,12 @@ open class IrPluginContextImpl constructor(
} }
override fun referenceConstructors(classFqn: FqName): Collection<IrConstructorSymbol> { override fun referenceConstructors(classFqn: FqName): Collection<IrConstructorSymbol> {
@Suppress("DEPRECATION")
val classSymbol = referenceClass(classFqn) ?: error("Cannot find class $classFqn") val classSymbol = referenceClass(classFqn) ?: error("Cannot find class $classFqn")
return classSymbol.owner.declarations.filterIsInstance<IrConstructor>().map { it.symbol } return classSymbol.owner.declarations.filterIsInstance<IrConstructor>().map { it.symbol }
} }
@Deprecated("Use callableId overload instead")
@OptIn(ObsoleteDescriptorBasedAPI::class) @OptIn(ObsoleteDescriptorBasedAPI::class)
override fun referenceFunctions(fqName: FqName): Collection<IrSimpleFunctionSymbol> { override fun referenceFunctions(fqName: FqName): Collection<IrSimpleFunctionSymbol> {
assert(!fqName.isRoot) assert(!fqName.isRoot)
@@ -133,6 +137,7 @@ open class IrPluginContextImpl constructor(
} }
} }
@Deprecated("Use callableId overload instead")
@OptIn(ObsoleteDescriptorBasedAPI::class) @OptIn(ObsoleteDescriptorBasedAPI::class)
override fun referenceProperties(fqName: FqName): Collection<IrPropertySymbol> { override fun referenceProperties(fqName: FqName): Collection<IrPropertySymbol> {
assert(!fqName.isRoot) assert(!fqName.isRoot)
@@ -143,6 +148,7 @@ open class IrPluginContextImpl constructor(
} }
override fun referenceClass(classId: ClassId): IrClassSymbol? { override fun referenceClass(classId: ClassId): IrClassSymbol? {
@Suppress("DEPRECATION")
return referenceClass(classId.asSingleFqName()) return referenceClass(classId.asSingleFqName())
} }
@@ -155,10 +161,12 @@ open class IrPluginContextImpl constructor(
} }
override fun referenceFunctions(callableId: CallableId): Collection<IrSimpleFunctionSymbol> { override fun referenceFunctions(callableId: CallableId): Collection<IrSimpleFunctionSymbol> {
@Suppress("DEPRECATION")
return referenceFunctions(callableId.asSingleFqName()) return referenceFunctions(callableId.asSingleFqName())
} }
override fun referenceProperties(callableId: CallableId): Collection<IrPropertySymbol> { override fun referenceProperties(callableId: CallableId): Collection<IrPropertySymbol> {
@Suppress("DEPRECATION")
return referenceProperties(callableId.asSingleFqName()) return referenceProperties(callableId.asSingleFqName())
} }
@@ -120,6 +120,7 @@ private class AndroidIrTransformer(val extension: AndroidIrExtension, val plugin
} }
// NOTE: sparse array version intentionally not implemented; this plugin is deprecated // NOTE: sparse array version intentionally not implemented; this plugin is deprecated
@Suppress("DEPRECATION") // TODO: check that it still works with FIR
private val mapFactory = pluginContext.referenceFunctions(FqName("kotlin.collections.mutableMapOf")) private val mapFactory = pluginContext.referenceFunctions(FqName("kotlin.collections.mutableMapOf"))
.single { it.owner.valueParameters.isEmpty() } .single { it.owner.valueParameters.isEmpty() }
private val mapGet = pluginContext.irBuiltIns.mapClass.owner.functions private val mapGet = pluginContext.irBuiltIns.mapClass.owner.functions
@@ -14,6 +14,7 @@ dependencies {
compileOnly(project(":compiler:frontend")) compileOnly(project(":compiler:frontend"))
compileOnly(project(":compiler:backend")) compileOnly(project(":compiler:backend"))
compileOnly(project(":compiler:ir.backend.common")) compileOnly(project(":compiler:ir.backend.common"))
compileOnly(project(":compiler:backend.jvm"))
compileOnly(project(":compiler:ir.tree")) compileOnly(project(":compiler:ir.tree"))
compileOnly(project(":js:js.frontend")) compileOnly(project(":js:js.frontend"))
compileOnly(project(":js:js.translator")) compileOnly(project(":js:js.translator"))
@@ -22,9 +22,12 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotat
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 AbstractSerialGenerator(val bindingContext: BindingContext, val currentDeclaration: ClassDescriptor) { const val K2_ERR_MESSAGE = "K2 not supported yet.\nBindingContext is null, meaning this function is used from the K2 compiler. Please report to devs so we can support this feature."
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
val annotation = AnnotationsUtils val annotation = AnnotationsUtils
.getContainingFileAnnotations(bindingContext, declarationInFile) .getContainingFileAnnotations(bindingContext, declarationInFile)
.find { it.fqName == annotationFqName } .find { it.fqName == annotationFqName }
@@ -16,7 +16,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.*
abstract class SerializableCodegen( abstract class SerializableCodegen(
protected val serializableDescriptor: ClassDescriptor, protected val serializableDescriptor: ClassDescriptor,
bindingContext: BindingContext bindingContext: BindingContext?
) : AbstractSerialGenerator(bindingContext, serializableDescriptor) { ) : AbstractSerialGenerator(bindingContext, serializableDescriptor) {
protected val properties = bindingContext.serializablePropertiesFor(serializableDescriptor) protected val properties = bindingContext.serializablePropertiesFor(serializableDescriptor)
@@ -8,6 +8,7 @@ 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.*
@@ -15,12 +16,12 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SE
abstract class SerializableCompanionCodegen( abstract class SerializableCompanionCodegen(
protected val companionDescriptor: ClassDescriptor, protected val companionDescriptor: ClassDescriptor,
bindingContext: BindingContext bindingContext: BindingContext?
) : AbstractSerialGenerator(bindingContext, companionDescriptor) { ) : AbstractSerialGenerator(bindingContext, companionDescriptor) {
protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorByCompanion(companionDescriptor)!! protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorByCompanion(companionDescriptor)!!
fun generate() { open fun getSerializerGetterDescriptor(): FunctionDescriptor {
val serializerGetterDescriptor = companionDescriptor.unsubstitutedMemberScope.getContributedFunctions( return companionDescriptor.unsubstitutedMemberScope.getContributedFunctions(
SERIALIZER_PROVIDER_NAME, SERIALIZER_PROVIDER_NAME,
NoLookupLocation.FROM_BACKEND NoLookupLocation.FROM_BACKEND
).firstOrNull { ).firstOrNull {
@@ -32,6 +33,10 @@ abstract class SerializableCompanionCodegen(
"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() {
val serializerGetterDescriptor = getSerializerGetterDescriptor()
if (serializableDescriptor.isSerializableObject if (serializableDescriptor.isSerializableObject
|| serializableDescriptor.isAbstractOrSealedSerializableClass() || serializableDescriptor.isAbstractOrSealedSerializableClass()
@@ -16,7 +16,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.*
abstract class SerializerCodegen( abstract class SerializerCodegen(
protected val serializerDescriptor: ClassDescriptor, protected val serializerDescriptor: ClassDescriptor,
bindingContext: BindingContext, bindingContext: BindingContext?,
metadataPlugin: SerializationDescriptorSerializerPlugin? metadataPlugin: SerializationDescriptorSerializerPlugin?
) : AbstractSerialGenerator(bindingContext, serializerDescriptor) { ) : AbstractSerialGenerator(bindingContext, serializerDescriptor) {
val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!! val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!!
@@ -6,10 +6,15 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.common package org.jetbrains.kotlinx.serialization.compiler.backend.common
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.builtins.KotlinBuiltIns 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.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
@@ -21,17 +26,32 @@ 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(
val property: SerializableProperty, override val property: SerializableProperty,
val elementMethodPrefix: String, override val elementMethodPrefix: String,
val serializer: ClassDescriptor? = null override 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 }
@@ -46,6 +66,33 @@ fun AbstractSerialGenerator.findAddOnSerializer(propertyType: KotlinType, module
fun KotlinType.isGeneratedSerializableObject() = fun KotlinType.isGeneratedSerializableObject() =
toClassDescriptor?.run { kind == ClassKind.OBJECT && hasSerializableOrMetaAnnotationWithoutArgs } == true toClassDescriptor?.run { kind == ClassKind.OBJECT && hasSerializableOrMetaAnnotationWithoutArgs } == true
fun AbstractSerialGenerator.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?.let { return SerializableInfo(it.classOrNull!!) }
// TODO findAddOnSerializer(T, property.module)?.let { return SerializableInfo(it) }
T.overridenSerializer?.let { return SerializableInfo(it.classOrNull!!) }
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?.classOrNull ?: ctx.getClassFromRuntime(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?) =
@@ -155,20 +202,32 @@ fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescri
val stdSer = findStandardKotlinTypeSerializer(module, kType) // see if there is a standard serializer val stdSer = findStandardKotlinTypeSerializer(module, kType) // see if there is a standard serializer
?: findEnumTypeSerializer(module, kType) ?: findEnumTypeSerializer(module, kType)
if (stdSer != null) return stdSer if (stdSer != null) return stdSer
if (kType.isInterface() && kType.toClassDescriptor?.isSealedSerializableInterface == false) return module.getClassFromSerializationPackage(SpecialBuiltins.polymorphicSerializer) if (kType.isInterface() && kType.toClassDescriptor?.isSealedSerializableInterface == false) return module.getClassFromSerializationPackage(
SpecialBuiltins.polymorphicSerializer
)
return kType.toClassDescriptor?.classSerializer // check for serializer defined on the type return kType.toClassDescriptor?.classSerializer // check for serializer defined on the type
} }
fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? { fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? {
val name = when (kType.getJetTypeFqName(false)) { val typeName = kType.getJetTypeFqName(false)
"Z" -> if (kType.isBoolean()) "BooleanSerializer" else return null val name = when (typeName) {
"B" -> if (kType.isByte()) "ByteSerializer" else return null "Z" -> if (kType.isBoolean()) "BooleanSerializer" else null
"S" -> if (kType.isShort()) "ShortSerializer" else return null "B" -> if (kType.isByte()) "ByteSerializer" else null
"I" -> if (kType.isInt()) "IntSerializer" else return null "S" -> if (kType.isShort()) "ShortSerializer" else null
"J" -> if (kType.isLong()) "LongSerializer" else return null "I" -> if (kType.isInt()) "IntSerializer" else null
"F" -> if (kType.isFloat()) "FloatSerializer" else return null "J" -> if (kType.isLong()) "LongSerializer" else null
"D" -> if (kType.isDouble()) "DoubleSerializer" else return null "F" -> if (kType.isFloat()) "FloatSerializer" else null
"C" -> if (kType.isChar()) "CharSerializer" else return null "D" -> if (kType.isDouble()) "DoubleSerializer" else null
"C" -> if (kType.isChar()) "CharSerializer" else null
else -> findStandardKotlinTypeSerializer(typeName)
} ?: return null
val identifier = Name.identifier(name)
return module.findClassAcrossModuleDependencies(ClassId(internalPackageFqName, identifier))
?: module.findClassAcrossModuleDependencies(ClassId(SerializationPackages.packageFqName, identifier))
}
fun findStandardKotlinTypeSerializer(typeName: String): String? {
return when (typeName) {
"kotlin.Unit" -> "UnitSerializer" "kotlin.Unit" -> "UnitSerializer"
"kotlin.Nothing" -> "NothingSerializer" "kotlin.Nothing" -> "NothingSerializer"
"kotlin.Boolean" -> "BooleanSerializer" "kotlin.Boolean" -> "BooleanSerializer"
@@ -223,9 +282,6 @@ fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType
"java.util.Map.Entry" -> "MapEntrySerializer" "java.util.Map.Entry" -> "MapEntrySerializer"
else -> return null else -> return null
} }
val identifier = Name.identifier(name)
return module.findClassAcrossModuleDependencies(ClassId(internalPackageFqName, identifier))
?: module.findClassAcrossModuleDependencies(ClassId(SerializationPackages.packageFqName, identifier))
} }
fun findEnumTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? { fun findEnumTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? {
@@ -0,0 +1,326 @@
/*
* 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.common
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.codegen.CompilationException
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
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.util.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.objectSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.polymorphicSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.fir.SerializationPluginKey
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
fun AbstractSerialGenerator.findTypeSerializerOrContextUnchecked(
context: SerializationPluginContext, kType: IrType
): IrClassSymbol? {
val annotations = kType.annotations
if (kType.isTypeParameter()) return null
annotations.serializableWith()?.let { return it.classOrNull }
additionalSerializersInScopeOfCurrentFile[kType.classOrNull?.descriptor to kType.isMarkedNullable()]?.let {
return context.referenceClass(
ClassId.topLevel(it.fqNameSafe)
)
}
if (kType.isMarkedNullable()) return findTypeSerializerOrContextUnchecked(context, kType.makeNotNull())
if (kType.toKotlinType() in contextualKClassListInCurrentFile) return context.referenceClass(contextSerializerId)
return analyzeSpecialSerializers(context, annotations) ?: findTypeSerializer(context, kType)
}
fun analyzeSpecialSerializers(
context: SerializationPluginContext,
annotations: List<IrConstructorCall>
): IrClassSymbol? = when {
annotations.hasAnnotation(SerializationAnnotations.contextualFqName) || annotations.hasAnnotation(SerializationAnnotations.contextualOnPropertyFqName) ->
context.referenceClass(contextSerializerId)
// can be annotation on type usage, e.g. List<@Polymorphic Any>
annotations.hasAnnotation(SerializationAnnotations.polymorphicFqName) ->
context.referenceClass(polymorphicSerializerId)
else -> null
}
fun AbstractSerialGenerator.findTypeSerializerOrContext(
context: SerializationPluginContext, kType: IrType,
sourceElement: PsiElement? = null
): IrClassSymbol? {
if (kType.isTypeParameter()) return null
return findTypeSerializerOrContextUnchecked(context, kType) ?: throw CompilationException(
"Serializer for element of type $kType has not been found.\n" +
"To use context serializer as fallback, explicitly annotate element with @Contextual",
null,
sourceElement
)
}
fun findTypeSerializer(context: SerializationPluginContext, type: IrType): IrClassSymbol? {
val userOverride = type.overridenSerializer
if (userOverride != null) return userOverride.classOrNull
if (type.isTypeParameter()) return null
if (type.isArray()) return context.referenceClass(referenceArraySerializerId)
if (type.isGeneratedSerializableObject()) return context.referenceClass(objectSerializerId)
val stdSer = findStandardKotlinTypeSerializer(context, type) // see if there is a standard serializer
?: findEnumTypeSerializer(context, type)
if (stdSer != null) return stdSer
if (type.isInterface() && type.classOrNull?.owner?.isSealedSerializableInterface == false) return context.referenceClass(
polymorphicSerializerId
)
return type.classOrNull?.owner.classSerializer(context) // check for serializer defined on the type
}
internal fun IrClass?.classSerializer(context: SerializationPluginContext): IrClassSymbol? = this?.let {
// serializer annotation on class?
serializableWith?.let { return it.classOrNull }
// companion object serializer?
if (hasCompanionObjectAsSerializer) return companionObject()?.symbol
// can infer @Poly?
polymorphicSerializerIfApplicableAutomatically(context)?.let { return it }
// default serializable?
if (shouldHaveGeneratedSerializer) {
// $serializer nested class
return this.declarations
.filterIsInstance<IrClass>()
.singleOrNull { it.name == SerialEntityNames.SERIALIZER_CLASS_NAME }?.symbol
}
return null
}
internal val IrClass.shouldHaveGeneratedSerializer: Boolean
get() = (isInternalSerializable && (modality == Modality.FINAL || modality == Modality.OPEN))
|| isEnumWithLegacyGeneratedSerializer()
internal fun IrClass.polymorphicSerializerIfApplicableAutomatically(context: SerializationPluginContext): IrClassSymbol? {
val serializer = when {
kind == ClassKind.INTERFACE && modality == Modality.SEALED -> SpecialBuiltins.sealedSerializer
kind == ClassKind.INTERFACE -> SpecialBuiltins.polymorphicSerializer
isInternalSerializable && modality == Modality.ABSTRACT -> SpecialBuiltins.polymorphicSerializer
isInternalSerializable && modality == Modality.SEALED -> SpecialBuiltins.sealedSerializer
else -> null
}
return serializer?.let { context.getClassFromRuntimeOrNull(it, SerializationPackages.packageFqName, SerializationPackages.internalPackageFqName) }
}
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.defaultType
internal val IrClass.isInternallySerializableObject: Boolean
get() = kind == ClassKind.OBJECT && hasSerializableOrMetaAnnotationWithoutArgs()
internal val IrClass.serializerForClass: IrType?
get() = null // TODO("Serializer(forClass)")
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 // todo ????
internal val IrClass.isSealedSerializableInterface: Boolean
get() = kind == ClassKind.INTERFACE && modality == Modality.SEALED && hasSerializableOrMetaAnnotationWithoutArgs() // in previous version, it was just 'serializableOrMeta'
internal fun IrClass.isInternallySerializableEnum(): Boolean =
kind == ClassKind.ENUM_CLASS && hasSerializableOrMetaAnnotationWithoutArgs()
fun findStandardKotlinTypeSerializer(context: SerializationPluginContext, type: IrType): IrClassSymbol? {
val typeName = type.classFqName?.toString()
val name = when (typeName) {
"Z" -> if (type.isBoolean()) "BooleanSerializer" else null
"B" -> if (type.isByte()) "ByteSerializer" else null
"S" -> if (type.isShort()) "ShortSerializer" else null
"I" -> if (type.isInt()) "IntSerializer" else null
"J" -> if (type.isLong()) "LongSerializer" else null
"F" -> if (type.isFloat()) "FloatSerializer" else null
"D" -> if (type.isDouble()) "DoubleSerializer" else null
"C" -> if (type.isChar()) "CharSerializer" else null
null -> null
else -> findStandardKotlinTypeSerializer(typeName)
} ?: return null
return context.getClassFromRuntimeOrNull(name, SerializationPackages.internalPackageFqName, SerializationPackages.packageFqName)
}
fun IrType.isGeneratedSerializableObject(): Boolean {
return classOrNull?.run { owner.kind == ClassKind.OBJECT && owner.hasSerializableOrMetaAnnotationWithoutArgs() } == true
}
internal val IrClass.isSerializableObject: Boolean
get() = kind == ClassKind.OBJECT && hasSerializableOrMetaAnnotation()
// todo: optimize & unify
internal fun IrClass.hasSerializableOrMetaAnnotationWithoutArgs(): Boolean {
val annot = getAnnotation(SerializationAnnotations.serializableAnnotationFqName)
if (annot != null) {
for (i in 0 until annot.valueArgumentsCount) {
if (annot.getValueArgument(i) != null) return false
}
return true
}
val metaAnnotation = annotations
.flatMap { it.symbol.owner.constructedClass.annotations }
.find { it.isAnnotation(SerializationAnnotations.metaSerializableAnnotationFqName) }
return metaAnnotation != null
}
fun SerializationPluginContext.getClassFromRuntimeOrNull(className: String, vararg packages: FqName): IrClassSymbol? {
val listToSearch = if (packages.isEmpty()) SerializationPackages.allPublicPackages else packages.toList()
for (pkg in listToSearch) {
referenceClass(ClassId(pkg, Name.identifier(className)))?.let { return it }
}
return null
}
fun SerializationPluginContext.getClassFromRuntime(className: String, vararg packages: FqName): IrClassSymbol {
return getClassFromRuntimeOrNull(className, *packages) ?:
error("Class $className wasn't found in ${packages.toList().ifEmpty { SerializationPackages.allPublicPackages }}. " +
"Check that you have correct version of serialization runtime in classpath.")
}
fun SerializationPluginContext.getClassFromInternalSerializationPackage(className: String): IrClassSymbol =
getClassFromRuntimeOrNull(className, SerializationPackages.internalPackageFqName)
?: error("Class $className wasn't found in ${SerializationPackages.internalPackageFqName}. Check that you have correct version of serialization runtime in classpath.")
internal val IrType.overridenSerializer: IrSimpleType?
get() {
val desc = this.classOrNull ?: return null
desc.owner.serializableWith?.let { return it }
return null
}
internal val IrClass.serializableWith: IrSimpleType?
get() = annotations.serializableWith()
internal fun List<IrConstructorCall>.serializableWith(): IrSimpleType? {
// XXX::class
// val annotationArg =
// firstOrNull { it.type.classFqName == SerializationAnnotations.serializerAnnotationFqName }?.getValueArgument(0) ?: return null
// TODO("SerializableWith")
return null
}
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 descriptor.serialName() // TODO
}
fun AbstractSerialGenerator.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>()
// .filter { it.kind == ClassKind.ENUM_ENTRY }
.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() = false // TODO serialNameValue != null || any { it.annotationClass?.isSerialInfoAnnotation == true }
internal val List<IrConstructorCall>.serialNameValue: String?
get() = null // todo("List<IrConstructorCall>.serialNameValue") @SerialName
internal fun getSerializableClassDescriptorBySerializer(serializer: IrClass): IrClass? {
val serializerForClass = serializer.serializerForClass
if (serializerForClass != null) return serializerForClass.classOrNull?.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.origin == IrDeclarationOrigin.GeneratedByPlugin(SerializationPluginKey) }
}
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
}
@@ -0,0 +1,41 @@
/*
* 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.extensions.IrPluginContext
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
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.util.primaryConstructor
// TODO KT-53096
fun IrPluginContext.generateBodyForDefaultConstructor(declaration: IrConstructor): IrBody? {
val type = declaration.returnType as? IrSimpleType ?: return null
val delegatingAnyCall = IrDelegatingConstructorCallImpl(
-1,
-1,
irBuiltIns.anyType,
irBuiltIns.anyClass.owner.primaryConstructor?.symbol ?: return null,
typeArgumentsCount = 0,
valueArgumentsCount = 0
)
val initializerCall = IrInstanceInitializerCallImpl(
-1,
-1,
(declaration.parent as? IrClass)?.symbol ?: return null,
type
)
return irFactory.createBlockBody(-1, -1, listOf(delegatingAnyCall, initializerCall))
}
val Sequence<IrConstructor>.primary get() = find { it.isPrimary } ?: error("Expected to have a primary constructor")
@@ -5,9 +5,11 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.ir.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
import org.jetbrains.kotlin.ir.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.lower.irIfThen import org.jetbrains.kotlin.backend.common.lower.irIfThen
import org.jetbrains.kotlin.backend.common.sourceElement
import org.jetbrains.kotlin.backend.jvm.functionByName
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
@@ -23,14 +25,21 @@ import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.backend.jvm.ir.representativeUpperBound
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.name.CallableId
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.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.psi
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.* import org.jetbrains.kotlin.resolve.descriptorUtil.*
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.typeConstructor
import org.jetbrains.kotlin.types.model.dependsOnTypeConstructor
import org.jetbrains.kotlin.types.typeUtil.* import org.jetbrains.kotlin.types.typeUtil.*
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlinx.serialization.compiler.backend.common.* import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
@@ -47,16 +56,16 @@ interface IrBuilderExtension {
val compilerContext: SerializationPluginContext val compilerContext: SerializationPluginContext
private val throwMissedFieldExceptionFunc private val throwMissedFieldExceptionFunc
get() = compilerContext.referenceFunctions(SerialEntityNames.SINGLE_MASK_FIELD_MISSING_FUNC_FQ).singleOrNull() get() = compilerContext.referenceFunctions(CallableId(SerializationPackages.internalPackageFqName, SerialEntityNames.SINGLE_MASK_FIELD_MISSING_FUNC_NAME)).singleOrNull()
private val throwMissedFieldExceptionArrayFunc private val throwMissedFieldExceptionArrayFunc
get() = compilerContext.referenceFunctions(SerialEntityNames.ARRAY_MASK_FIELD_MISSING_FUNC_FQ).singleOrNull() get() = compilerContext.referenceFunctions(CallableId(SerializationPackages.internalPackageFqName, SerialEntityNames.ARRAY_MASK_FIELD_MISSING_FUNC_NAME)).singleOrNull()
private val enumSerializerFactoryFunc private val enumSerializerFactoryFunc
get() = compilerContext.referenceFunctions(SerialEntityNames.ENUM_SERIALIZER_FACTORY_FUNC_FQ).singleOrNull() get() = compilerContext.referenceFunctions(CallableId(SerializationPackages.internalPackageFqName, SerialEntityNames.ENUM_SERIALIZER_FACTORY_FUNC_NAME)).singleOrNull()
private val markedEnumSerializerFactoryFunc private val markedEnumSerializerFactoryFunc
get() = compilerContext.referenceFunctions(SerialEntityNames.MARKED_ENUM_SERIALIZER_FACTORY_FUNC_FQ).singleOrNull() get() = compilerContext.referenceFunctions(CallableId(SerializationPackages.internalPackageFqName, SerialEntityNames.MARKED_ENUM_SERIALIZER_FACTORY_FUNC_NAME)).singleOrNull()
private inline fun <reified T : IrDeclaration> IrClass.searchForDeclaration(descriptor: DeclarationDescriptor): T? { private inline fun <reified T : IrDeclaration> IrClass.searchForDeclaration(descriptor: DeclarationDescriptor): T? {
return declarations.singleOrNull { it.descriptor == descriptor } as? T return declarations.singleOrNull { it.descriptor == descriptor } as? T
@@ -66,6 +75,13 @@ interface IrBuilderExtension {
return throwMissedFieldExceptionFunc != null && throwMissedFieldExceptionArrayFunc != null return throwMissedFieldExceptionFunc != null && throwMissedFieldExceptionArrayFunc != null
} }
fun <F: IrFunction> addFunctionBody(function: F, bodyGen: IrBlockBodyBuilder.(F) -> Unit) {
function.body = DeclarationIrBuilder(compilerContext, function.symbol, function.startOffset, function.endOffset).irBlockBody(
function.startOffset,
function.endOffset
) { bodyGen(function) }
}
fun IrClass.contributeFunction(descriptor: FunctionDescriptor, ignoreWhenMissing: Boolean = false, bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit) { fun IrClass.contributeFunction(descriptor: FunctionDescriptor, ignoreWhenMissing: Boolean = false, bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit) {
val f: IrSimpleFunction = searchForDeclaration(descriptor) val f: IrSimpleFunction = searchForDeclaration(descriptor)
?: (if (ignoreWhenMissing) return else compilerContext.symbolTable.referenceSimpleFunction(descriptor).owner) ?: (if (ignoreWhenMissing) return else compilerContext.symbolTable.referenceSimpleFunction(descriptor).owner)
@@ -104,9 +120,9 @@ interface IrBuilderExtension {
DeclarationIrBuilder(compilerContext, function.symbol, startOffset, endOffset).irBlockBody(startOffset, endOffset, bodyGen) DeclarationIrBuilder(compilerContext, function.symbol, startOffset, endOffset).irBlockBody(startOffset, endOffset, bodyGen)
function.parent = this function.parent = this
val f0Type = module.findClassAcrossModuleDependencies(ClassId.topLevel(FUNCTION0_FQ))!!.defaultType val f0Type = compilerContext.irBuiltIns.functionN(0)
val f0ParamSymbol = compilerContext.symbolTable.referenceTypeParameter(f0Type.constructor.parameters[0]) val f0ParamSymbol = f0Type.typeParameters[0].symbol
val f0IrType = f0Type.toIrType().substitute(mapOf(f0ParamSymbol to type)) val f0IrType = f0Type.defaultType.substitute(mapOf(f0ParamSymbol to type))
return IrFunctionExpressionImpl( return IrFunctionExpressionImpl(
startOffset, startOffset,
@@ -123,13 +139,13 @@ interface IrBuilderExtension {
name: Name, name: Name,
initializerBuilder: IrBlockBodyBuilder.() -> Unit initializerBuilder: IrBlockBodyBuilder.() -> Unit
): IrProperty { ): IrProperty {
val lazySafeModeClassDescriptor = compilerContext.referenceClass(LAZY_MODE_FQ)!!.descriptor val lazySafeModeClassDescriptor = compilerContext.referenceClass(ClassId.topLevel(LAZY_MODE_FQ))!!.owner
val lazyFunctionSymbol = compilerContext.referenceFunctions(LAZY_FUNC_FQ).single { val lazyFunctionSymbol = compilerContext.referenceFunctions(CallableId(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, Name.identifier("lazy"))).single {
it.descriptor.valueParameters.size == 2 && it.descriptor.valueParameters[0].type == lazySafeModeClassDescriptor.defaultType it.descriptor.valueParameters.size == 2 && it.descriptor.valueParameters[0].type == lazySafeModeClassDescriptor.defaultType
} }
val publicationEntryDescriptor = lazySafeModeClassDescriptor.enumEntries().single { it.name == LAZY_PUBLICATION_MODE_NAME } val publicationEntryDescriptor = lazySafeModeClassDescriptor.enumEntries().single { it.name == LAZY_PUBLICATION_MODE_NAME }
val lazyIrClass = compilerContext.referenceClass(LAZY_FQ)!!.owner val lazyIrClass = compilerContext.referenceClass(ClassId.topLevel(LAZY_FQ))!!.owner
val lazyIrType = lazyIrClass.defaultType.substitute(mapOf(lazyIrClass.typeParameters[0].symbol to targetIrType)) val lazyIrType = lazyIrClass.defaultType.substitute(mapOf(lazyIrClass.typeParameters[0].symbol to targetIrType))
val propertyDescriptor = val propertyDescriptor =
@@ -146,8 +162,8 @@ interface IrBuilderExtension {
val enumElement = IrGetEnumValueImpl( val enumElement = IrGetEnumValueImpl(
startOffset, startOffset,
endOffset, endOffset,
publicationEntryDescriptor.classValueType!!.toIrType(), lazySafeModeClassDescriptor.defaultType,
compilerContext.symbolTable.referenceEnumEntry(publicationEntryDescriptor) publicationEntryDescriptor.symbol
) )
val lambdaExpression = containingClass.createLambdaExpression(targetIrType, initializerBuilder) val lambdaExpression = containingClass.createLambdaExpression(targetIrType, initializerBuilder)
@@ -191,7 +207,7 @@ interface IrBuilderExtension {
} }
fun IrBlockBodyBuilder.getLazyValueExpression(thisParam: IrValueParameter, property: IrProperty, type: IrType): IrExpression { fun IrBlockBodyBuilder.getLazyValueExpression(thisParam: IrValueParameter, property: IrProperty, type: IrType): IrExpression {
val lazyIrClass = compilerContext.referenceClass(LAZY_FQ)!!.owner val lazyIrClass = compilerContext.referenceClass(ClassId.topLevel(LAZY_FQ))!!.owner
val valueGetter = lazyIrClass.getPropertyGetter("value")!! val valueGetter = lazyIrClass.getPropertyGetter("value")!!
val propertyGetter = property.getter!! val propertyGetter = property.getter!!
@@ -245,16 +261,6 @@ interface IrBuilderExtension {
} }
} }
fun ClassDescriptor.referenceFunctionSymbol(
functionName: String,
predicate: (IrSimpleFunction) -> Boolean = { true }
): IrFunctionSymbol {
val irClass = compilerContext.referenceClass(fqNameSafe)?.owner ?: error("Couldn't load class $this")
val simpleFunctions = irClass.declarations.filterIsInstance<IrSimpleFunction>()
return simpleFunctions.filter { it.name.asString() == functionName }.single { predicate(it) }.symbol
}
fun IrBuilderWithScope.createPrimitiveArrayOfExpression( fun IrBuilderWithScope.createPrimitiveArrayOfExpression(
elementPrimitiveType: IrType, elementPrimitiveType: IrType,
arrayElements: List<IrExpression> arrayElements: List<IrExpression>
@@ -270,18 +276,10 @@ interface IrBuilderExtension {
fun IrBuilderWithScope.irBinOp(name: Name, lhs: IrExpression, rhs: IrExpression): IrExpression { fun IrBuilderWithScope.irBinOp(name: Name, lhs: IrExpression, rhs: IrExpression): IrExpression {
val classFqName = (lhs.type as IrSimpleType).classOrNull!!.owner.fqNameWhenAvailable!! val classFqName = (lhs.type as IrSimpleType).classOrNull!!.owner.fqNameWhenAvailable!!
val symbol = compilerContext.referenceFunctions(classFqName.child(name)).single() val symbol = compilerContext.referenceFunctions(CallableId(ClassId.topLevel(classFqName), name)).single()
return irInvoke(lhs, symbol, rhs) return irInvoke(lhs, symbol, rhs)
} }
fun IrBuilderWithScope.irGetObject(classDescriptor: ClassDescriptor) =
IrGetObjectValueImpl(
startOffset,
endOffset,
classDescriptor.defaultType.toIrType(),
compilerContext.symbolTable.referenceClass(classDescriptor)
)
fun IrBuilderWithScope.irGetObject(irObject: IrClass) = fun IrBuilderWithScope.irGetObject(irObject: IrClass) =
IrGetObjectValueImpl( IrGetObjectValueImpl(
startOffset, startOffset,
@@ -297,14 +295,6 @@ interface IrBuilderExtension {
} }
} }
fun IrBuilderWithScope.irEmptyVararg(forValueParameter: ValueParameterDescriptor) =
IrVarargImpl(
startOffset,
endOffset,
forValueParameter.type.toIrType(),
forValueParameter.varargElementType!!.toIrType()
)
class BranchBuilder( class BranchBuilder(
val irWhen: IrWhen, val irWhen: IrWhen,
context: IrGeneratorContext, context: IrGeneratorContext,
@@ -330,10 +320,12 @@ interface IrBuilderExtension {
result result
) )
@Deprecated("", level = DeprecationLevel.ERROR)
fun KotlinType.toIrType() = compilerContext.typeTranslator.translateType(this) fun KotlinType.toIrType() = compilerContext.typeTranslator.translateType(this)
// note: this method should be used only for properties from current module. Fields from other modules are private and inaccessible. // note: this method should be used only for properties from current module. Fields from other modules are private and inaccessible.
val SerializableProperty.irField: IrField? get() = compilerContext.symbolTable.referenceField(this.descriptor).let { if (it.isBound) it.owner else null } val IrSerializableProperty.irField: IrField?
get() = this.descriptor.backingField
fun IrClass.searchForProperty(descriptor: PropertyDescriptor): IrProperty { fun IrClass.searchForProperty(descriptor: PropertyDescriptor): IrProperty {
// this API is used to reference both current module descriptors and external ones (because serializable class can be in any of them), // this API is used to reference both current module descriptors and external ones (because serializable class can be in any of them),
@@ -341,13 +333,11 @@ interface IrBuilderExtension {
return searchForDeclaration(descriptor) ?: if (descriptor.module == compilerContext.moduleDescriptor) { return searchForDeclaration(descriptor) ?: if (descriptor.module == compilerContext.moduleDescriptor) {
compilerContext.symbolTable.referenceProperty(descriptor).owner compilerContext.symbolTable.referenceProperty(descriptor).owner
} else { } else {
@Suppress("DEPRECATION")
compilerContext.referenceProperties(descriptor.fqNameSafe).single().owner compilerContext.referenceProperties(descriptor.fqNameSafe).single().owner
} }
} }
fun SerializableProperty.getIrPropertyFrom(thisClass: IrClass): IrProperty {
return thisClass.searchForProperty(descriptor)
}
/* /*
@@ -356,37 +346,40 @@ interface IrBuilderExtension {
*/ */
fun IrBuilderWithScope.createPropertyByParamReplacer( fun IrBuilderWithScope.createPropertyByParamReplacer(
irClass: IrClass, irClass: IrClass,
serialProperties: List<SerializableProperty>, serialProperties: List<IrSerializableProperty>,
instance: IrValueParameter, instance: IrValueParameter,
bindingContext: BindingContext bindingContext: BindingContext?
): (ValueParameterDescriptor) -> IrExpression? { ): (ValueParameterDescriptor) -> IrExpression? {
fun SerializableProperty.irGet(): IrExpression { fun IrSerializableProperty.irGet(): IrExpression {
val ownerType = instance.symbol.owner.type val ownerType = instance.symbol.owner.type
return getProperty( return getProperty(
irGet( irGet(
type = ownerType, type = ownerType,
variable = instance.symbol variable = instance.symbol
), getIrPropertyFrom(irClass) ), descriptor
) )
} }
val serialPropertiesMap = serialProperties.associateBy { it.descriptor } val serialPropertiesMap = serialProperties.associateBy { it.descriptor }
val transientPropertiesMap = val transientPropertiesSet =
irClass.declarations.asSequence() irClass.declarations.asSequence()
.filterIsInstance<IrProperty>() .filterIsInstance<IrProperty>()
.filter { it.backingField != null }.filter { !serialPropertiesMap.containsKey(it.descriptor) } .filter { it.backingField != null }
.associateBy { it.symbol.descriptor } .filter { !serialPropertiesMap.containsKey(it) }
.toSet()
return { return { vpd ->
val propertyDescriptor = bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, it] val propertyDescriptor = irClass.properties.find { it.name == vpd.name }
if (propertyDescriptor != null) { if (propertyDescriptor != null) {
val value = serialPropertiesMap[propertyDescriptor] val value = serialPropertiesMap[propertyDescriptor]
value?.irGet() ?: transientPropertiesMap[propertyDescriptor]?.let { prop -> value?.irGet() ?: run {
getProperty( if (propertyDescriptor in transientPropertiesSet)
irGet(instance), getProperty(
prop irGet(instance),
) propertyDescriptor
)
else null
} }
} else { } else {
null null
@@ -428,7 +421,7 @@ interface IrBuilderExtension {
fun IrBlockBodyBuilder.generateGoldenMaskCheck( fun IrBlockBodyBuilder.generateGoldenMaskCheck(
seenVars: List<IrValueDeclaration>, seenVars: List<IrValueDeclaration>,
properties: SerializableProperties, properties: IrSerializableProperties,
serialDescriptor: IrExpression serialDescriptor: IrExpression
) { ) {
val fieldsMissedTest: IrExpression val fieldsMissedTest: IrExpression
@@ -539,6 +532,7 @@ interface IrBuilderExtension {
val field = with(propertyDescriptor) { val field = with(propertyDescriptor) {
// TODO: type parameters // TODO: type parameters
@Suppress("DEPRECATION_ERROR") // should be called only with old FE
originProperty.factory.createField( originProperty.factory.createField(
originProperty.startOffset, originProperty.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrFieldSymbolImpl(propertyDescriptor), name, type.toIrType(), originProperty.startOffset, originProperty.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrFieldSymbolImpl(propertyDescriptor), name, type.toIrType(),
visibility, !isVar, isEffectivelyExternal(), dispatchReceiverParameter == null visibility, !isVar, isEffectivelyExternal(), dispatchReceiverParameter == null
@@ -564,6 +558,7 @@ interface IrBuilderExtension {
false -> searchForDeclaration<IrProperty>(propertyDescriptor)?.setter false -> searchForDeclaration<IrProperty>(propertyDescriptor)?.setter
} ?: run { } ?: run {
with(descriptor) { with(descriptor) {
@Suppress("DEPRECATION_ERROR") // should never be called after FIR frontend
property.factory.createFunction( property.factory.createFunction(
fieldSymbol.owner.startOffset, fieldSymbol.owner.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrSimpleFunctionSymbolImpl(descriptor), fieldSymbol.owner.startOffset, fieldSymbol.owner.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrSimpleFunctionSymbolImpl(descriptor),
name, visibility, modality, returnType!!.toIrType(), name, visibility, modality, returnType!!.toIrType(),
@@ -572,6 +567,7 @@ interface IrBuilderExtension {
}.also { f -> }.also { f ->
generateOverriddenFunctionSymbols(f, compilerContext.symbolTable) generateOverriddenFunctionSymbols(f, compilerContext.symbolTable)
f.createParameterDeclarations(descriptor) f.createParameterDeclarations(descriptor)
@Suppress("DEPRECATION_ERROR") // should never be called after FIR frontend
f.returnType = descriptor.returnType!!.toIrType() f.returnType = descriptor.returnType!!.toIrType()
f.correspondingPropertySymbol = fieldSymbol.owner.correspondingPropertySymbol f.correspondingPropertySymbol = fieldSymbol.owner.correspondingPropertySymbol
} }
@@ -601,7 +597,7 @@ interface IrBuilderExtension {
val receiver = generateReceiverExpressionForFieldAccess(irAccessor.dispatchReceiverParameter!!.symbol, property) val receiver = generateReceiverExpressionForFieldAccess(irAccessor.dispatchReceiverParameter!!.symbol, property)
val propertyIrType = property.type.toIrType() val propertyIrType = irAccessor.returnType
irBody.statements.add( irBody.statements.add(
IrReturnImpl( IrReturnImpl(
startOffset, endOffset, compilerContext.irBuiltIns.nothingType, startOffset, endOffset, compilerContext.irBuiltIns.nothingType,
@@ -644,7 +640,7 @@ interface IrBuilderExtension {
return irBody return irBody
} }
fun generateReceiverExpressionForFieldAccess( fun generateReceiverExpressionForFieldAccess( // todo: remove this
ownerSymbol: IrValueSymbol, ownerSymbol: IrValueSymbol,
property: PropertyDescriptor property: PropertyDescriptor
): IrExpression { ): IrExpression {
@@ -666,6 +662,7 @@ interface IrBuilderExtension {
) { ) {
val function = this val function = this
fun irValueParameter(descriptor: ParameterDescriptor): IrValueParameter = with(descriptor) { fun irValueParameter(descriptor: ParameterDescriptor): IrValueParameter = with(descriptor) {
@Suppress("DEPRECATION_ERROR") // should never be called after FIR frontend
factory.createValueParameter( factory.createValueParameter(
function.startOffset, function.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrValueParameterSymbolImpl(this), function.startOffset, function.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrValueParameterSymbolImpl(this),
name, indexOrMinusOne, type.toIrType(), varargElementType?.toIrType(), isCrossinline, isNoinline, name, indexOrMinusOne, type.toIrType(), varargElementType?.toIrType(), isCrossinline, isNoinline,
@@ -700,7 +697,7 @@ interface IrBuilderExtension {
typeParameter.parent = this typeParameter.parent = this
} }
} }
@Suppress("DEPRECATION_ERROR") // should never be called after FIR frontend
newTypeParameters.forEach { typeParameter -> newTypeParameters.forEach { typeParameter ->
typeParameter.superTypes = typeParameter.descriptor.upperBounds.map { it.toIrType() } typeParameter.superTypes = typeParameter.descriptor.upperBounds.map { it.toIrType() }
} }
@@ -708,27 +705,13 @@ interface IrBuilderExtension {
typeParameters = newTypeParameters typeParameters = newTypeParameters
} }
fun createClassReference(classType: KotlinType, startOffset: Int, endOffset: Int): IrClassReference { fun createClassReference(classType: IrType, startOffset: Int, endOffset: Int): IrClassReference {
val clazz = classType.toClassDescriptor!!
val classSymbol = compilerContext.referenceClass(clazz.fqNameSafe) ?: error("Couldn't load class $clazz")
return IrClassReferenceImpl( return IrClassReferenceImpl(
startOffset, startOffset,
endOffset, endOffset,
compilerContext.irBuiltIns.kClassClass.starProjectedType, compilerContext.irBuiltIns.kClassClass.starProjectedType,
classSymbol, classType.classifierOrFail,
classType.approximateJvmErasure.toIrType() classType
)
}
fun createClassReference(irClass: IrClass, startOffset: Int, endOffset: Int): IrClassReference {
val classType = irClass.descriptor.toSimpleType(false)
val classSymbol = irClass.symbol
return IrClassReferenceImpl(
startOffset,
endOffset,
compilerContext.irBuiltIns.kClassClass.starProjectedType,
classSymbol,
classType.approximateJvmErasure.toIrType()
) )
} }
@@ -755,7 +738,9 @@ interface IrBuilderExtension {
else -> error("Unsupported classifier: $this") else -> error("Unsupported classifier: $this")
} }
fun IrBuilderWithScope.classReference(classType: KotlinType): IrClassReference = createClassReference(classType, startOffset, endOffset)
fun IrBuilderWithScope.classReference(classSymbol: IrType): IrClassReference =
createClassReference(classSymbol, startOffset, endOffset)
private fun extractDefaultValuesFromConstructor(irClass: IrClass?): Map<ParameterDescriptor, IrExpression?> { private fun extractDefaultValuesFromConstructor(irClass: IrClass?): Map<ParameterDescriptor, IrExpression?> {
if (irClass == null) return emptyMap() if (irClass == null) return emptyMap()
@@ -808,15 +793,6 @@ interface IrBuilderExtension {
} }
} }
fun findEnumValuesMethod(enumClass: ClassDescriptor): IrFunction {
assert(enumClass.kind == ClassKind.ENUM_CLASS)
return compilerContext.referenceClass(enumClass.fqNameSafe)?.let {
it.owner.functions.singleOrNull { f ->
f.name == Name.identifier("values") && f.valueParameters.isEmpty() && f.extensionReceiverParameter == null
} ?: throw AssertionError("Enum class does not have single .values() function")
} ?: error("Couldn't load class $enumClass")
}
private fun getEnumMembersNames(enumClass: ClassDescriptor): Sequence<String> { private fun getEnumMembersNames(enumClass: ClassDescriptor): Sequence<String> {
assert(enumClass.kind == ClassKind.ENUM_CLASS) assert(enumClass.kind == ClassKind.ENUM_CLASS)
return enumClass.unsubstitutedMemberScope.getContributedDescriptors().asSequence() return enumClass.unsubstitutedMemberScope.getContributedDescriptors().asSequence()
@@ -850,21 +826,20 @@ interface IrBuilderExtension {
fun IrBuilderWithScope.serializerTower( fun IrBuilderWithScope.serializerTower(
generator: SerializerIrGenerator, generator: SerializerIrGenerator,
dispatchReceiverParameter: IrValueParameter, dispatchReceiverParameter: IrValueParameter,
property: SerializableProperty property: IrSerializableProperty
): IrExpression? { ): IrExpression? {
val nullableSerClass = compilerContext.referenceProperties(SerialEntityNames.wrapIntoNullableExt).single() val nullableSerClass = compilerContext.referenceProperties(SerialEntityNames.wrapIntoNullableCallableId).single()
val serializer = val serializer =
property.serializableWith?.toClassDescriptor property.serializableWith?.classOrNull
?: if (!property.type.isTypeParameter()) generator.findTypeSerializerOrContext( ?: if (!property.type.isTypeParameter()) generator.findTypeSerializerOrContext(
property.module, compilerContext,
property.type, property.type
property.descriptor.findPsi()
) else null ) else null
return serializerInstance( return serializerInstance(
generator, generator,
dispatchReceiverParameter, dispatchReceiverParameter,
serializer, serializer,
property.module, compilerContext,
property.type, property.type,
genericIndex = property.genericIndex genericIndex = property.genericIndex
) )
@@ -872,12 +847,12 @@ interface IrBuilderExtension {
} }
private fun IrBuilderWithScope.wrapWithNullableSerializerIfNeeded( private fun IrBuilderWithScope.wrapWithNullableSerializerIfNeeded(
type: KotlinType, type: IrType,
expression: IrExpression, expression: IrExpression,
nullableProp: IrPropertySymbol nullableProp: IrPropertySymbol
): IrExpression = if (type.isMarkedNullable) { ): IrExpression = if (type.isMarkedNullable()) {
val resultType = type.makeNotNullable() val resultType = type.makeNotNull()
val typeArguments = listOf(resultType.toIrType()) val typeArguments = listOf(resultType)
val callee = nullableProp.owner.getter!! val callee = nullableProp.owner.getter!!
val returnType = callee.returnType.substitute(callee.typeParameters, typeArguments) val returnType = callee.returnType.substitute(callee.typeParameters, typeArguments)
@@ -892,10 +867,19 @@ interface IrBuilderExtension {
expression expression
} }
// private fun IrBuilderWithScope.wrapWithNullableSerializerIfNeeded(
// type: KotlinType,
// expression: IrExpression,
// nullableProp: IrPropertySymbol
// ): IrExpression = wrapWithNullableSerializerIfNeeded(type.toIrType(), expression, nullableProp)
fun wrapIrTypeIntoKSerializerIrType(module: ModuleDescriptor, type: IrType, variance: Variance = Variance.INVARIANT): IrType {
val serializerFqn = getSerializationPackageFqn(SerialEntityNames.KSERIALIZER_CLASS) fun wrapIrTypeIntoKSerializerIrType(
val kSerClass = compilerContext.referenceClass(serializerFqn) ?: error("Couldn't find class $serializerFqn") 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( return IrSimpleTypeImpl(
kSerClass, hasQuestionMark = false, arguments = listOf( kSerClass, hasQuestionMark = false, arguments = listOf(
makeTypeProjection(type, variance) makeTypeProjection(type, variance)
@@ -906,14 +890,14 @@ interface IrBuilderExtension {
fun IrBuilderWithScope.serializerInstance( fun IrBuilderWithScope.serializerInstance(
enclosingGenerator: SerializerIrGenerator, enclosingGenerator: SerializerIrGenerator,
dispatchReceiverParameter: IrValueParameter, dispatchReceiverParameter: IrValueParameter,
serializerClassOriginal: ClassDescriptor?, serializerClassOriginal: IrClassSymbol?,
module: ModuleDescriptor, pluginContext: SerializationPluginContext,
kType: KotlinType, kType: IrType,
genericIndex: Int? = null genericIndex: Int? = null
): IrExpression? = serializerInstance( ): IrExpression? = serializerInstance(
enclosingGenerator, enclosingGenerator,
serializerClassOriginal, serializerClassOriginal,
module, pluginContext,
kType, kType,
genericIndex genericIndex
) { it, _ -> ) { it, _ ->
@@ -925,23 +909,41 @@ interface IrBuilderExtension {
enclosingGenerator: AbstractSerialGenerator, enclosingGenerator: AbstractSerialGenerator,
serializerClassOriginal: ClassDescriptor?, serializerClassOriginal: ClassDescriptor?,
module: ModuleDescriptor, module: ModuleDescriptor,
kType: KotlinType, kType: IrType,
genericIndex: Int? = null, genericIndex: Int? = null,
genericGetter: ((Int, KotlinType) -> IrExpression)? = null genericGetter: ((Int) -> IrExpression)? = null
): IrExpression? { ): IrExpression? {
val nullableSerClass = compilerContext.referenceProperties(SerialEntityNames.wrapIntoNullableExt).single() return serializerInstance(
enclosingGenerator,
serializerClassOriginal?.let { compilerContext.symbolTable.referenceClass(it) },
compilerContext,
kType,
genericIndex,
if (genericGetter != null) { i, _ -> genericGetter(i) } else null
)
}
fun IrBuilderWithScope.serializerInstance(
enclosingGenerator: AbstractSerialGenerator,
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 (serializerClassOriginal == null) {
if (genericIndex == null) return null if (genericIndex == null) return null
return genericGetter?.invoke(genericIndex, kType) return genericGetter?.invoke(genericIndex, kType)
} }
if (serializerClassOriginal.kind == ClassKind.OBJECT) { if (serializerClassOriginal.owner.kind == ClassKind.OBJECT) {
return irGetObject(serializerClassOriginal) return irGetObject(serializerClassOriginal)
} }
fun instantiate(serializer: ClassDescriptor?, type: KotlinType): IrExpression? { fun instantiate(serializer: IrClassSymbol?, type: IrType): IrExpression? {
val expr = serializerInstance( val expr = serializerInstance(
enclosingGenerator, enclosingGenerator,
serializer, serializer,
module, pluginContext,
type, type,
type.genericIndex, type.genericIndex,
genericGetter genericGetter
@@ -951,11 +953,11 @@ interface IrBuilderExtension {
var serializerClass = serializerClassOriginal var serializerClass = serializerClassOriginal
var args: List<IrExpression> var args: List<IrExpression>
var typeArgs: List<IrType?> var typeArgs: List<IrType>
val thisIrType = kType.toIrType() val thisIrType = (kType as? IrSimpleType) ?: error("Don't know how to work with type ${kType::class}")
var needToCopyAnnotations = false var needToCopyAnnotations = false
when (serializerClassOriginal.classId) { when (serializerClassOriginal.owner.classId) {
polymorphicSerializerId -> { polymorphicSerializerId -> {
needToCopyAnnotations = true needToCopyAnnotations = true
args = listOf(classReference(kType)) args = listOf(classReference(kType))
@@ -965,29 +967,26 @@ interface IrBuilderExtension {
args = listOf(classReference(kType)) args = listOf(classReference(kType))
typeArgs = listOf(thisIrType) typeArgs = listOf(thisIrType)
val hasNewCtxSerCtor = val hasNewCtxSerCtor = compilerContext.referenceConstructors(contextSerializerId).any { it.owner.valueParameters.size == 3 }
serializerClassOriginal.classId == contextSerializerId && compilerContext.referenceConstructors(serializerClass.fqNameSafe)
.any { it.owner.valueParameters.size == 3 }
if (hasNewCtxSerCtor) { if (hasNewCtxSerCtor) {
// new signature of context serializer // new signature of context serializer
args = args + mutableListOf<IrExpression>().apply { args = args + mutableListOf<IrExpression>().apply {
val fallbackDefaultSerializer = findTypeSerializer(module, kType) val fallbackDefaultSerializer = findTypeSerializer(pluginContext, kType)
add(instantiate(fallbackDefaultSerializer, kType) ?: irNull()) add(instantiate(fallbackDefaultSerializer, kType) ?: irNull())
add( add(
createArrayOfExpression( createArrayOfExpression(
wrapIrTypeIntoKSerializerIrType( wrapIrTypeIntoKSerializerIrType(
module,
thisIrType, thisIrType,
variance = Variance.OUT_VARIANCE variance = Variance.OUT_VARIANCE
), ),
kType.arguments.map { thisIrType.arguments.map {
val argSer = enclosingGenerator.findTypeSerializerOrContext( val argSer = enclosingGenerator.findTypeSerializerOrContext(
module, compilerContext,
it.type, it.typeOrNull!!, //todo: handle star projections here
sourceElement = serializerClassOriginal.findPsi() sourceElement = serializerClassOriginal.owner.sourceElement()?.psi
) )
instantiate(argSer, it.type)!! instantiate(argSer, it.typeOrNull!!)!!
}) })
) )
} }
@@ -995,7 +994,7 @@ interface IrBuilderExtension {
} }
objectSerializerId -> { objectSerializerId -> {
needToCopyAnnotations = true needToCopyAnnotations = true
args = listOf(irString(kType.serialName()), irGetObject(kType.toClassDescriptor!!)) args = listOf(irString(kType.serialName()), irGetObject(kType.classOrNull!!))
typeArgs = listOf(thisIrType) typeArgs = listOf(thisIrType)
} }
sealedSerializerId -> { sealedSerializerId -> {
@@ -1004,8 +1003,8 @@ interface IrBuilderExtension {
add(irString(kType.serialName())) add(irString(kType.serialName()))
add(classReference(kType)) add(classReference(kType))
val (subclasses, subSerializers) = enclosingGenerator.allSealedSerializableSubclassesFor( val (subclasses, subSerializers) = enclosingGenerator.allSealedSerializableSubclassesFor(
kType.toClassDescriptor!!, kType.classOrNull!!.owner,
module pluginContext
) )
val projectedOutCurrentKClass = val projectedOutCurrentKClass =
compilerContext.irBuiltIns.kClassClass.typeWithArguments( compilerContext.irBuiltIns.kClassClass.typeWithArguments(
@@ -1019,23 +1018,21 @@ interface IrBuilderExtension {
) )
add( add(
createArrayOfExpression( createArrayOfExpression(
wrapIrTypeIntoKSerializerIrType(module, thisIrType, variance = Variance.OUT_VARIANCE), wrapIrTypeIntoKSerializerIrType(thisIrType, variance = Variance.OUT_VARIANCE),
subSerializers.mapIndexed { i, serializer -> subSerializers.mapIndexed { i, serializer ->
val type = subclasses[i] val type = subclasses[i]
val expr = serializerInstance( val expr = serializerInstance(
enclosingGenerator, enclosingGenerator,
serializer, serializer,
module, pluginContext,
type, type,
type.genericIndex type.genericIndex
) { _, genericType -> ) { _, genericType ->
serializerInstance( serializerInstance(
enclosingGenerator, enclosingGenerator,
module.getClassFromSerializationPackage( pluginContext.referenceClass(polymorphicSerializerId),
SpecialBuiltins.polymorphicSerializer pluginContext,
), (genericType.classifierOrNull as IrTypeParameterSymbol).owner.representativeUpperBound
module,
(genericType.constructor.declarationDescriptor as TypeParameterDescriptor).representativeUpperBound
)!! )!!
}!! }!!
wrapWithNullableSerializerIfNeeded(type, expr, nullableSerClass) wrapWithNullableSerializerIfNeeded(type, expr, nullableSerClass)
@@ -1046,8 +1043,8 @@ interface IrBuilderExtension {
typeArgs = listOf(thisIrType) typeArgs = listOf(thisIrType)
} }
enumSerializerId -> { enumSerializerId -> {
serializerClass = module.getClassFromInternalSerializationPackage(SpecialBuiltins.enumSerializer) serializerClass = pluginContext.referenceClass(enumSerializerId)
val enumDescriptor = kType.toClassDescriptor!! val enumDescriptor = kType.classOrNull!!
typeArgs = listOf(thisIrType) typeArgs = listOf(thisIrType)
// instantiate serializer only inside enum Companion // instantiate serializer only inside enum Companion
if (enclosingGenerator !is SerializableCompanionIrGenerator) { if (enclosingGenerator !is SerializableCompanionIrGenerator) {
@@ -1056,21 +1053,22 @@ interface IrBuilderExtension {
} }
val enumArgs = mutableListOf( val enumArgs = mutableListOf(
irString(enumDescriptor.serialName()), irString(thisIrType.serialName()),
irCall(findEnumValuesMethod(enumDescriptor)), irCall(enumDescriptor.owner.findEnumValuesMethod()),
) )
val enumSerializerFactoryFunc = enumSerializerFactoryFunc val enumSerializerFactoryFunc = enumSerializerFactoryFunc
val markedEnumSerializerFactoryFunc = markedEnumSerializerFactoryFunc val markedEnumSerializerFactoryFunc = markedEnumSerializerFactoryFunc
if (enumSerializerFactoryFunc != null && markedEnumSerializerFactoryFunc != null) { if (enumSerializerFactoryFunc != null && markedEnumSerializerFactoryFunc != null) {
// runtime contains enum serializer factory functions // runtime contains enum serializer factory functions
val factoryFunc: IrSimpleFunctionSymbol = if (enumDescriptor.isEnumWithSerialInfoAnnotation()) { val factoryFunc: IrSimpleFunctionSymbol = if (enumDescriptor.owner.isEnumWithSerialInfoAnnotation()) {
// need to store SerialInfo annotation in descriptor // need to store SerialInfo annotation in descriptor
val enumEntries = enumDescriptor.enumEntries() val enumEntries = enumDescriptor.owner.enumEntries()
val entriesNames = enumEntries.map { it.annotations.serialNameValue?.let { n -> irString(n) } ?: irNull() } val entriesNames = enumEntries.map { it.annotations.serialNameValue?.let { n -> irString(n) } ?: irNull() }
val entriesAnnotations = enumEntries.map { val entriesAnnotations = enumEntries.map {
val annotationConstructors = it.annotations.mapNotNull { a -> val annotationConstructors = it.annotations.map { a ->
compilerContext.typeTranslator.constantValueGenerator.generateAnnotationConstructorCall(a) // compilerContext.typeTranslator.constantValueGenerator.generateAnnotationConstructorCall(a)
a.deepCopyWithVariables()
} }
val annotationsConstructors = copyAnnotationsFrom(annotationConstructors) val annotationsConstructors = copyAnnotationsFrom(annotationConstructors)
if (annotationsConstructors.isEmpty()) { if (annotationsConstructors.isEmpty()) {
@@ -1100,36 +1098,37 @@ interface IrBuilderExtension {
else -> { else -> {
args = kType.arguments.map { args = kType.arguments.map {
val argSer = enclosingGenerator.findTypeSerializerOrContext( val argSer = enclosingGenerator.findTypeSerializerOrContext(
module, pluginContext,
it.type, it.typeOrNull!!, // todo: stars
sourceElement = serializerClassOriginal.findPsi() sourceElement = serializerClassOriginal.owner.source.getPsi()
) )
instantiate(argSer, it.type) ?: return null instantiate(argSer, it.typeOrNull!!) ?: return null
} }
typeArgs = kType.arguments.map { it.type.toIrType() } typeArgs = kType.arguments.map { it.typeOrNull!! }
} }
} }
if (serializerClassOriginal.classId == referenceArraySerializerId) { if (serializerClassOriginal.owner.classId == referenceArraySerializerId) {
args = listOf(wrapperClassReference(kType.arguments.single().type)) + args args = listOf(wrapperClassReference(kType.arguments.single().typeOrNull!!)) + args
typeArgs = listOf(typeArgs[0].makeNotNull()) + typeArgs 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 is interface, .classSerializer always yields PolymorphicSerializer, which may be unavailable for interfaces from other modules
if (!kType.isInterface() && serializerClassOriginal == kType.toClassDescriptor?.classSerializer && enclosingGenerator !is SerializableCompanionIrGenerator) { if (!kType.isInterface() && serializerClassOriginal == kType.classOrNull!!.owner.classSerializer(pluginContext) && enclosingGenerator !is SerializableCompanionIrGenerator) {
// This is default type serializer, we can shortcut through Companion.serializer() // This is default type serializer, we can shortcut through Companion.serializer()
// BUT not during generation of this method itself // BUT not during generation of this method itself
callSerializerFromCompanion(thisIrType, typeArgs, args)?.let { return it } callSerializerFromCompanion(thisIrType, typeArgs, args)?.let { return it }
} }
val serializable = getSerializableClassDescriptorBySerializer(serializerClass) val serializable = serializerClass?.owner?.let { getSerializableClassDescriptorBySerializer(it) }
val ctor = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) { requireNotNull(serializerClass)
val ctor = if (serializable?.typeParameters?.isNotEmpty() == true) {
requireNotNull( requireNotNull(
findSerializerConstructorForTypeArgumentsSerializers(serializerClass) findSerializerConstructorForTypeArgumentsSerializers(serializerClass.owner)
) { "Generated serializer does not have constructor with required number of arguments" } ) { "Generated serializer does not have constructor with required number of arguments" }
} else { } else {
val constructors = compilerContext.referenceConstructors(serializerClass.fqNameSafe) val constructors = serializerClass.constructors
// search for new signature of polymorphic/sealed/contextual serializer // search for new signature of polymorphic/sealed/contextual serializer
if (!needToCopyAnnotations) { if (!needToCopyAnnotations) {
constructors.single { it.owner.isPrimary } constructors.single { it.owner.isPrimary }
@@ -1163,7 +1162,8 @@ interface IrBuilderExtension {
fun collectSerialInfoAnnotations(irClass: IrClass): List<IrConstructorCall> { fun collectSerialInfoAnnotations(irClass: IrClass): List<IrConstructorCall> {
if (!(irClass.isInterface || irClass.descriptor.hasSerializableOrMetaAnnotation)) return emptyList() if (!(irClass.isInterface || irClass.descriptor.hasSerializableOrMetaAnnotation)) return emptyList()
val annotationByFq: MutableMap<FqName, IrConstructorCall> = irClass.annotations.associateBy { it.symbol.owner.parentAsClass.descriptor.fqNameSafe }.toMutableMap() val annotationByFq: MutableMap<FqName, IrConstructorCall> =
irClass.annotations.associateBy { it.symbol.owner.parentAsClass.descriptor.fqNameSafe }.toMutableMap()
for (clazz in irClass.getAllSuperclasses()) { for (clazz in irClass.getAllSuperclasses()) {
val annotations = clazz.annotations val annotations = clazz.annotations
.mapNotNull { .mapNotNull {
@@ -1195,7 +1195,7 @@ interface IrBuilderExtension {
val adjustedArgs: List<IrExpression> = 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 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)) { if ((typeArgs.size != args.size) && (baseClass.descriptor.isSealed() || baseClass.descriptor.modality == Modality.ABSTRACT)) {
val serializer = findStandardKotlinTypeSerializer(baseClass.module, context.irBuiltIns.unitType.toKotlinType())!! 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 // 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) } List(baseClass.typeParameters.size) { irGetObject(serializer) }
} else { } else {
@@ -1219,12 +1219,13 @@ interface IrBuilderExtension {
return ((lastArgType as? IrSimpleType)?.arguments?.firstOrNull()?.typeOrNull?.classFqName?.toString() == "kotlin.Annotation") return ((lastArgType as? IrSimpleType)?.arguments?.firstOrNull()?.typeOrNull?.classFqName?.toString() == "kotlin.Annotation")
} }
private fun IrBuilderWithScope.wrapperClassReference(classType: KotlinType): IrClassReference { private fun IrBuilderWithScope.wrapperClassReference(classType: IrType): IrClassReference {
if (compilerContext.platform.isJvm()) { if (compilerContext.platform.isJvm()) {
// "Byte::class" -> "java.lang.Byte::class" // "Byte::class" -> "java.lang.Byte::class"
val wrapperFqName = KotlinBuiltIns.getPrimitiveType(classType)?.let(JvmPrimitiveType::get)?.wrapperFqName // TODO: get rid of descriptor
val wrapperFqName = KotlinBuiltIns.getPrimitiveType(classType.classOrNull!!.descriptor)?.let(JvmPrimitiveType::get)?.wrapperFqName
if (wrapperFqName != null) { if (wrapperFqName != null) {
val wrapperClass = compilerContext.moduleDescriptor.findClassAcrossModuleDependencies(ClassId.topLevel(wrapperFqName)) val wrapperClass = compilerContext.referenceClass(ClassId.topLevel(wrapperFqName))
?: error("Primitive wrapper class for $classType not found: $wrapperFqName") ?: error("Primitive wrapper class for $classType not found: $wrapperFqName")
return classReference(wrapperClass.defaultType) return classReference(wrapperClass.defaultType)
} }
@@ -1232,28 +1233,19 @@ interface IrBuilderExtension {
return classReference(classType) return classReference(classType)
} }
private fun findSerializerConstructorForTypeArgumentsSerializers(serializer: ClassDescriptor): IrConstructorSymbol? { fun findSerializerConstructorForTypeArgumentsSerializers(serializer: IrClass): IrConstructorSymbol? {
val serializableImplementationTypeArguments = extractKSerializerArgumentFromImplementation(serializer)?.arguments
?: throw AssertionError("Serializer does not implement KSerializer??")
val typeParamsCount = serializableImplementationTypeArguments.size val typeParamsCount = ((serializer.superTypes.find { isKSerializer(it) } as IrSimpleType).arguments.first().typeOrNull!! as IrSimpleType).arguments.size
if (typeParamsCount == 0) return null //don't need it if (typeParamsCount == 0) return null //don't need it
val constructors = compilerContext.referenceConstructors(serializer.fqNameSafe)
fun isKSerializer(type: IrType): Boolean { return serializer.constructors.singleOrNull {
val simpleType = type as? IrSimpleType ?: return false it.valueParameters.let { vps -> vps.size == typeParamsCount && vps.all { vp -> isKSerializer(vp.type) } }
val classifier = simpleType.classifier as? IrClassSymbol ?: return false }?.symbol
return classifier.owner.fqNameWhenAvailable == SerialEntityNames.KSERIALIZER_NAME_FQ
}
return constructors.singleOrNull {
it.owner.valueParameters.let { vps -> vps.size == typeParamsCount && vps.all { vp -> isKSerializer(vp.type) } }
}
} }
private fun IrConstructor.isSerializationCtor(): Boolean { private fun IrConstructor.isSerializationCtor(): Boolean {
val serialMarker = val serialMarker =
compilerContext.referenceClass(SerializationPackages.internalPackageFqName.child(SerialEntityNames.SERIAL_CTOR_MARKER_NAME)) compilerContext.referenceClass(ClassId.topLevel(SerializationPackages.internalPackageFqName.child(SerialEntityNames.SERIAL_CTOR_MARKER_NAME)))
return valueParameters.lastOrNull()?.run { return valueParameters.lastOrNull()?.run {
name == SerialEntityNames.dummyParamName && type.classifierOrNull == serialMarker name == SerialEntityNames.dummyParamName && type.classifierOrNull == serialMarker
@@ -1279,23 +1271,23 @@ interface IrBuilderExtension {
fun IrBlockBodyBuilder.serializeAllProperties( fun IrBlockBodyBuilder.serializeAllProperties(
generator: AbstractSerialGenerator, generator: AbstractSerialGenerator,
serializableIrClass: IrClass, serializableIrClass: IrClass,
serializableProperties: List<SerializableProperty>, serializableProperties: List<IrSerializableProperty>,
objectToSerialize: IrValueDeclaration, objectToSerialize: IrValueDeclaration,
localOutput: IrValueDeclaration, localOutput: IrValueDeclaration,
localSerialDesc: IrValueDeclaration, localSerialDesc: IrValueDeclaration,
kOutputClass: ClassDescriptor, kOutputClass: IrClassSymbol,
ignoreIndexTo: Int, ignoreIndexTo: Int,
initializerAdapter: (IrExpressionBody) -> IrExpression, initializerAdapter: (IrExpressionBody) -> IrExpression,
genericGetter: ((Int, KotlinType) -> IrExpression)? genericGetter: ((Int, IrType) -> IrExpression)?
) { ) {
fun SerializableProperty.irGet(): IrExpression { fun IrSerializableProperty.irGet(): IrExpression {
val ownerType = objectToSerialize.symbol.owner.type val ownerType = objectToSerialize.symbol.owner.type
return getProperty( return getProperty(
irGet( irGet(
type = ownerType, type = ownerType,
variable = objectToSerialize.symbol variable = objectToSerialize.symbol
), getIrPropertyFrom(serializableIrClass) ), descriptor
) )
} }
@@ -1307,7 +1299,7 @@ interface IrBuilderExtension {
irGet(localOutput), irGet(localOutput),
property, { innerSerial, sti -> property, { innerSerial, sti ->
val f = val f =
kOutputClass.referenceFunctionSymbol("${CallingConventions.encode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}") kOutputClass.functionByName("${CallingConventions.encode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}")
f to listOf( f to listOf(
irGet(localSerialDesc), irGet(localSerialDesc),
irInt(index), irInt(index),
@@ -1316,7 +1308,7 @@ interface IrBuilderExtension {
) )
}, { }, {
val f = val f =
kOutputClass.referenceFunctionSymbol("${CallingConventions.encode}${it.elementMethodPrefix}${CallingConventions.elementPostfix}") kOutputClass.functionByName("${CallingConventions.encode}${it.elementMethodPrefix}${CallingConventions.elementPostfix}")
val args: MutableList<IrExpression> = mutableListOf(irGet(localSerialDesc), irInt(index)) val args: MutableList<IrExpression> = mutableListOf(irGet(localSerialDesc), irInt(index))
if (it.elementMethodPrefix != "Unit") args.add(property.irGet()) if (it.elementMethodPrefix != "Unit") args.add(property.irGet())
f to args f to args
@@ -1325,7 +1317,7 @@ interface IrBuilderExtension {
) )
// check for call to .shouldEncodeElementDefault // check for call to .shouldEncodeElementDefault
val encodeDefaults = property.getIrPropertyFrom(serializableIrClass).getEncodeDefaultAnnotationValue() val encodeDefaults = property.descriptor.getEncodeDefaultAnnotationValue()
val field = property.irField // Nullable when property from another module; can't compare it with default value on JS or Native val field = property.irField // Nullable when property from another module; can't compare it with default value on JS or Native
if (!property.optional || encodeDefaults == true || field == null) { if (!property.optional || encodeDefaults == true || field == null) {
// emit call right away // emit call right away
@@ -1340,7 +1332,7 @@ interface IrBuilderExtension {
// emit check: // emit check:
// if (if (output.shouldEncodeElementDefault(this.descriptor, i)) true else {obj.prop != DEFAULT_VALUE} ) { // 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 // output.encodeIntElement(this.descriptor, i, obj.prop)// block {obj.prop != DEFAULT_VALUE} may contain several statements
val shouldEncodeFunc = kOutputClass.referenceFunctionSymbol(CallingConventions.shouldEncodeDefault) val shouldEncodeFunc = kOutputClass.functionByName(CallingConventions.shouldEncodeDefault)
val partA = irInvoke(irGet(localOutput), shouldEncodeFunc, irGet(localSerialDesc), irInt(index)) val partA = irInvoke(irGet(localOutput), shouldEncodeFunc, irGet(localSerialDesc), irInt(index))
// Ir infrastructure does not have dedicated symbol for ||, so // Ir infrastructure does not have dedicated symbol for ||, so
// `a || b == if (a) true else b`, see org.jetbrains.kotlin.ir.builders.PrimitivesKt.oror // `a || b == if (a) true else b`, see org.jetbrains.kotlin.ir.builders.PrimitivesKt.oror
@@ -1359,7 +1351,8 @@ interface IrBuilderExtension {
fun IrProperty.getEncodeDefaultAnnotationValue(): Boolean? { fun IrProperty.getEncodeDefaultAnnotationValue(): Boolean? {
val call = annotations.findAnnotation(SerializationAnnotations.encodeDefaultFqName) ?: return null val call = annotations.findAnnotation(SerializationAnnotations.encodeDefaultFqName) ?: return null
val arg = call.getValueArgument(0) ?: return true // ALWAYS by default 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() val argValue = (arg as? IrGetEnumValue
?: error("Argument of enum constructor expected to implement IrGetEnumValue, got $arg")).symbol.owner.name.toString()
return when (argValue) { return when (argValue) {
"ALWAYS" -> true "ALWAYS" -> true
"NEVER" -> false "NEVER" -> false
@@ -1371,23 +1364,23 @@ interface IrBuilderExtension {
fun IrBlockBodyBuilder.formEncodeDecodePropertyCall( fun IrBlockBodyBuilder.formEncodeDecodePropertyCall(
enclosingGenerator: AbstractSerialGenerator, enclosingGenerator: AbstractSerialGenerator,
encoder: IrExpression, encoder: IrExpression,
property: SerializableProperty, property: IrSerializableProperty,
whenHaveSerializer: (serializer: IrExpression, sti: SerialTypeInfo) -> FunctionWithArgs, whenHaveSerializer: (serializer: IrExpression, sti: IrSerialTypeInfo) -> FunctionWithArgs,
whenDoNot: (sti: SerialTypeInfo) -> FunctionWithArgs, whenDoNot: (sti: IrSerialTypeInfo) -> FunctionWithArgs,
genericGetter: ((Int, KotlinType) -> IrExpression)? = null, genericGetter: ((Int, IrType) -> IrExpression)? = null,
returnTypeHint: IrType? = null returnTypeHint: IrType? = null
): IrExpression { ): IrExpression {
val sti = enclosingGenerator.getSerialTypeInfo(property) val sti = enclosingGenerator.getIrSerialTypeInfo(property, compilerContext)
val innerSerial = serializerInstance( val innerSerial = serializerInstance(
enclosingGenerator, enclosingGenerator,
sti.serializer, sti.serializer,
property.module, compilerContext,
property.type, property.type,
property.genericIndex, property.genericIndex,
genericGetter genericGetter
) )
val (functionToCall, args: List<IrExpression>) = if (innerSerial != null) whenHaveSerializer(innerSerial, sti) else whenDoNot(sti) val (functionToCall, args: List<IrExpression>) = if (innerSerial != null) whenHaveSerializer(innerSerial, sti) else whenDoNot(sti)
val typeArgs = if (functionToCall.descriptor.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf() val typeArgs = if (functionToCall.descriptor.typeParameters.isNotEmpty()) listOf(property.type) else listOf()
return irInvoke(encoder, functionToCall, typeArguments = typeArgs, valueArguments = args, returnTypeHint = returnTypeHint) return irInvoke(encoder, functionToCall, typeArguments = typeArgs, valueArguments = args, returnTypeHint = returnTypeHint)
} }
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.createImplicitParameterDeclarationWithWrappedDescriptor import org.jetbrains.kotlin.ir.util.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.kotlinFqName import org.jetbrains.kotlin.ir.util.kotlinFqName
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.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -44,7 +45,7 @@ class SerialInfoImplJvmIrGenerator(
override val compilerContext: SerializationPluginContext override val compilerContext: SerializationPluginContext
get() = context get() = context
private val jvmNameClass get() = context.referenceClass(DescriptorUtils.JVM_NAME)!!.owner private val jvmNameClass get() = context.referenceClass(ClassId.topLevel(DescriptorUtils.JVM_NAME))!!.owner
private val javaLangClass = createClass(createPackage("java.lang"), "Class", ClassKind.CLASS) private val javaLangClass = createClass(createPackage("java.lang"), "Class", ClassKind.CLASS)
private val javaLangType = javaLangClass.starProjectedType private val javaLangType = javaLangClass.starProjectedType
@@ -54,6 +55,7 @@ class SerialInfoImplJvmIrGenerator(
fun getImplClass(serialInfoAnnotationClass: IrClass): IrClass = fun getImplClass(serialInfoAnnotationClass: IrClass): IrClass =
annotationToImpl.getOrPut(serialInfoAnnotationClass) { annotationToImpl.getOrPut(serialInfoAnnotationClass) {
@Suppress("DEPRECATION") // TODO
val implClassSymbol = context.referenceClass(serialInfoAnnotationClass.kotlinFqName.child(SerialEntityNames.IMPL_NAME)) val implClassSymbol = context.referenceClass(serialInfoAnnotationClass.kotlinFqName.child(SerialEntityNames.IMPL_NAME))
implClassSymbol!!.owner.apply(this::generate) implClassSymbol!!.owner.apply(this::generate)
} }
@@ -7,58 +7,67 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irInt
import org.jetbrains.kotlin.ir.builders.irReturn
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
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.ir.types.impl.IrErrorClassImpl.endOffset
import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.types.impl.IrErrorClassImpl.startOffset
import org.jetbrains.kotlin.ir.util.substitute import org.jetbrains.kotlin.ir.types.toKotlinType
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.BindingContext
import org.jetbrains.kotlin.resolve.calls.components.isVararg import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer 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.*
class SerializableCompanionIrGenerator( class SerializableCompanionIrGenerator(
val irClass: IrClass, val irClass: IrClass,
val serializableIrClass: IrClass,
override val compilerContext: SerializationPluginContext, override val compilerContext: SerializationPluginContext,
bindingContext: BindingContext ) : SerializableCompanionCodegen(irClass.descriptor, null), IrBuilderExtension {
) : SerializableCompanionCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
override fun getSerializerGetterDescriptor(): FunctionDescriptor { // todo: remove .toKotlinType()
return irClass.findDeclaration<IrSimpleFunction> {
(it.valueParameters.size == serializableDescriptor.declaredTypeParameters.size
&& it.valueParameters.all { p -> isKSerializer(p.type.toKotlinType()) }) && isKSerializer(it.returnType.toKotlinType())
}?.descriptor ?: throw IllegalStateException(
"Can't find synthesized 'Companion.serializer()' function to generate, " +
"probably clash with user-defined function has occurred"
)
}
companion object { companion object {
fun generate( fun generate(
irClass: IrClass, irClass: IrClass,
context: SerializationPluginContext, context: SerializationPluginContext,
bindingContext: BindingContext
) { ) {
val companionDescriptor = irClass.descriptor val companionDescriptor = irClass.descriptor
val serializableClass = getSerializableClassDescriptorByCompanion(companionDescriptor) ?: return val serializableClass = getSerializableClassDescriptorByCompanion(companionDescriptor) ?: return
if (serializableClass.shouldHaveGeneratedMethodsInCompanion) { if (serializableClass.shouldHaveGeneratedMethodsInCompanion) {
SerializableCompanionIrGenerator(irClass, context, bindingContext).generate() SerializableCompanionIrGenerator(irClass, getSerializableClassByCompanion(irClass)!!, context).generate()
val declaration = irClass.constructors.primary // todo: move to appropriate place
if (declaration.body == null) declaration.body = context.generateBodyForDefaultConstructor(declaration)
irClass.patchDeclarationParents(irClass.parent) irClass.patchDeclarationParents(irClass.parent)
} }
} }
} }
private fun IrBuilderWithScope.patchSerializableClassWithMarkerAnnotation(serializer: ClassDescriptor) { private fun IrBuilderWithScope.patchSerializableClassWithMarkerAnnotation(serializer: IrClass) {
if (serializer.kind != ClassKind.OBJECT) { if (serializer.kind != ClassKind.OBJECT) {
return return
} }
val annotationMarkerClass = serializer.module.findClassAcrossModuleDependencies( val annotationMarkerClass = compilerContext.referenceClass(
ClassId( ClassId(
SerializationPackages.packageFqName, SerializationPackages.packageFqName,
Name.identifier(SerialEntityNames.ANNOTATION_MARKER_CLASS) Name.identifier(SerialEntityNames.ANNOTATION_MARKER_CLASS)
@@ -67,29 +76,18 @@ class SerializableCompanionIrGenerator(
val irSerializableClass = if (irClass.isCompanion) irClass.parentAsClass else irClass val irSerializableClass = if (irClass.isCompanion) irClass.parentAsClass else irClass
val serializableWithAlreadyPresent = irSerializableClass.annotations.any { val serializableWithAlreadyPresent = irSerializableClass.annotations.any {
it.symbol.descriptor.constructedClass.fqNameSafe == annotationMarkerClass.fqNameSafe it.symbol.descriptor.constructedClass.fqNameSafe == annotationMarkerClass.owner.fqNameWhenAvailable
} }
if (serializableWithAlreadyPresent) return if (serializableWithAlreadyPresent) return
val annotationCtor = compilerContext.referenceConstructors(annotationMarkerClass.fqNameSafe).single { it.owner.isPrimary } val annotationCtor = annotationMarkerClass.constructors.single { it.owner.isPrimary }
val annotationType = annotationMarkerClass.defaultType.toIrType() val annotationType = annotationMarkerClass.defaultType
val serializerIrClass = if (serializableDescriptor.isInternalSerializable) {
// internally generated serializer always declared inside serializable class
irSerializableClass.declarations
.filterIsInstanceAnd<IrClass> { it.name == serializer.name }
.singleOrNull() ?: throw Exception("No class with name ${serializer.fqNameSafe}")
} else {
// FIXME referenceClass not supports local classes so it should be replaced in future
compilerContext.referenceClass(serializer.fqNameSafe)!!.owner
}
val annotationCtorCall = IrConstructorCallImpl.fromSymbolDescriptor(startOffset, endOffset, annotationType, annotationCtor).apply { val annotationCtorCall = IrConstructorCallImpl.fromSymbolDescriptor(startOffset, endOffset, annotationType, annotationCtor).apply {
putValueArgument( putValueArgument(
0, 0,
createClassReference( createClassReference(
serializerIrClass, serializer.defaultType,
startOffset, startOffset,
endOffset endOffset
) )
@@ -100,24 +98,23 @@ class SerializableCompanionIrGenerator(
} }
override fun generateLazySerializerGetter(methodDescriptor: FunctionDescriptor) { override fun generateLazySerializerGetter(methodDescriptor: FunctionDescriptor) {
val serializerDescriptor = requireNotNull( val serializer = requireNotNull(
findTypeSerializer( findTypeSerializer(
serializableDescriptor.module, compilerContext,
serializableDescriptor.toSimpleType() serializableIrClass.defaultType
) )
) )
val kSerializerIrClass = compilerContext.referenceClass(SerialEntityNames.KSERIALIZER_NAME_FQ)!!.owner val kSerializerIrClass = serializer.owner
val targetIrType = val targetIrType =
kSerializerIrClass.defaultType.substitute(mapOf(kSerializerIrClass.typeParameters[0].symbol to compilerContext.irBuiltIns.anyType)) kSerializerIrClass.defaultType.substitute(mapOf(kSerializerIrClass.typeParameters[0].symbol to compilerContext.irBuiltIns.anyType))
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, this@SerializableCompanionIrGenerator,
serializerDescriptor, serializableDescriptor.module, serializer, compilerContext, kSerializerIrClass.defaultType
serializableDescriptor.defaultType
) )
patchSerializableClassWithMarkerAnnotation(serializerDescriptor) patchSerializableClassWithMarkerAnnotation(kSerializerIrClass)
+irReturn(requireNotNull(expr)) +irReturn(requireNotNull(expr))
} }
@@ -131,17 +128,17 @@ class SerializableCompanionIrGenerator(
irClass.contributeFunction(methodDescriptor) { getter -> irClass.contributeFunction(methodDescriptor) { getter ->
val serializer = requireNotNull( val serializer = requireNotNull(
findTypeSerializer( findTypeSerializer(
serializableDescriptor.module, compilerContext,
serializableDescriptor.toSimpleType() serializableIrClass.defaultType
) )
) )
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, this@SerializableCompanionIrGenerator,
serializer, serializableDescriptor.module, serializer, compilerContext,
serializableDescriptor.defaultType serializableIrClass.defaultType
) { it, _ -> args[it] } ) { it, _ -> args[it] }
patchSerializableClassWithMarkerAnnotation(serializer) patchSerializableClassWithMarkerAnnotation(serializer.owner)
+irReturn(requireNotNull(expr)) +irReturn(requireNotNull(expr))
} }
generateSerializerFactoryIfNeeded(methodDescriptor) generateSerializerFactoryIfNeeded(methodDescriptor)
@@ -149,16 +146,13 @@ class SerializableCompanionIrGenerator(
private fun generateSerializerFactoryIfNeeded(getterDescriptor: FunctionDescriptor) { private fun generateSerializerFactoryIfNeeded(getterDescriptor: FunctionDescriptor) {
if (!companionDescriptor.needSerializerFactory()) return if (!companionDescriptor.needSerializerFactory()) return
val serialFactoryDescriptor = companionDescriptor.unsubstitutedMemberScope.getContributedFunctions( val serialFactoryDescriptor = irClass.findDeclaration<IrSimpleFunction> {
SerialEntityNames.SERIALIZER_PROVIDER_NAME,
NoLookupLocation.FROM_BACKEND
).firstOrNull {
it.valueParameters.size == 1 it.valueParameters.size == 1
&& it.valueParameters.first().isVararg && it.valueParameters.first().isVararg
&& it.kind == CallableMemberDescriptor.Kind.SYNTHESIZED // && it.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
&& it.returnType != null && isKSerializer(it.returnType) && isKSerializer(it.returnType)
} ?: return } ?: return
irClass.contributeFunction(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 = serializableDescriptor.declaredTypeParameters.size
@@ -177,8 +171,9 @@ class SerializableCompanionIrGenerator(
returnTypeHint = kSerializerStarType returnTypeHint = kSerializerStarType
) )
+irReturn(call) +irReturn(call)
patchSerializableClassWithMarkerAnnotation(companionDescriptor) patchSerializableClassWithMarkerAnnotation(irClass)
} }
} }
} }
@@ -5,71 +5,70 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.ir.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.lower.irThrow import org.jetbrains.kotlin.backend.common.lower.irThrow
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.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* 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.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.IrTypeProjection
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.isString
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.descriptorUtil.secondaryConstructors
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd
import org.jetbrains.kotlin.utils.getOrPutNullable import org.jetbrains.kotlin.utils.getOrPutNullable
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
import org.jetbrains.kotlinx.serialization.compiler.backend.common.isStaticSerializable import org.jetbrains.kotlinx.serialization.compiler.backend.common.isStaticSerializable
import org.jetbrains.kotlinx.serialization.compiler.backend.common.serialName
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.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.CACHED_DESCRIPTOR_FIELD_NAME import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.CACHED_DESCRIPTOR_FIELD_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.LOAD
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.MISSING_FIELD_EXC import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.MISSING_FIELD_EXC
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SAVE
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESC_FIELD import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESC_FIELD
class SerializableIrGenerator( class SerializableIrGenerator(
val irClass: IrClass, val irClass: IrClass,
override val compilerContext: SerializationPluginContext, override val compilerContext: SerializationPluginContext
bindingContext: BindingContext ) : AbstractSerialGenerator(null, irClass.descriptor), IrBuilderExtension {
) : SerializableCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
private val serialDescClass: ClassDescriptor = serializableDescriptor.module protected val properties = bindingContext.serializablePropertiesForIrBackend(irClass)
.getClassFromSerializationDescriptorsPackage(SerialEntityNames.SERIAL_DESCRIPTOR_CLASS)
private val serialDescImplClass: ClassDescriptor = serializableDescriptor private val serialDescriptorClass = compilerContext.referenceClass(
.getClassFromInternalSerializationPackage(SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL) ClassId(
SerializationPackages.descriptorsPackageFqName,
Name.identifier(SerialEntityNames.SERIAL_DESCRIPTOR_CLASS)
)
)!!.owner
private val addElementFun = serialDescImplClass.referenceFunctionSymbol(CallingConventions.addElement) private val serialDescriptorImplClass = compilerContext.referenceClass(
ClassId(
SerializationPackages.internalPackageFqName,
Name.identifier(SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL)
)
)!!.owner
private fun IrClass.hasSerializableOrMetaAnnotationWithoutArgs(): Boolean { private val addElementFun =
val annot = getAnnotation(SerializationAnnotations.serializableAnnotationFqName) serialDescriptorImplClass.findDeclaration<IrFunction> { it.name.toString() == CallingConventions.addElement }!!.symbol
if (annot != null) {
for (i in 0 until annot.valueArgumentsCount) {
if (annot.getValueArgument(i) != null) return false
}
return true
}
val metaAnnotation = annotations
.flatMap { it.symbol.owner.constructedClass.annotations }
.find { it.isAnnotation(SerializationAnnotations.metaSerializableAnnotationFqName) }
return metaAnnotation != null
}
private val IrClass.isInternalSerializable: Boolean get() = kind == ClassKind.CLASS && hasSerializableOrMetaAnnotationWithoutArgs() private val IrClass.isInternalSerializable: Boolean get() = kind == ClassKind.CLASS && hasSerializableOrMetaAnnotationWithoutArgs()
override fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor) = fun generateInternalConstructor(constructorDescriptor: IrConstructor) =
irClass.contributeConstructor(constructorDescriptor) { ctor -> addFunctionBody(constructorDescriptor) { ctor ->
val thiz = irClass.thisReceiver!! val thiz = irClass.thisReceiver!!
val serializableProperties = properties.serializableProperties val serializableProperties = properties.serializableProperties
@@ -81,14 +80,14 @@ class SerializableIrGenerator(
val initializerAdapter: (IrExpressionBody) -> IrExpression = createInitializerAdapter(irClass, propertyByParamReplacer) val initializerAdapter: (IrExpressionBody) -> IrExpression = createInitializerAdapter(irClass, propertyByParamReplacer)
var current: PropertyDescriptor? = null var current: IrProperty? = null
val statementsAfterSerializableProperty: MutableMap<PropertyDescriptor?, MutableList<IrStatement>> = mutableMapOf() val statementsAfterSerializableProperty: MutableMap<IrProperty?, MutableList<IrStatement>> = mutableMapOf()
irClass.declarations.asSequence().forEach { irClass.declarations.asSequence().forEach {
when { when {
// only properties with backing field // only properties with backing field
it is IrProperty && it.backingField != null -> { it is IrProperty && it.backingField != null -> {
if (it.descriptor in serialDescs) { if (it in serialDescs) {
current = it.descriptor current = it
} else if (it.backingField?.initializer != null) { } else if (it.backingField?.initializer != null) {
// skip transient lateinit or deferred properties (with null initializer) // skip transient lateinit or deferred properties (with null initializer)
val expression = initializerAdapter(it.backingField!!.initializer!!) val expression = initializerAdapter(it.backingField!!.initializer!!)
@@ -121,9 +120,9 @@ class SerializableIrGenerator(
if (useFieldMissingOptimization() && if (useFieldMissingOptimization() &&
// for abstract classes fields MUST BE checked in child classes // for abstract classes fields MUST BE checked in child classes
!serializableDescriptor.isAbstractOrSealedSerializableClass() !irClass.isAbstractOrSealedSerializableClass
) { ) {
val getDescriptorExpr = if (serializableDescriptor.isStaticSerializable) { val getDescriptorExpr = if (irClass.isStaticSerializable) {
getStaticSerialDescriptorExpr() getStaticSerialDescriptorExpr()
} else { } else {
// synthetic constructor is created only for internally serializable classes - so companion definitely exists // synthetic constructor is created only for internally serializable classes - so companion definitely exists
@@ -133,7 +132,7 @@ class SerializableIrGenerator(
generateGoldenMaskCheck(seenVars, properties, getDescriptorExpr) generateGoldenMaskCheck(seenVars, properties, getDescriptorExpr)
} }
when { when {
superClass.symbol == compilerContext.irBuiltIns.anyClass -> generateAnySuperConstructorCall(toBuilder = this@contributeConstructor) superClass.symbol == compilerContext.irBuiltIns.anyClass -> generateAnySuperConstructorCall(toBuilder = this@addFunctionBody)
superClass.isInternalSerializable -> { superClass.isInternalSerializable -> {
startPropOffset = generateSuperSerializableCall(superClass, ctor.valueParameters, seenVarsOffset) startPropOffset = generateSuperSerializableCall(superClass, ctor.valueParameters, seenVarsOffset)
} }
@@ -146,7 +145,7 @@ 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.getIrPropertyFrom(irClass).backingField!! val backingFieldToAssign = prop.descriptor.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) {
@@ -196,17 +195,17 @@ class SerializableIrGenerator(
} }
private fun IrBlockBodyBuilder.getStaticSerialDescriptorExpr(): IrExpression { private fun IrBlockBodyBuilder.getStaticSerialDescriptorExpr(): IrExpression {
val serializer = serializableDescriptor.classSerializer!! val serializerIrClass = irClass.classSerializer(compilerContext)!!.owner
// internally generated serializer always declared inside serializable class // internally generated serializer always declared inside serializable class
val serializerIrClass = irClass.declarations // val serializerIrClass = irClass.declarations
.filterIsInstanceAnd<IrClass> { it.name == serializer.name } // .filterIsInstanceAnd<IrClass> { it.name == serializer.name }
.singleOrNull() ?: throw Exception("No class with name ${serializer.fqNameSafe}") // .singleOrNull() ?: throw Exception("No class with name ${serializer.fqNameSafe}")
val serialDescriptorGetter = val serialDescriptorGetter =
serializerIrClass.getPropertyGetter(SERIAL_DESC_FIELD)!! serializerIrClass.getPropertyGetter(SERIAL_DESC_FIELD)!!
return irGet( return irGet(
serializerIrClass.defaultType, serializerIrClass.defaultType,
irGetObject(serializer), irGetObject(serializerIrClass),
serialDescriptorGetter.owner.symbol serialDescriptorGetter.owner.symbol
) )
} }
@@ -216,7 +215,7 @@ class SerializableIrGenerator(
} }
private fun IrBlockBodyBuilder.createCachedDescriptorProperty(companionObject: IrClass): IrProperty { private fun IrBlockBodyBuilder.createCachedDescriptorProperty(companionObject: IrClass): IrProperty {
val serialDescIrType = serialDescClass.defaultType.toIrType() val serialDescIrType = serialDescriptorClass.defaultType
return createCompanionValProperty(companionObject, serialDescIrType, CACHED_DESCRIPTOR_FIELD_NAME) { return createCompanionValProperty(companionObject, serialDescIrType, CACHED_DESCRIPTOR_FIELD_NAME) {
val serialDescVar = irTemporary( val serialDescVar = irTemporary(
@@ -231,16 +230,16 @@ class SerializableIrGenerator(
} }
private fun IrBlockBodyBuilder.getInstantiateDescriptorExpr(): IrExpression { private fun IrBlockBodyBuilder.getInstantiateDescriptorExpr(): IrExpression {
val classConstructors = compilerContext.referenceConstructors(serialDescImplClass.fqNameSafe) val classConstructors = compilerContext.referenceConstructors(serialDescriptorImplClass.kotlinFqName) //todo: remove reference
val serialClassDescImplCtor = classConstructors.single { it.owner.isPrimary } val serialClassDescImplCtor = classConstructors.single { it.owner.isPrimary }
return irInvoke( return irInvoke(
null, serialClassDescImplCtor, null, serialClassDescImplCtor,
irString(serializableDescriptor.serialName()), irNull(), irInt(properties.serializableProperties.size) irString(irClass.serialName()), irNull(), irInt(properties.serializableProperties.size)
) )
} }
private fun IrBlockBodyBuilder.getAddElementToDescriptorExpr( private fun IrBlockBodyBuilder.getAddElementToDescriptorExpr(
property: SerializableProperty, property: IrSerializableProperty,
serialDescVar: IrVariable serialDescVar: IrVariable
): IrExpression { ): IrExpression {
return irInvoke( return irInvoke(
@@ -254,7 +253,7 @@ class SerializableIrGenerator(
private fun IrBlockBodyBuilder.generateSuperNonSerializableCall(superClass: IrClass) { private fun IrBlockBodyBuilder.generateSuperNonSerializableCall(superClass: IrClass) {
val ctorRef = superClass.declarations.filterIsInstance<IrConstructor>().singleOrNull { it.valueParameters.isEmpty() } val ctorRef = superClass.declarations.filterIsInstance<IrConstructor>().singleOrNull { it.valueParameters.isEmpty() }
?: error("Non-serializable parent of serializable $serializableDescriptor must have no arg constructor") ?: error("Non-serializable parent of serializable $irClass must have no arg constructor")
val call = IrDelegatingConstructorCallImpl.fromSymbolDescriptor( val call = IrDelegatingConstructorCallImpl.fromSymbolDescriptor(
@@ -301,13 +300,13 @@ class SerializableIrGenerator(
return superProperties.size return superProperties.size
} }
override fun generateWriteSelfMethod(methodDescriptor: FunctionDescriptor) { fun generateWriteSelfMethod(methodDescriptor: IrSimpleFunction) {
irClass.contributeFunction(methodDescriptor, ignoreWhenMissing = true) { writeSelfFunction -> addFunctionBody(methodDescriptor) { writeSelfFunction ->
val objectToSerialize = writeSelfFunction.valueParameters[0] val objectToSerialize = writeSelfFunction.valueParameters[0]
val localOutput = writeSelfFunction.valueParameters[1] val localOutput = writeSelfFunction.valueParameters[1]
val localSerialDesc = writeSelfFunction.valueParameters[2] val localSerialDesc = writeSelfFunction.valueParameters[2]
val serializableProperties = properties.serializableProperties val serializableProperties = properties.serializableProperties
val kOutputClass = serializableDescriptor.getClassFromSerializationPackage(SerialEntityNames.STRUCTURE_ENCODER_CLASS) val kOutputClass = compilerContext.getClassFromRuntime(SerialEntityNames.STRUCTURE_ENCODER_CLASS)
val propertyByParamReplacer: (ValueParameterDescriptor) -> IrExpression? = val propertyByParamReplacer: (ValueParameterDescriptor) -> IrExpression? =
createPropertyByParamReplacer(irClass, serializableProperties, objectToSerialize, bindingContext) createPropertyByParamReplacer(irClass, serializableProperties, objectToSerialize, bindingContext)
@@ -339,21 +338,21 @@ class SerializableIrGenerator(
val args = mutableListOf<IrExpression>(irGet(objectToSerialize), irGet(localOutput), irGet(localSerialDesc)) val args = mutableListOf<IrExpression>(irGet(objectToSerialize), irGet(localOutput), irGet(localSerialDesc))
val typeArgsForParent = val typeArgsForParent =
serializableDescriptor.typeConstructor.supertypes.single { it.toClassDescriptor?.isInternalSerializable == true }.arguments (irClass.superTypes.single { it.classOrNull?.owner?.isInternalSerializable == true } as? IrSimpleType)?.arguments.orEmpty()
val parentWriteSelfSerializers = typeArgsForParent.map { arg -> val parentWriteSelfSerializers = typeArgsForParent.map { arg ->
val genericIdx = serializableDescriptor.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(serializableDescriptor.module, arg.type) val serial = findTypeSerializerOrContext(compilerContext, arg.typeOrNull!!)
serializerInstance( serializerInstance(
this@SerializableIrGenerator, this@SerializableIrGenerator,
serial, serial,
serializableDescriptor.module, compilerContext,
arg.type, arg.typeOrNull!!,
genericIdx genericIdx
) { it, _ -> ) { it, _ ->
irGet(writeSelfFunction.valueParameters[3 + it]) irGet(writeSelfFunction.valueParameters[3 + it])
}!! }!!
} }
+irInvoke(null, superWriteSelfF.symbol, typeArgsForParent.map { it.type.toIrType() }, args + parentWriteSelfSerializers) +irInvoke(null, superWriteSelfF.symbol, typeArgsForParent.map { it.typeOrNull!! }, args + parentWriteSelfSerializers)
} }
} }
@@ -367,16 +366,45 @@ class SerializableIrGenerator(
} }
} }
fun generate() {
generateSyntheticInternalConstructor()
generateSyntheticMethods()
}
private inline fun IrClass.shouldHaveSpecificSyntheticMethods(functionPresenceChecker: () -> IrSimpleFunction?) =
!isValue && (isAbstractOrSealedSerializableClass || functionPresenceChecker() != null)
private fun generateSyntheticInternalConstructor() { // TODO: this doesn't work with OLD FE
val serializerDescriptor = irClass.classSerializer(compilerContext)?.owner ?: return
if (irClass.shouldHaveSpecificSyntheticMethods { serializerDescriptor.findPluginGeneratedMethod(LOAD) }) {
val constrDesc = irClass.constructors.find(IrConstructor::isSerializationCtor) ?: return
generateInternalConstructor(constrDesc)
}
}
private fun generateSyntheticMethods() {
val serializerDescriptor = irClass.classSerializer(compilerContext)?.owner ?: return
if (irClass.shouldHaveSpecificSyntheticMethods { serializerDescriptor.findPluginGeneratedMethod(SAVE) }) {
val func =
irClass.functions.singleOrNull { function ->
function.name == SerialEntityNames.WRITE_SELF_NAME &&
function.modality == Modality.FINAL &&
function.returnType.isUnit()
} ?: return
generateWriteSelfMethod(func)
}
}
companion object { companion object {
fun generate( fun generate(
irClass: IrClass, irClass: IrClass,
context: SerializationPluginContext, context: SerializationPluginContext,
bindingContext: BindingContext
) { ) {
val serializableClass = irClass.descriptor val serializableClass = irClass.descriptor
if (serializableClass.isInternalSerializable) { if (serializableClass.isInternalSerializable) {
SerializableIrGenerator(irClass, context, bindingContext).generate() SerializableIrGenerator(irClass, context).generate()
irClass.patchDeclarationParents(irClass.parent) irClass.patchDeclarationParents(irClass.parent)
} else if (serializableClass.serializableAnnotationIsUseless) { } else if (serializableClass.serializableAnnotationIsUseless) {
throw CompilationException( throw CompilationException(
@@ -5,6 +5,7 @@
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.builtins.StandardNames import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
@@ -12,31 +13,37 @@ 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
import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.deepCopyWithVariables
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.defaultType 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.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe 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.*
class SerializerForEnumsGenerator( class SerializerForEnumsGenerator(
irClass: IrClass, irClass: IrClass,
compilerContext: SerializationPluginContext, compilerContext: SerializationPluginContext,
bindingContext: BindingContext,
serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator, serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
) : SerializerIrGenerator(irClass, compilerContext, bindingContext, null, serialInfoJvmGenerator) { ) : SerializerIrGenerator(irClass, compilerContext, null, serialInfoJvmGenerator) {
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc -> override fun generateSave(function: IrSimpleFunction) = addFunctionBody(function) { saveFunc ->
fun irThis(): IrExpression = fun irThis(): IrExpression =
IrGetValueImpl(startOffset, endOffset, saveFunc.dispatchReceiverParameter!!.symbol) IrGetValueImpl(startOffset, endOffset, saveFunc.dispatchReceiverParameter!!.symbol)
val encoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.ENCODER_CLASS) val encoderClass = compilerContext.getClassFromRuntime(SerialEntityNames.ENCODER_CLASS)
val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol val descriptorGetterSymbol = irAnySerialDescProperty?.getter!!.symbol
val encodeEnum = encoderClass.referenceFunctionSymbol(CallingConventions.encodeEnum) val encodeEnum = encoderClass.functionByName(CallingConventions.encodeEnum)
val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol) val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol)
val serializableIrClass = requireNotNull(serializableIrClass) { "Enums do not support external serialization" } val serializableIrClass = requireNotNull(serializableIrClass) { "Enums do not support external serialization" }
@@ -46,13 +53,13 @@ class SerializerForEnumsGenerator(
+call +call
} }
override fun generateLoad(function: FunctionDescriptor) = irClass.contributeFunction(function) { loadFunc -> override fun generateLoad(function: IrSimpleFunction) = addFunctionBody(function) { loadFunc ->
fun irThis(): IrExpression = fun irThis(): IrExpression =
IrGetValueImpl(startOffset, endOffset, loadFunc.dispatchReceiverParameter!!.symbol) IrGetValueImpl(startOffset, endOffset, loadFunc.dispatchReceiverParameter!!.symbol)
val decoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.DECODER_CLASS) val decoderClass = compilerContext.getClassFromRuntime(SerialEntityNames.DECODER_CLASS)
val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol val descriptorGetterSymbol = irAnySerialDescProperty?.getter!!.symbol
val decode = decoderClass.referenceFunctionSymbol(CallingConventions.decodeEnum) val decode = decoderClass.functionByName(CallingConventions.decodeEnum)
val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol) val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol)
val serializableIrClass = requireNotNull(serializableIrClass) { "Enums do not support external serialization" } val serializableIrClass = requireNotNull(serializableIrClass) { "Enums do not support external serialization" }
@@ -73,27 +80,23 @@ class SerializerForEnumsGenerator(
+irReturn(getValueByOrdinal) +irReturn(getValueByOrdinal)
} }
override val serialDescImplClass: ClassDescriptor = serializerDescriptor override val serialDescImplClass: IrClassSymbol = compilerContext.getClassFromInternalSerializationPackage(SerialEntityNames.SERIAL_DESCRIPTOR_FOR_ENUM)
.getClassFromInternalSerializationPackage(SerialEntityNames.SERIAL_DESCRIPTOR_FOR_ENUM)
override fun IrBlockBodyBuilder.instantiateNewDescriptor( override fun IrBlockBodyBuilder.instantiateNewDescriptor(serialDescImplClass: IrClassSymbol, correctThis: IrExpression): IrExpression {
serialDescImplClass: ClassDescriptor, val ctor = serialDescImplClass.constructors.single { it.owner.isPrimary }
correctThis: IrExpression
): IrExpression {
val ctor = compilerContext.referenceConstructors(serialDescImplClass.fqNameSafe).single { it.owner.isPrimary }
return irInvoke( return irInvoke(
null, ctor, null, ctor,
irString(serialName), irString(serialName),
irInt(serializableDescriptor.enumEntries().size) irInt(serializableIrClass.enumEntries().size)
) )
} }
override fun IrBlockBodyBuilder.addElementsContentToDescriptor( override fun IrBlockBodyBuilder.addElementsContentToDescriptor(
serialDescImplClass: ClassDescriptor, serialDescImplClass: IrClassSymbol,
localDescriptor: IrVariable, localDescriptor: IrVariable,
addFunction: IrFunctionSymbol addFunction: IrFunctionSymbol
) { ) {
val enumEntries = serializableDescriptor.enumEntries() val enumEntries = serializableIrClass.enumEntries()
for (entry in enumEntries) { for (entry in enumEntries) {
// regular .serialName() produces fqName here, which is kinda inconvenient for enum entry // regular .serialName() produces fqName here, which is kinda inconvenient for enum entry
val serialName = entry.annotations.serialNameValue ?: entry.name.toString() val serialName = entry.annotations.serialNameValue ?: entry.name.toString()
@@ -107,9 +110,9 @@ class SerializerForEnumsGenerator(
+call +call
// serialDesc.pushAnnotation(...) // serialDesc.pushAnnotation(...)
copySerialInfoAnnotationsToDescriptor( copySerialInfoAnnotationsToDescriptor(
entry.annotations.mapNotNull(compilerContext.typeTranslator.constantValueGenerator::generateAnnotationConstructorCall), entry.annotations.map {it.deepCopyWithVariables()},
localDescriptor, localDescriptor,
serialDescImplClass.referenceFunctionSymbol(CallingConventions.addAnnotation) serialDescImplClass.functionByName(CallingConventions.addAnnotation)
) )
} }
} }
@@ -5,34 +5,38 @@
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.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor 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.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType 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.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe 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.*
class SerializerForInlineClassGenerator( class SerializerForInlineClassGenerator(
irClass: IrClass, irClass: IrClass,
compilerContext: SerializationPluginContext, compilerContext: SerializationPluginContext,
bindingContext: BindingContext,
serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator, serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
) : SerializerIrGenerator(irClass, compilerContext, bindingContext, null, serialInfoJvmGenerator) { ) : SerializerIrGenerator(irClass, compilerContext, null, serialInfoJvmGenerator) {
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc -> override fun generateSave(function: IrSimpleFunction) = addFunctionBody(function) { saveFunc ->
fun irThis(): IrExpression = fun irThis(): IrExpression =
IrGetValueImpl(startOffset, endOffset, saveFunc.dispatchReceiverParameter!!.symbol) IrGetValueImpl(startOffset, endOffset, saveFunc.dispatchReceiverParameter!!.symbol)
val encoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.ENCODER_CLASS) val encoderClass = compilerContext.getClassFromRuntime(SerialEntityNames.ENCODER_CLASS)
val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol val descriptorGetterSymbol = irAnySerialDescProperty?.getter!!.symbol
val encodeInline = encoderClass.referenceFunctionSymbol(CallingConventions.encodeInline) val encodeInline = encoderClass.functionByName(CallingConventions.encodeInline)
val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol) val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol)
// val inlineEncoder = encoder.encodeInline() // val inlineEncoder = encoder.encodeInline()
@@ -45,14 +49,14 @@ class SerializerForInlineClassGenerator(
// 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 ->
val f = val f =
encoderClass.referenceFunctionSymbol("${CallingConventions.encode}${sti.elementMethodPrefix}SerializableValue") encoderClass.functionByName("${CallingConventions.encode}${sti.elementMethodPrefix}SerializableValue")
f to listOf( f to listOf(
innerSerial, innerSerial,
value value
) )
}, { }, {
val f = val f =
encoderClass.referenceFunctionSymbol("${CallingConventions.encode}${it.elementMethodPrefix}") encoderClass.functionByName("${CallingConventions.encode}${it.elementMethodPrefix}")
val args = if (it.elementMethodPrefix != "Unit") listOf(value) else emptyList() val args = if (it.elementMethodPrefix != "Unit") listOf(value) else emptyList()
f to args f to args
}) })
@@ -61,37 +65,33 @@ class SerializerForInlineClassGenerator(
+actualEncodeCall +actualEncodeCall
} }
override fun generateLoad(function: FunctionDescriptor) = irClass.contributeFunction(function) { loadFunc -> override fun generateLoad(function: IrSimpleFunction) = addFunctionBody(function) { loadFunc ->
fun irThis(): IrExpression = fun irThis(): IrExpression =
IrGetValueImpl(startOffset, endOffset, loadFunc.dispatchReceiverParameter!!.symbol) IrGetValueImpl(startOffset, endOffset, loadFunc.dispatchReceiverParameter!!.symbol)
val decoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.DECODER_CLASS) val decoderClass = compilerContext.getClassFromRuntime(SerialEntityNames.DECODER_CLASS)
val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol val descriptorGetterSymbol = irAnySerialDescProperty?.getter!!.symbol
val decodeInline = decoderClass.referenceFunctionSymbol(CallingConventions.decodeInline) val decodeInline = decoderClass.functionByName(CallingConventions.decodeInline)
val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol) val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol)
// val inlineDecoder = decoder.decodeInline() // val inlineDecoder = decoder.decodeInline()
val inlineDecoder: IrExpression = irInvoke(irGet(loadFunc.valueParameters[0]), decodeInline, serialDescGetter) val inlineDecoder: IrExpression = irInvoke(irGet(loadFunc.valueParameters[0]), decodeInline, serialDescGetter)
val property = serializableProperties.first() val property = serializableProperties.first()
val inlinedType = property.type.toIrType() val inlinedType = property.type
val actualCall = formEncodeDecodePropertyCall(inlineDecoder, loadFunc.dispatchReceiverParameter!!, property, { innerSerial, sti -> val actualCall = formEncodeDecodePropertyCall(inlineDecoder, loadFunc.dispatchReceiverParameter!!, property, { innerSerial, sti ->
decoderClass.referenceFunctionSymbol( "${CallingConventions.decode}${sti.elementMethodPrefix}SerializableValue") to listOf(innerSerial) decoderClass.functionByName( "${CallingConventions.decode}${sti.elementMethodPrefix}SerializableValue") to listOf(innerSerial)
}, { }, {
decoderClass.referenceFunctionSymbol("${CallingConventions.decode}${it.elementMethodPrefix}") to listOf() decoderClass.functionByName("${CallingConventions.decode}${it.elementMethodPrefix}") to listOf()
}, returnTypeHint = inlinedType) }, returnTypeHint = inlinedType)
val value = coerceToBox(actualCall, loadFunc.returnType) val value = coerceToBox(actualCall, loadFunc.returnType)
+irReturn(value) +irReturn(value)
} }
override val serialDescImplClass: ClassDescriptor = serializerDescriptor override val serialDescImplClass: IrClassSymbol = compilerContext.getClassFromInternalSerializationPackage(SerialEntityNames.SERIAL_DESCRIPTOR_FOR_INLINE)
.getClassFromInternalSerializationPackage(SerialEntityNames.SERIAL_DESCRIPTOR_FOR_INLINE)
override fun IrBlockBodyBuilder.instantiateNewDescriptor( override fun IrBlockBodyBuilder.instantiateNewDescriptor(serialDescImplClass: IrClassSymbol, correctThis: IrExpression): IrExpression {
serialDescImplClass: ClassDescriptor, val ctor = serialDescImplClass.constructors.single { it.owner.isPrimary }
correctThis: IrExpression
): IrExpression {
val ctor = compilerContext.referenceConstructors(serialDescImplClass.fqNameSafe).single { it.owner.isPrimary }
return irInvoke( return irInvoke(
null, ctor, null, ctor,
irString(serialName), irString(serialName),
@@ -109,6 +109,6 @@ class SerializerForInlineClassGenerator(
listOf(expression) listOf(expression)
) )
private fun IrBlockBodyBuilder.getFromBox(expression: IrExpression, serializableProperty: SerializableProperty): IrExpression = private fun IrBlockBodyBuilder.getFromBox(expression: IrExpression, serializableProperty: IrSerializableProperty): IrExpression =
getProperty(expression, serializableProperty.getIrPropertyFrom(serializableIrClass)) getProperty(expression, serializableProperty.descriptor)
} }
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.ir.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irIfThen import org.jetbrains.kotlin.backend.common.lower.irIfThen
import org.jetbrains.kotlin.backend.common.lower.irThrow import org.jetbrains.kotlin.backend.common.lower.irThrow
import org.jetbrains.kotlin.backend.jvm.functionByName
import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.codegen.CompilationException import org.jetbrains.kotlin.codegen.CompilationException
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
@@ -16,29 +17,29 @@ import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
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.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
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.SerialTypeInfo import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
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.fir.SerializationPluginKey
import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.DECODER_CLASS import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.DECODER_CLASS
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENCODER_CLASS import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENCODER_CLASS
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SAVE
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.STRUCTURE_DECODER_CLASS import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.STRUCTURE_DECODER_CLASS
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.STRUCTURE_ENCODER_CLASS import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.STRUCTURE_ENCODER_CLASS
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.UNKNOWN_FIELD_EXC import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.UNKNOWN_FIELD_EXC
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorBySerializer
import org.jetbrains.kotlinx.serialization.compiler.resolve.isEnumWithLegacyGeneratedSerializer
object SERIALIZABLE_PLUGIN_ORIGIN : IrDeclarationOriginImpl("SERIALIZER", true) object SERIALIZABLE_PLUGIN_ORIGIN : IrDeclarationOriginImpl("SERIALIZER", true)
@@ -47,31 +48,63 @@ internal typealias FunctionWithArgs = Pair<IrFunctionSymbol, List<IrExpression>>
open class SerializerIrGenerator( open class SerializerIrGenerator(
val irClass: IrClass, val irClass: IrClass,
final override val compilerContext: SerializationPluginContext, final override val compilerContext: SerializationPluginContext,
bindingContext: BindingContext,
metadataPlugin: SerializationDescriptorSerializerPlugin?, metadataPlugin: SerializationDescriptorSerializerPlugin?,
private val serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator, private val serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
) : SerializerCodegen(irClass.descriptor, bindingContext, metadataPlugin), IrBuilderExtension { ) : AbstractSerialGenerator(null, irClass.descriptor), IrBuilderExtension {
protected val serializableIrClass = compilerContext.symbolTable.referenceClass(serializableDescriptor).owner protected val serializableIrClass = getSerializableClassDescriptorBySerializer(irClass)!!
protected val irAnySerialDescProperty = anySerialDescProperty?.let { compilerContext.symbolTable.referenceProperty(it) }
protected val serialName: String = serializableIrClass.serialName()
protected val properties = bindingContext.serializablePropertiesForIrBackend(serializableIrClass, metadataPlugin)
protected val serializableProperties = properties.serializableProperties
protected val isGeneratedSerializer = irClass.descriptor.typeConstructor.supertypes.any(::isGeneratedKSerializer) // TODO TODO
protected val generatedSerialDescPropertyDescriptor = getProperty(
SerialEntityNames.SERIAL_DESC_FIELD,
{ true }
)?.takeIf { it.origin == IrDeclarationOrigin.GeneratedByPlugin(SerializationPluginKey) }
protected val anySerialDescProperty = getProperty(
SerialEntityNames.SERIAL_DESC_FIELD,
) { true } // TODO REMOVE TRUE
protected val irAnySerialDescProperty = anySerialDescProperty
fun getProperty(
name: String,
isReturnTypeOk: (IrProperty) -> Boolean
): IrProperty? {
return irClass.properties.singleOrNull { it.name.asString() == name && isReturnTypeOk(it) }
}
var localSerializersFieldsDescriptors: List<Pair<PropertyDescriptor, IrProperty>> = emptyList()
protected set
protected fun findLocalSerializersFieldDescriptors(): List<IrProperty> {
val count = serializableIrClass.typeParameters.size
if (count == 0) return emptyList()
val propNames = (0 until count).map { "${SerialEntityNames.typeArgPrefix}$it" }
return propNames.mapNotNull { name ->
getProperty(name) { isKSerializer(it.getter!!.returnType) }
}
}
protected open val serialDescImplClass: ClassDescriptor = serializerDescriptor protected open val serialDescImplClass: IrClassSymbol =
.getClassFromInternalSerializationPackage(SERIAL_DESCRIPTOR_CLASS_IMPL) compilerContext.getClassFromInternalSerializationPackage(SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL)
override fun generateSerialDesc() { fun generateSerialDesc() {
val desc: PropertyDescriptor = generatedSerialDescPropertyDescriptor ?: return val desc = generatedSerialDescPropertyDescriptor ?: return
val addFuncS = serialDescImplClass.referenceFunctionSymbol(CallingConventions.addElement) val addFuncS = serialDescImplClass.functionByName(CallingConventions.addElement)
val thisAsReceiverParameter = irClass.thisReceiver!! val thisAsReceiverParameter = irClass.thisReceiver!!
lateinit var prop: IrProperty lateinit var prop: IrProperty
// how to (auto)create backing field and getter/setter? // how to (auto)create backing field and getter/setter?
compilerContext.symbolTable.withReferenceScope(irClass) { compilerContext.symbolTable.withReferenceScope(irClass) {
prop = generateSimplePropertyWithBackingField(desc, irClass) prop = generateSimplePropertyWithBackingField(desc.descriptor, irClass) // TODO check if this works correctly with old FE
// TODO: Do not use descriptors here // TODO: Do not use descriptors here
localSerializersFieldsDescriptors = findLocalSerializersFieldDescriptors().map { descriptor -> localSerializersFieldsDescriptors = findLocalSerializersFieldDescriptors().map { prop ->
descriptor to generateSimplePropertyWithBackingField(descriptor, irClass) prop.descriptor to generateSimplePropertyWithBackingField(prop.descriptor, irClass)
} }
} }
@@ -97,14 +130,14 @@ open class SerializerIrGenerator(
copySerialInfoAnnotationsToDescriptor( copySerialInfoAnnotationsToDescriptor(
collectSerialInfoAnnotations(serializableIrClass), collectSerialInfoAnnotations(serializableIrClass),
localDesc, localDesc,
serialDescImplClass.referenceFunctionSymbol(CallingConventions.addClassAnnotation) serialDescImplClass.functionByName(CallingConventions.addClassAnnotation)
) )
// save local descriptor to field // save local descriptor to field
+irSetField( +irSetField(
generateReceiverExpressionForFieldAccess( generateReceiverExpressionForFieldAccess(
thisAsReceiverParameter.symbol, thisAsReceiverParameter.symbol,
generatedSerialDescPropertyDescriptor generatedSerialDescPropertyDescriptor.descriptor
), ),
prop.backingField!!, prop.backingField!!,
irGet(localDesc) irGet(localDesc)
@@ -115,11 +148,11 @@ open class SerializerIrGenerator(
} }
protected open fun IrBlockBodyBuilder.instantiateNewDescriptor( protected open fun IrBlockBodyBuilder.instantiateNewDescriptor(
serialDescImplClass: ClassDescriptor, serialDescImplClass: IrClassSymbol,
correctThis: IrExpression correctThis: IrExpression
): IrExpression { ): IrExpression {
val classConstructors = compilerContext.referenceConstructors(serialDescImplClass.fqNameSafe) // val classConstructors = compilerContext.referenceConstructors(serialDescImplClass.fqNameSafe)
val serialClassDescImplCtor = classConstructors.single { it.owner.isPrimary } val serialClassDescImplCtor = serialDescImplClass.constructors.single { it.owner.isPrimary }
return irInvoke( return irInvoke(
null, serialClassDescImplCtor, null, serialClassDescImplCtor,
irString(serialName), if (isGeneratedSerializer) correctThis else irNull(), irInt(serializableProperties.size) irString(serialName), if (isGeneratedSerializer) correctThis else irNull(), irInt(serializableProperties.size)
@@ -127,11 +160,11 @@ open class SerializerIrGenerator(
} }
protected open fun IrBlockBodyBuilder.addElementsContentToDescriptor( protected open fun IrBlockBodyBuilder.addElementsContentToDescriptor(
serialDescImplClass: ClassDescriptor, serialDescImplClass: IrClassSymbol,
localDescriptor: IrVariable, localDescriptor: IrVariable,
addFunction: IrFunctionSymbol addFunction: IrFunctionSymbol
) { ) {
fun addFieldCall(prop: SerializableProperty) = irInvoke( fun addFieldCall(prop: IrSerializableProperty) = irInvoke(
irGet(localDescriptor), irGet(localDescriptor),
addFunction, addFunction,
irString(prop.name), irString(prop.name),
@@ -143,11 +176,11 @@ open class SerializerIrGenerator(
if (classProp.transient) continue if (classProp.transient) continue
+addFieldCall(classProp) +addFieldCall(classProp)
// add property annotations // add property annotations
val property = classProp.getIrPropertyFrom(serializableIrClass) val property = classProp.descriptor//.getIrPropertyFrom(serializableIrClass)
copySerialInfoAnnotationsToDescriptor( copySerialInfoAnnotationsToDescriptor(
property.annotations, property.annotations,
localDescriptor, localDescriptor,
serialDescImplClass.referenceFunctionSymbol(CallingConventions.addAnnotation) serialDescImplClass.functionByName(CallingConventions.addAnnotation)
) )
} }
} }
@@ -162,11 +195,10 @@ open class SerializerIrGenerator(
} }
} }
override fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ClassConstructorDescriptor) = fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: IrConstructor) =
irClass.contributeConstructor(typedConstructorDescriptor) { ctor -> addFunctionBody(typedConstructorDescriptor) { ctor ->
// generate call to primary ctor to init serialClassDesc and super() // generate call to primary ctor to init serialClassDesc and super()
val primaryCtor = irClass.constructors.find { it.isPrimary } val primaryCtor = irClass.constructors.primary
?: throw AssertionError("Serializer class must have primary constructor")
+IrDelegatingConstructorCallImpl.fromSymbolDescriptor( +IrDelegatingConstructorCallImpl.fromSymbolDescriptor(
startOffset, startOffset,
endOffset, endOffset,
@@ -191,7 +223,7 @@ open class SerializerIrGenerator(
} }
} }
override fun generateChildSerializersGetter(function: FunctionDescriptor) = irClass.contributeFunction(function) { irFun -> open fun generateChildSerializersGetter(function: IrSimpleFunction) = addFunctionBody(function) { irFun ->
val allSerializers = serializableProperties.map { val allSerializers = serializableProperties.map {
requireNotNull( requireNotNull(
serializerTower(this@SerializerIrGenerator, irFun.dispatchReceiverParameter!!, it) serializerTower(this@SerializerIrGenerator, irFun.dispatchReceiverParameter!!, it)
@@ -203,8 +235,8 @@ open class SerializerIrGenerator(
+irReturn(array) +irReturn(array)
} }
override fun generateTypeParamsSerializersGetter(function: FunctionDescriptor) = irClass.contributeFunction(function) { irFun -> open fun generateTypeParamsSerializersGetter(function: IrSimpleFunction) = addFunctionBody(function) { irFun ->
val typeParams = serializableDescriptor.declaredTypeParameters.mapIndexed { idx, _ -> val typeParams = serializableIrClass.typeParameters.mapIndexed { idx, _ ->
irGetField( irGetField(
irGet(irFun.dispatchReceiverParameter!!), irGet(irFun.dispatchReceiverParameter!!),
localSerializersFieldsDescriptors[idx].second.backingField!! localSerializersFieldsDescriptors[idx].second.backingField!!
@@ -215,26 +247,26 @@ open class SerializerIrGenerator(
+irReturn(array) +irReturn(array)
} }
override fun generateSerializableClassProperty(property: PropertyDescriptor) { open fun generateSerializableClassProperty(property: IrProperty) {
/* Already implemented in .generateSerialClassDesc ? */ /* Already implemented in .generateSerialClassDesc ? */
} }
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc -> open fun generateSave(function: IrSimpleFunction) = addFunctionBody(function) { saveFunc ->
fun irThis(): IrExpression = fun irThis(): IrExpression =
IrGetValueImpl(startOffset, endOffset, saveFunc.dispatchReceiverParameter!!.symbol) IrGetValueImpl(startOffset, endOffset, saveFunc.dispatchReceiverParameter!!.symbol)
val kOutputClass = serializerDescriptor.getClassFromSerializationPackage(STRUCTURE_ENCODER_CLASS) val kOutputClass = compilerContext.getClassFromRuntime(STRUCTURE_ENCODER_CLASS)
val encoderClass = serializerDescriptor.getClassFromSerializationPackage(ENCODER_CLASS) val encoderClass = compilerContext.getClassFromRuntime(ENCODER_CLASS)
val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol val descriptorGetterSymbol = irAnySerialDescProperty?.getter!!.symbol
val localSerialDesc = irTemporary(irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol), "desc") val localSerialDesc = irTemporary(irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol), "desc")
// fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): StructureEncoder // fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): StructureEncoder
val beginFunc = encoderClass.referenceFunctionSymbol(CallingConventions.begin) { it.valueParameters.size == 1 } val beginFunc = encoderClass.functions.single { it.owner.name.asString() == CallingConventions.begin && it.owner.valueParameters.size == 1 }
val call = irCall(beginFunc, type = kOutputClass.defaultType.toIrType()).mapValueParametersIndexed { _, _ -> val call = irCall(beginFunc, type = kOutputClass.defaultType).mapValueParametersIndexed { _, _ ->
irGet(localSerialDesc) irGet(localSerialDesc)
} }
// can it be done in more concise way? e.g. additional builder function? // can it be done in more concise way? e.g. additional builder function?
@@ -274,16 +306,16 @@ open class SerializerIrGenerator(
} }
// output.writeEnd(serialClassDesc) // output.writeEnd(serialClassDesc)
val wEndFunc = kOutputClass.referenceFunctionSymbol(CallingConventions.end) val wEndFunc = kOutputClass.functionByName(CallingConventions.end)
+irInvoke(irGet(localOutput), wEndFunc, irGet(localSerialDesc)) +irInvoke(irGet(localOutput), wEndFunc, irGet(localSerialDesc))
} }
protected fun IrBlockBodyBuilder.formEncodeDecodePropertyCall( protected fun IrBlockBodyBuilder.formEncodeDecodePropertyCall(
encoder: IrExpression, encoder: IrExpression,
dispatchReceiver: IrValueParameter, dispatchReceiver: IrValueParameter,
property: SerializableProperty, property: IrSerializableProperty,
whenHaveSerializer: (serializer: IrExpression, sti: SerialTypeInfo) -> FunctionWithArgs, whenHaveSerializer: (serializer: IrExpression, sti: IrSerialTypeInfo) -> FunctionWithArgs,
whenDoNot: (sti: SerialTypeInfo) -> FunctionWithArgs, whenDoNot: (sti: IrSerialTypeInfo) -> FunctionWithArgs,
returnTypeHint: IrType? = null returnTypeHint: IrType? = null
): IrExpression = formEncodeDecodePropertyCall( ): IrExpression = formEncodeDecodePropertyCall(
this@SerializerIrGenerator, this@SerializerIrGenerator,
@@ -299,9 +331,8 @@ open class SerializerIrGenerator(
) )
// returns null: Any? for boxed types and 0: <number type> for primitives // returns null: Any? for boxed types and 0: <number type> for primitives
private fun IrBuilderWithScope.defaultValueAndType(descriptor: PropertyDescriptor): Pair<IrExpression, IrType> { private fun IrBuilderWithScope.defaultValueAndType(descriptor: IrProperty): Pair<IrExpression, IrType> {
val kType = descriptor.returnType!! val T = descriptor.getter!!.returnType
val T = kType.toIrType()
val defaultPrimitive: IrExpression? = val defaultPrimitive: IrExpression? =
if (T.isMarkedNullable()) null if (T.isMarkedNullable()) null
else when (T.getPrimitiveType()) { else when (T.getPrimitiveType()) {
@@ -321,9 +352,9 @@ open class SerializerIrGenerator(
defaultPrimitive to T defaultPrimitive to T
} }
override fun generateLoad(function: FunctionDescriptor) = irClass.contributeFunction(function) { loadFunc -> open fun generateLoad(function: IrSimpleFunction) = addFunctionBody(function) { loadFunc ->
if (serializableDescriptor.modality == Modality.ABSTRACT || serializableDescriptor.modality == Modality.SEALED) { if (serializableIrClass.modality == Modality.ABSTRACT || serializableIrClass.modality == Modality.SEALED) {
return@contributeFunction return@addFunctionBody
} }
fun irThis(): IrExpression = fun irThis(): IrExpression =
@@ -331,9 +362,9 @@ open class SerializerIrGenerator(
fun IrVariable.get() = irGet(this) fun IrVariable.get() = irGet(this)
val inputClass = serializerDescriptor.getClassFromSerializationPackage(STRUCTURE_DECODER_CLASS) val inputClass = compilerContext.getClassFromRuntime(STRUCTURE_DECODER_CLASS)
val decoderClass = serializerDescriptor.getClassFromSerializationPackage(DECODER_CLASS) val decoderClass = compilerContext.getClassFromRuntime(DECODER_CLASS)
val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol val descriptorGetterSymbol = irAnySerialDescProperty?.getter!!.symbol
val localSerialDesc = irTemporary(irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol), "desc") val localSerialDesc = irTemporary(irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol), "desc")
// workaround due to unavailability of labels (KT-25386) // workaround due to unavailability of labels (KT-25386)
@@ -350,7 +381,7 @@ open class SerializerIrGenerator(
val transients = serializableIrClass.declarations.asSequence() val transients = serializableIrClass.declarations.asSequence()
.filterIsInstance<IrProperty>() .filterIsInstance<IrProperty>()
.filter { !serialPropertiesIndexes.containsKey(it.descriptor) } .filter { !serialPropertiesIndexes.contains(it) }
.filter { it.backingField != null } .filter { it.backingField != null }
// var bitMask0 = 0, bitMask1 = 0... // var bitMask0 = 0, bitMask1 = 0...
@@ -361,18 +392,18 @@ open class SerializerIrGenerator(
descriptor to irTemporary(expr, "local$i", type, isMutable = true) descriptor to irTemporary(expr, "local$i", type, isMutable = true)
} }
// var transient0 = null, transient0 = null ... // var transient0 = null, transient0 = null ...
val transientsPropertiesMap = transients.mapIndexed { i, prop -> i to prop.descriptor }.associate { (i, descriptor) -> val transientsPropertiesMap = transients.mapIndexed { i, prop -> i to prop }.associate { (i, descriptor) ->
val (expr, type) = defaultValueAndType(descriptor) val (expr, type) = defaultValueAndType(descriptor)
descriptor to irTemporary(expr, "transient$i", type, isMutable = true) descriptor to irTemporary(expr, "transient$i", type, isMutable = true)
} }
//input = input.beginStructure(...) //input = input.beginStructure(...)
val beginFunc = decoderClass.referenceFunctionSymbol(CallingConventions.begin) { it.valueParameters.size == 1 } val beginFunc = decoderClass.functions.single { it.owner.name.asString() == CallingConventions.begin && it.owner.valueParameters.size == 1 }
val call = irInvoke( val call = irInvoke(
irGet(loadFunc.valueParameters[0]), irGet(loadFunc.valueParameters[0]),
beginFunc, beginFunc,
irGet(localSerialDesc), irGet(localSerialDesc),
typeHint = inputClass.defaultType.toIrType() typeHint = inputClass.defaultType
) )
val localInput = irTemporary(call, "input") val localInput = irTemporary(call, "input")
@@ -380,19 +411,20 @@ open class SerializerIrGenerator(
val decoderCalls: List<Pair<Int, IrExpression>> = val decoderCalls: List<Pair<Int, IrExpression>> =
serializableProperties.mapIndexed { index, property -> serializableProperties.mapIndexed { index, property ->
val body = irBlock { val body = irBlock {
val decodeFuncToCall = formEncodeDecodePropertyCall(localInput.get(), loadFunc.dispatchReceiverParameter!!, property, {innerSerial, sti -> val decodeFuncToCall =
inputClass.referenceFunctionSymbol( formEncodeDecodePropertyCall(localInput.get(), loadFunc.dispatchReceiverParameter!!, property, { innerSerial, sti ->
"${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}", {it.valueParameters.size == 4} inputClass.functions.single {
) to listOf( it.owner.name.asString() == "${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}" &&
localSerialDesc.get(), irInt(index), innerSerial, serialPropertiesMap.getValue(property.descriptor).get() it.owner.valueParameters.size == 4
) } to listOf(
}, { localSerialDesc.get(), irInt(index), innerSerial, serialPropertiesMap.getValue(property.descriptor).get()
inputClass.referenceFunctionSymbol( )
"${CallingConventions.decode}${it.elementMethodPrefix}${CallingConventions.elementPostfix}", {it.valueParameters.size == 2} }, {sti ->
) to listOf( inputClass.functions.single {
localSerialDesc.get(), irInt(index) it.owner.name.asString() == "${CallingConventions.decode}${sti.elementMethodPrefix}${CallingConventions.elementPostfix}" &&
) it.owner.valueParameters.size == 2
}, returnTypeHint = property.type.toIrType()) } to listOf(localSerialDesc.get(), irInt(index))
}, returnTypeHint = property.type)
// local$i = localInput.decode...(...) // local$i = localInput.decode...(...)
+irSet( +irSet(
serialPropertiesMap.getValue(property.descriptor).symbol, serialPropertiesMap.getValue(property.descriptor).symbol,
@@ -407,7 +439,7 @@ open class SerializerIrGenerator(
} }
// if (decoder.decodeSequentially()) // if (decoder.decodeSequentially())
val decodeSequentiallyCall = irInvoke(localInput.get(), inputClass.referenceFunctionSymbol(CallingConventions.decodeSequentially)) val decodeSequentiallyCall = irInvoke(localInput.get(), inputClass.functionByName(CallingConventions.decodeSequentially))
val sequentialPart = irBlock { val sequentialPart = irBlock {
decoderCalls.forEach { (_, expr) -> +expr.deepCopyWithVariables() } decoderCalls.forEach { (_, expr) -> +expr.deepCopyWithVariables() }
@@ -416,7 +448,7 @@ open class SerializerIrGenerator(
val byIndexPart: IrExpression = irWhile().also { loop -> val byIndexPart: IrExpression = irWhile().also { loop ->
loop.condition = flagVar.get() loop.condition = flagVar.get()
loop.body = irBlock { loop.body = irBlock {
val readElementF = inputClass.referenceFunctionSymbol(CallingConventions.decodeElementIndex) val readElementF = inputClass.functionByName(CallingConventions.decodeElementIndex)
+irSet(indexVar.symbol, irInvoke(localInput.get(), readElementF, localSerialDesc.get())) +irSet(indexVar.symbol, irInvoke(localInput.get(), readElementF, localSerialDesc.get()))
+irWhen { +irWhen {
// if index == -1 (READ_DONE) break loop // if index == -1 (READ_DONE) break loop
@@ -445,7 +477,7 @@ open class SerializerIrGenerator(
+irIfThenElse(compilerContext.irBuiltIns.unitType, decodeSequentiallyCall, sequentialPart, byIndexPart) +irIfThenElse(compilerContext.irBuiltIns.unitType, decodeSequentiallyCall, sequentialPart, byIndexPart)
//input.endStructure(...) //input.endStructure(...)
val endFunc = inputClass.referenceFunctionSymbol(CallingConventions.end) val endFunc = inputClass.functionByName(CallingConventions.end)
+irInvoke( +irInvoke(
localInput.get(), localInput.get(),
endFunc, endFunc,
@@ -453,16 +485,16 @@ 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 }
if (serializableDescriptor.isInternalSerializable) { if (serializableIrClass.isInternalSerializable) {
var args: List<IrExpression> = serializableProperties.map { serialPropertiesMap.getValue(it.descriptor).get() } var args: List<IrExpression> = serializableProperties.map { serialPropertiesMap.getValue(it.descriptor).get() }
args = bitMasks.map { irGet(it) } + args + irNull() args = bitMasks.map { irGet(it) } + args + irNull()
val ctor: IrConstructorSymbol = serializableSyntheticConstructor(serializableIrClass) val ctor: IrConstructorSymbol = serializableSyntheticConstructor(serializableIrClass)
+irReturn(irInvoke(null, ctor, typeArgs, args)) +irReturn(irInvoke(null, ctor, typeArgs, args))
} else { } else {
if (DescriptorUtils.isLocal(serializerDescriptor)) { if (irClass.isLocal) {
// if the serializer is local, then the serializable class too, since they must be in the same scope // if the serializer is local, then the serializable class too, since they must be in the same scope
throw CompilationException( throw CompilationException(
"External serializer class `${serializerDescriptor.fqNameSafe}` is local. Local external serializers are not supported yet.", "External serializer class `${irClass.fqNameWhenAvailable}` is local. Local external serializers are not supported yet.",
null, null,
null null
) )
@@ -470,13 +502,11 @@ open class SerializerIrGenerator(
generateGoldenMaskCheck(bitMasks, properties, localSerialDesc.get()) generateGoldenMaskCheck(bitMasks, properties, localSerialDesc.get())
val ctor: IrConstructorSymbol = val ctor: IrConstructorSymbol = serializableIrClass.constructors.primary.symbol
compilerContext.referenceConstructors(serializableDescriptor.fqNameSafe).single { it.owner.isPrimary }
val params = ctor.owner.valueParameters val params = ctor.owner.valueParameters
val variableByParamReplacer: (ValueParameterDescriptor) -> IrExpression? = { vpd ->
val variableByParamReplacer: (ValueParameterDescriptor) -> IrExpression? = { val propertyDescriptor = serializableIrClass.properties.find { it.name == vpd.name }
val propertyDescriptor = bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, it]
if (propertyDescriptor != null) { if (propertyDescriptor != null) {
val serializable = serialPropertiesMap[propertyDescriptor] val serializable = serialPropertiesMap[propertyDescriptor]
(serializable ?: transientsPropertiesMap[propertyDescriptor])?.get() (serializable ?: transientsPropertiesMap[propertyDescriptor])?.get()
@@ -489,8 +519,8 @@ open class SerializerIrGenerator(
// constructor args: // constructor args:
val ctorArgs = params.map { parameter -> val ctorArgs = params.map { parameter ->
val parameterDescriptor = parameter.descriptor as ValueParameterDescriptor val propertyDescriptor = serializableIrClass.properties.find { it.name == parameter.name }!! // todo: check with tests
val propertyDescriptor = bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameterDescriptor]!! val parameterDescriptor = parameter.descriptor as ValueParameterDescriptor // TODO: remove descriptor here
val serialProperty = serialPropertiesMap[propertyDescriptor] val serialProperty = serialPropertiesMap[propertyDescriptor]
// null if transient // null if transient
@@ -532,14 +562,14 @@ open class SerializerIrGenerator(
private fun IrBlockBodyBuilder.generateSetStandaloneProperties( private fun IrBlockBodyBuilder.generateSetStandaloneProperties(
serializableVar: IrVariable, serializableVar: IrVariable,
propVars: (PropertyDescriptor) -> IrVariable, propVars: (IrProperty) -> IrVariable,
propIndexes: (PropertyDescriptor) -> Int, propIndexes: (IrProperty) -> Int,
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.descriptor)
// generate setter call // generate setter call
val setter = property.getIrPropertyFrom(serializableIrClass).setter!! val setter = property.descriptor.setter!!
val propSeenTest = val propSeenTest =
irNotEquals( irNotEquals(
irInt(0), irInt(0),
@@ -556,21 +586,46 @@ open class SerializerIrGenerator(
} }
} }
// !!! TODO: this doesn't work with OLD FE !!!
fun generate() {
val prop = generatedSerialDescPropertyDescriptor?.let { generateSerializableClassProperty(it); true } ?: false
if (prop)
generateSerialDesc()
val save = irClass.findPluginGeneratedMethod(SAVE)?.let { generateSave(it); true } ?: false
val load = irClass.findPluginGeneratedMethod(SAVE)?.let { generateSave(it); true } ?: false
irClass.findPluginGeneratedMethod(SerialEntityNames.CHILD_SERIALIZERS_GETTER.identifier)?.let { generateChildSerializersGetter(it) }
irClass.findPluginGeneratedMethod(SerialEntityNames.TYPE_PARAMS_SERIALIZERS_GETTER.identifier)?.let { generateTypeParamsSerializersGetter(it) }
if (!prop && (save || load))
generateSerialDesc()
if (serializableIrClass.typeParameters.isNotEmpty()) {
findSerializerConstructorForTypeArgumentsSerializers(irClass)?.let {
generateGenericFieldsAndConstructor(it.owner)
}
}
}
companion object { companion object {
fun generate( fun generate(
irClass: IrClass, irClass: IrClass,
context: SerializationPluginContext, context: SerializationPluginContext,
bindingContext: BindingContext,
metadataPlugin: SerializationDescriptorSerializerPlugin?, metadataPlugin: SerializationDescriptorSerializerPlugin?,
serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator, serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
) { ) {
val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return
val generator = when { val generator = when {
serializableDesc.isEnumWithLegacyGeneratedSerializer() -> SerializerForEnumsGenerator(irClass, context, bindingContext, serialInfoJvmGenerator) serializableDesc.isEnumWithLegacyGeneratedSerializer() -> SerializerForEnumsGenerator(
serializableDesc.isInlineClass() -> SerializerForInlineClassGenerator(irClass, context, bindingContext, serialInfoJvmGenerator) irClass,
else -> SerializerIrGenerator(irClass, context, bindingContext, metadataPlugin, serialInfoJvmGenerator) context,
serialInfoJvmGenerator
)
serializableDesc.isInlineClass() -> SerializerForInlineClassGenerator(irClass, context, serialInfoJvmGenerator)
else -> SerializerIrGenerator(irClass, context, metadataPlugin, serialInfoJvmGenerator)
} }
generator.generate() generator.generate()
val declaration = irClass.constructors.primary // todo: move to appropriate place
if (declaration.body == null) declaration.body = context.generateBodyForDefaultConstructor(declaration)
irClass.patchDeclarationParents(irClass.parent) irClass.patchDeclarationParents(irClass.parent)
} }
} }
@@ -51,8 +51,8 @@ object VersionReader {
return versions return versions
} }
fun getVersionsForCurrentModuleFromContext(module: ModuleDescriptor, context: BindingContext): RuntimeVersions? { fun getVersionsForCurrentModuleFromContext(module: ModuleDescriptor, context: BindingContext?): RuntimeVersions? {
context.get(VERSIONS_SLICE, module)?.let { return it } context?.get(VERSIONS_SLICE, module)?.let { return it }
return getVersionsForCurrentModule(module) return getVersionsForCurrentModule(module)
} }
@@ -56,9 +56,9 @@ private class SerializerClassLowering(
private val serialInfoJvmGenerator = SerialInfoImplJvmIrGenerator(context, moduleFragment).also { context.serialInfoImplJvmIrGenerator = it } private val serialInfoJvmGenerator = SerialInfoImplJvmIrGenerator(context, moduleFragment).also { context.serialInfoImplJvmIrGenerator = it }
override fun lower(irClass: IrClass) { override fun lower(irClass: IrClass) {
SerializableIrGenerator.generate(irClass, context, context.bindingContext) SerializableIrGenerator.generate(irClass, context)
SerializerIrGenerator.generate(irClass, context, context.bindingContext, context.metadataPlugin, serialInfoJvmGenerator) SerializerIrGenerator.generate(irClass, context, context.metadataPlugin, serialInfoJvmGenerator)
SerializableCompanionIrGenerator.generate(irClass, context, context.bindingContext) SerializableCompanionIrGenerator.generate(irClass, context)
if (context.platform.isJvm() && KSerializerDescriptorResolver.isSerialInfoImpl(irClass.descriptor)) { if (context.platform.isJvm() && KSerializerDescriptorResolver.isSerialInfoImpl(irClass.descriptor)) {
serialInfoJvmGenerator.generate(irClass) serialInfoJvmGenerator.generate(irClass)
@@ -34,7 +34,7 @@ import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
// FIXME: this has to be shared (copied from plugin example) // FIXME KT-53096: this has to be shared (copied from plugin example)
@OptIn(SymbolInternals::class) @OptIn(SymbolInternals::class)
fun FirDeclarationGenerationExtension.buildConstructor(classId: ClassId, isInner: Boolean, key: GeneratedDeclarationKey): FirConstructor { fun FirDeclarationGenerationExtension.buildConstructor(classId: ClassId, isInner: Boolean, key: GeneratedDeclarationKey): FirConstructor {
val lookupTag = ConeClassLikeLookupTagImpl(classId) val lookupTag = ConeClassLikeLookupTagImpl(classId)
@@ -212,7 +212,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
return f.symbol return f.symbol
} }
@OptIn(SymbolInternals::class) @OptIn(SymbolInternals::class) // TODO: localSerializersFieldDescriptors
override fun generateProperties(callableId: CallableId, context: MemberGenerationContext?): List<FirPropertySymbol> { override fun generateProperties(callableId: CallableId, context: MemberGenerationContext?): List<FirPropertySymbol> {
val owner = context?.owner ?: return emptyList() val owner = context?.owner ?: return emptyList()
if (owner.name != SerialEntityNames.SERIALIZER_CLASS_NAME) return emptyList() if (owner.name != SerialEntityNames.SERIALIZER_CLASS_NAME) return emptyList()
@@ -5,6 +5,8 @@
package org.jetbrains.kotlinx.serialization.compiler.resolve package org.jetbrains.kotlinx.serialization.compiler.resolve
import org.jetbrains.kotlin.name.CallableId
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
@@ -110,6 +112,7 @@ object SerialEntityNames {
internal const val typeArgPrefix = "typeSerial" internal const val typeArgPrefix = "typeSerial"
internal val wrapIntoNullableExt = SerializationPackages.builtinsPackageFqName.child(Name.identifier("nullable")) internal val wrapIntoNullableExt = SerializationPackages.builtinsPackageFqName.child(Name.identifier("nullable"))
internal val wrapIntoNullableCallableId = CallableId(SerializationPackages.builtinsPackageFqName, Name.identifier("nullable"))
} }
object SpecialBuiltins { object SpecialBuiltins {
@@ -6,6 +6,15 @@
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
@@ -17,25 +26,43 @@ 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.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
class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) { interface ISerializableProperties<D, T, S : ISerializableProperty<D, T>> {
val serializableProperties: List<S>
val isExternallySerializable: Boolean
val serializableConstructorProperties: List<S>
val serializableStandaloneProperties: List<S>
}
class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext?) :
ISerializableProperties<PropertyDescriptor, KotlinType, SerializableProperty> {
private val primaryConstructorParameters: List<ValueParameterDescriptor> = private val primaryConstructorParameters: List<ValueParameterDescriptor> =
serializableClass.unsubstitutedPrimaryConstructor?.valueParameters ?: emptyList() serializableClass.unsubstitutedPrimaryConstructor?.valueParameters ?: emptyList()
val serializableProperties: List<SerializableProperty> override val serializableProperties: List<SerializableProperty>
val isExternallySerializable: Boolean override val isExternallySerializable: Boolean
private val primaryConstructorProperties: Map<PropertyDescriptor, Boolean> private val primaryConstructorProperties: Map<PropertyDescriptor, Boolean>
init { init {
val descriptorsSequence = serializableClass.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES) val descriptorsSequence = serializableClass.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES)
.asSequence() .asSequence()
// call to any BindingContext.get should be only AFTER MemberScope.getContributedDescriptors // call to any BindingContext.get should be only AFTER MemberScope.getContributedDescriptors
// TODO: fix binding context shit
primaryConstructorProperties = primaryConstructorProperties =
primaryConstructorParameters.asSequence() primaryConstructorParameters.asSequence()
.map { parameter -> bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter] to parameter.declaresDefaultValue() } .map { parameter ->
bindingContext?.get(
BindingContext.VALUE_PARAMETER_AS_PROPERTY,
parameter
) to parameter.declaresDefaultValue()
}
.mapNotNull { (a, b) -> if (a == null) null else a to b } .mapNotNull { (a, b) -> if (a == null) null else a to b }
.toMap() .toMap()
@@ -56,7 +83,8 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
prop.hasBackingField(bindingContext) || (prop is DeserializedPropertyDescriptor && prop.backingField != null) // workaround for TODO in .hasBackingField prop.hasBackingField(bindingContext) || (prop is DeserializedPropertyDescriptor && prop.backingField != null) // workaround for TODO in .hasBackingField
// workaround for overridden getter (val) and getter+setter (var) - in this case hasBackingField returning false // workaround for overridden getter (val) and getter+setter (var) - in this case hasBackingField returning false
// but initializer presents only for property with backing field // but initializer presents only for property with backing field
|| declaresDefaultValue, || declaresDefaultValue
|| prop.backingField != null, // todo: find out what happens next
declaresDefaultValue declaresDefaultValue
) )
} }
@@ -76,12 +104,12 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
} }
val serializableConstructorProperties: List<SerializableProperty> = override val serializableConstructorProperties: List<SerializableProperty> =
serializableProperties.asSequence() serializableProperties.asSequence()
.filter { primaryConstructorProperties.contains(it.descriptor) } .filter { primaryConstructorProperties.contains(it.descriptor) }
.toList() .toList()
val serializableStandaloneProperties: List<SerializableProperty> = override val serializableStandaloneProperties: List<SerializableProperty> =
serializableProperties.minus(serializableConstructorProperties) serializableProperties.minus(serializableConstructorProperties)
val size = serializableProperties.size val size = serializableProperties.size
@@ -92,7 +120,7 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
?.original?.valueParameters?.any { it.declaresDefaultValue() } ?: false ?.original?.valueParameters?.any { it.declaresDefaultValue() } ?: false
} }
fun PropertyDescriptor.declaresDefaultValue(): Boolean{ fun PropertyDescriptor.declaresDefaultValue(): Boolean {
when (val declaration = this.source.getPsi()) { when (val declaration = this.source.getPsi()) {
is KtDeclarationWithInitializer -> return declaration.initializer != null is KtDeclarationWithInitializer -> return declaration.initializer != null
is KtParameter -> return declaration.defaultValue != null is KtParameter -> return declaration.defaultValue != null
@@ -112,7 +140,7 @@ fun PropertyDescriptor.declaresDefaultValue(): Boolean{
} }
internal val SerializableProperties.goldenMask: Int internal val ISerializableProperties<*, *, *>.goldenMask: Int
get() { get() {
var goldenMask = 0 var goldenMask = 0
var requiredBit = 1 var requiredBit = 1
@@ -125,7 +153,7 @@ internal val SerializableProperties.goldenMask: Int
return goldenMask return goldenMask
} }
internal val SerializableProperties.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 }
@@ -140,11 +168,14 @@ internal val SerializableProperties.goldenMaskList: List<Int>
return goldenMaskList return goldenMaskList
} }
internal fun List<SerializableProperty>.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(classDescriptor: ClassDescriptor, serializationDescriptorSerializer: SerializationDescriptorSerializerPlugin? = null): SerializableProperties { internal fun BindingContext?.serializablePropertiesFor(
val props = this.get(SERIALIZABLE_PROPERTIES, classDescriptor) ?: SerializableProperties(classDescriptor, this) classDescriptor: ClassDescriptor,
serializationDescriptorSerializer: SerializationDescriptorSerializerPlugin? = null
): SerializableProperties {
val props = this?.get(SERIALIZABLE_PROPERTIES, classDescriptor) ?: SerializableProperties(classDescriptor, this)
serializationDescriptorSerializer?.putIfNeeded(classDescriptor, props) serializationDescriptorSerializer?.putIfNeeded(classDescriptor, props)
return props return props
} }
@@ -156,3 +187,73 @@ private fun unsort(descriptor: ClassDescriptor, props: List<SerializableProperty
val propsMap = props.associateBy { it.descriptor.name } val propsMap = props.associateBy { it.descriptor.name }
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 BindingContext?.serializablePropertiesForIrBackend(
classDescriptor: IrClass,
serializationDescriptorSerializer: SerializationDescriptorSerializerPlugin? = null
): IrSerializableProperties {
if (this != null) {
// can work with old FE
TODO("Support this for old FE")
} else {
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
.filter { !it.isFakeOverride && !it.isDelegated }
.filter(::isPropSerializable)
.map {
val isConstructorParameterWithDefault = primaryParamsAsProps[it] ?: false
IrSerializableProperty(
it,
isConstructorParameterWithDefault,
it.backingField != null,
it.backingField?.initializer != null || isConstructorParameterWithDefault
)
}
.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
}
@@ -19,26 +19,63 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve
import org.jetbrains.kotlin.descriptors.ClassDescriptor 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.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.fir.scopes.impl.overrides
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.ir.util.module
import org.jetbrains.kotlin.psi.KtDeclarationWithInitializer import org.jetbrains.kotlin.psi.KtDeclarationWithInitializer
import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.ValueArgument import org.jetbrains.kotlin.psi.ValueArgument
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.asSimpleType
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.overridenSerializer
import org.jetbrains.kotlinx.serialization.compiler.backend.common.serialNameValue
class SerializableProperty( class SerializableProperty(
val descriptor: PropertyDescriptor, override val descriptor: PropertyDescriptor,
val isConstructorParameterWithDefault: Boolean, override val isConstructorParameterWithDefault: Boolean,
hasBackingField: Boolean, hasBackingField: Boolean,
declaresDefaultValue: Boolean declaresDefaultValue: Boolean
) { ) : ISerializableProperty<PropertyDescriptor, KotlinType> {
val name = descriptor.annotations.serialNameValue ?: descriptor.name.asString() override val name = descriptor.annotations.serialNameValue ?: descriptor.name.asString()
val type = descriptor.type override val type = descriptor.type
val genericIndex = type.genericIndex override val genericIndex = type.genericIndex
val module = descriptor.module val module = descriptor.module
val serializableWith = descriptor.serializableWith ?: analyzeSpecialSerializers(module, descriptor.annotations)?.defaultType override val serializableWith = descriptor.serializableWith ?: analyzeSpecialSerializers(module, descriptor.annotations)?.defaultType
val optional = !descriptor.annotations.serialRequired && declaresDefaultValue override val optional = !descriptor.annotations.serialRequired && declaresDefaultValue
val transient = descriptor.annotations.serialTransient || !hasBackingField override val transient = descriptor.annotations.serialTransient || !hasBackingField
val annotationsWithArguments: List<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> = val annotationsWithArguments: List<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> =
descriptor.annotationsWithArguments() descriptor.annotationsWithArguments()
} }
interface ISerializableProperty<D, T> {
val descriptor: D
val isConstructorParameterWithDefault: Boolean
val name: String
val type: T
val genericIndex: Int?
val serializableWith: T?
val optional: Boolean
val transient: Boolean
}
class IrSerializableProperty(
override val descriptor: IrProperty,
override val isConstructorParameterWithDefault: Boolean,
hasBackingField: Boolean,
declaresDefaultValue: Boolean
) : ISerializableProperty<IrProperty, IrSimpleType> {
override val name = descriptor.annotations.serialNameValue ?: descriptor.name.asString()
override val type = descriptor.getter!!.returnType as IrSimpleType
override val genericIndex = type.genericIndex
override val serializableWith = type.overridenSerializer /* ?:analyzeSpecialSerializers(module, descriptor.annotations)?.defaultType */ // TODO
override val optional = !descriptor.annotations.hasAnnotation(SerializationAnnotations.requiredAnnotationFqName) && declaresDefaultValue
override val transient = descriptor.annotations.hasAnnotation(SerializationAnnotations.serialTransientFqName) || !hasBackingField
}
@@ -8,17 +8,22 @@ package org.jetbrains.kotlinx.serialization
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter
import org.jetbrains.kotlin.test.TargetBackend import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.backend.BlackBoxCodegenSuppressor import org.jetbrains.kotlin.test.backend.BlackBoxCodegenSuppressor
import org.jetbrains.kotlin.test.backend.handlers.* import org.jetbrains.kotlin.test.backend.handlers.IrTextDumpHandler
import org.jetbrains.kotlin.test.backend.handlers.IrTreeVerifierHandler
import org.jetbrains.kotlin.test.backend.handlers.JvmBoxRunner
import org.jetbrains.kotlin.test.backend.ir.JvmIrBackendFacade import org.jetbrains.kotlin.test.backend.ir.JvmIrBackendFacade
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.builders.fir2IrStep import org.jetbrains.kotlin.test.builders.fir2IrStep
import org.jetbrains.kotlin.test.builders.irHandlersStep import org.jetbrains.kotlin.test.builders.irHandlersStep
import org.jetbrains.kotlin.test.builders.jvmArtifactsHandlersStep import org.jetbrains.kotlin.test.builders.jvmArtifactsHandlersStep
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerTest import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerTest
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerWithTargetBackendTest import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerWithTargetBackendTest
import org.jetbrains.kotlin.test.runners.baseFirDiagnosticTestConfiguration import org.jetbrains.kotlin.test.runners.baseFirDiagnosticTestConfiguration
import org.jetbrains.kotlin.test.services.RuntimeClasspathProvider
import org.jetbrains.kotlinx.serialization.compiler.fir.FirSerializationExtensionRegistrar import org.jetbrains.kotlinx.serialization.compiler.fir.FirSerializationExtensionRegistrar
import java.io.File
abstract class AbstractSerializationFirMembersTest: AbstractKotlinCompilerTest() { abstract class AbstractSerializationFirMembersTest: AbstractKotlinCompilerTest() {
override fun TestConfigurationBuilder.configuration() { override fun TestConfigurationBuilder.configuration() {
@@ -38,6 +43,16 @@ abstract class AbstractSerializationFirMembersTest: AbstractKotlinCompilerTest()
open class AbstractSerializationFirBlackBoxTest : AbstractKotlinCompilerWithTargetBackendTest(TargetBackend.JVM_IR) { open class AbstractSerializationFirBlackBoxTest : AbstractKotlinCompilerWithTargetBackendTest(TargetBackend.JVM_IR) {
override fun TestConfigurationBuilder.configuration() { override fun TestConfigurationBuilder.configuration() {
baseFirDiagnosticTestConfiguration() baseFirDiagnosticTestConfiguration()
configureForKotlinxSerialization(listOf(getSerializationCoreLibraryJar()!!)) {
FirExtensionRegistrarAdapter.registerExtension(FirSerializationExtensionRegistrar())
}
useCustomRuntimeClasspathProviders({ ts ->
object : RuntimeClasspathProvider(ts) {
override fun runtimeClassPaths(module: TestModule): List<File> {
return listOf(getSerializationCoreLibraryJar()!!)
}
}
})
defaultDirectives { defaultDirectives {
+FirDiagnosticsDirectives.ENABLE_PLUGIN_PHASES +FirDiagnosticsDirectives.ENABLE_PLUGIN_PHASES
} }
@@ -55,9 +70,5 @@ open class AbstractSerializationFirBlackBoxTest : AbstractKotlinCompilerWithTarg
} }
useAfterAnalysisCheckers(::BlackBoxCodegenSuppressor) useAfterAnalysisCheckers(::BlackBoxCodegenSuppressor)
configureForKotlinxSerialization(listOf(getSerializationCoreLibraryJar()!!)) {
FirExtensionRegistrarAdapter.registerExtension(FirSerializationExtensionRegistrar())
}
} }
} }