Skip to content

Commit

Permalink
Use EnumSerializer for explicitly serializable enum instead of auto-g…
Browse files Browse the repository at this point in the history
  • Loading branch information
shanshin committed May 26, 2022
1 parent c230a48 commit ec6a8aa
Show file tree
Hide file tree
Showing 14 changed files with 305 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ abstract class SerializableCompanionCodegen(
"probably clash with user-defined function has occurred"
)

if (serializableDescriptor.isSerializableObject || serializableDescriptor.isAbstractOrSealedSerializableClass()) {
if (serializableDescriptor.isSerializableObject
|| serializableDescriptor.isAbstractOrSealedSerializableClass()
|| serializableDescriptor.isSerializableEnum()
) {
generateLazySerializerGetter(serializerGetterDescriptor)
} else {
generateSerializerGetter(serializerGetterDescriptor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType

fun findEnumTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? {
val classDescriptor = kType.toClassDescriptor ?: return null
return if (classDescriptor.kind == ClassKind.ENUM_CLASS && !classDescriptor.isInternallySerializableEnum())
return if (classDescriptor.kind == ClassKind.ENUM_CLASS && !classDescriptor.isEnumWithLegacyGeneratedSerializer())
module.findClassAcrossModuleDependencies(enumSerializerId)
else null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ interface IrBuilderExtension {
private val throwMissedFieldExceptionArrayFunc
get() = compilerContext.referenceFunctions(SerialEntityNames.ARRAY_MASK_FIELD_MISSING_FUNC_FQ).singleOrNull()

private val enumSerializerFactoryFunc
get() = compilerContext.referenceFunctions(SerialEntityNames.ENUM_SERIALIZER_FACTORY_FUNC_FQ).singleOrNull()

private val markedEnumSerializerFactoryFunc
get() = compilerContext.referenceFunctions(SerialEntityNames.MARKED_ENUM_SERIALIZER_FACTORY_FUNC_FQ).singleOrNull()

private inline fun <reified T : IrDeclaration> IrClass.searchForDeclaration(descriptor: DeclarationDescriptor): T? {
return declarations.singleOrNull { it.descriptor == descriptor } as? T
}
Expand Down Expand Up @@ -1041,13 +1047,55 @@ interface IrBuilderExtension {
}
enumSerializerId -> {
serializerClass = module.getClassFromInternalSerializationPackage(SpecialBuiltins.enumSerializer)
args = kType.toClassDescriptor!!.let { enumDesc ->
listOf(
irString(enumDesc.serialName()),
irCall(findEnumValuesMethod(enumDesc))
)
}
val enumDescriptor = kType.toClassDescriptor!!
typeArgs = listOf(thisIrType)
// instantiate serializer only inside enum Companion
if (enclosingGenerator !is SerializableCompanionIrGenerator) {
// otherwise call Companion.serializer()
callSerializerFromCompanion(thisIrType, typeArgs, emptyList())?.let { return it }
}

val enumArgs = mutableListOf(
irString(enumDescriptor.serialName()),
irCall(findEnumValuesMethod(enumDescriptor)),
)

val enumSerializerFactoryFunc = enumSerializerFactoryFunc
val markedEnumSerializerFactoryFunc = markedEnumSerializerFactoryFunc
if (enumSerializerFactoryFunc != null && markedEnumSerializerFactoryFunc != null) {
// runtime contains enum serializer factory functions
val factoryFunc: IrSimpleFunctionSymbol = if (enumDescriptor.isEnumWithSerialInfoAnnotation()) {
// need to store SerialInfo annotation in descriptor
val enumEntries = enumDescriptor.enumEntries()
val entriesNames = enumEntries.map { it.annotations.serialNameValue?.let { n -> irString(n) } ?: irNull() }
val entriesAnnotations = enumEntries.map {
val annotationConstructors = it.annotations.mapNotNull { a ->
compilerContext.typeTranslator.constantValueGenerator.generateAnnotationConstructorCall(a)
}
val annotationsConstructors = copyAnnotationsFrom(annotationConstructors)
if (annotationsConstructors.isEmpty()) {
irNull()
} else {
createArrayOfExpression(compilerContext.irBuiltIns.annotationType, annotationsConstructors)
}
}
val annotationArrayType =
compilerContext.irBuiltIns.arrayClass.typeWith(compilerContext.irBuiltIns.annotationType.makeNullable())

enumArgs += createArrayOfExpression(compilerContext.irBuiltIns.stringType.makeNullable(), entriesNames)
enumArgs += createArrayOfExpression(annotationArrayType, entriesAnnotations)

markedEnumSerializerFactoryFunc
} else {
enumSerializerFactoryFunc
}

val factoryReturnType = factoryFunc.owner.returnType.substitute(factoryFunc.owner.typeParameters, typeArgs)
return irInvoke(null, factoryFunc, typeArgs, enumArgs, factoryReturnType)
} else {
// support legacy serializer instantiation by constructor for old runtimes
args = enumArgs
}
}
else -> {
args = kType.arguments.map {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ open class SerializerIrGenerator(
) {
val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return
val generator = when {
serializableDesc.isInternallySerializableEnum() -> SerializerForEnumsGenerator(irClass, context, bindingContext, serialInfoJvmGenerator)
serializableDesc.isEnumWithLegacyGeneratedSerializer() -> SerializerForEnumsGenerator(irClass, context, bindingContext, serialInfoJvmGenerator)
serializableDesc.isInlineClass() -> SerializerForInlineClassGenerator(irClass, context, bindingContext, serialInfoJvmGenerator)
else -> SerializerIrGenerator(irClass, context, bindingContext, metadataPlugin, serialInfoJvmGenerator)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.expression.ExpressionVisitor
import org.jetbrains.kotlin.js.translate.expression.translateAndAliasParameters
import org.jetbrains.kotlin.js.translate.general.Translation
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.psi.KtExpression
Expand Down Expand Up @@ -165,18 +166,65 @@ internal fun AbstractSerialGenerator.serializerInstance(
serializerClass.classId == contextSerializerId || serializerClass.classId == polymorphicSerializerId -> listOf(
ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!)
)
serializerClass.classId == enumSerializerId -> listOf(
JsStringLiteral(kType.serialName()),
// EnumClass.values() invocation
JsInvocation(
context.getInnerNameForDescriptor(
DescriptorUtils.getFunctionByName(
kType.toClassDescriptor!!.staticScope,
StandardNames.ENUM_VALUES
)
).makeRef()
serializerClass.classId == enumSerializerId -> {
val enumDescriptor = kType.toClassDescriptor!!

val enumArgs = mutableListOf(
JsStringLiteral(enumDescriptor.serialName()),
// EnumClass.values() invocation
JsInvocation(
context.getInnerNameForDescriptor(
DescriptorUtils.getFunctionByName(
enumDescriptor.staticScope,
StandardNames.ENUM_VALUES
)
).makeRef()
)
)
)

val packageScope = context.currentModule.getPackage(SerializationPackages.internalPackageFqName).memberScope
val enumSerializerFactoryFunc = DescriptorUtils.getFunctionByNameOrNull(
packageScope,
SerialEntityNames.ENUM_SERIALIZER_FACTORY_FUNC_NAME
)
val markedEnumSerializerFactoryFunc = DescriptorUtils.getFunctionByNameOrNull(
packageScope,
SerialEntityNames.MARKED_ENUM_SERIALIZER_FACTORY_FUNC_NAME
)
if (enumSerializerFactoryFunc != null && markedEnumSerializerFactoryFunc != null) {
// runtime contains enum serializer factory functions
val factoryFunc = if (enumDescriptor.isEnumWithSerialInfoAnnotation()) {
val enumEntries = enumDescriptor.enumEntries()
val entriesNames =
enumEntries.map { it.annotations.serialNameValue?.let { n -> JsStringLiteral(n) } ?: JsNullLiteral() }

val entriesAnnotations = enumEntries.map {
val annotationsConstructors = it.annotationsWithArguments().map { (annotationClass, args, _) ->
val argExprs = args.map { arg ->
Translation.translateAsExpression(arg.getArgumentExpression()!!, context)
}
val classRef = context.translateQualifiedReference(annotationClass)
JsNew(classRef, argExprs)
}

if (annotationsConstructors.isEmpty()) {
JsNullLiteral()
} else {
JsArrayLiteral(annotationsConstructors)
}
}
enumArgs += JsArrayLiteral(entriesNames)
enumArgs += JsArrayLiteral(entriesAnnotations)
markedEnumSerializerFactoryFunc
} else {
enumSerializerFactoryFunc
}
return JsInvocation(context.getInnerReference(factoryFunc), enumArgs)
} else {
// support legacy serializer instantiation by constructor for old runtimes
enumArgs
}
}
serializerClass.classId == objectSerializerId -> listOf(
JsStringLiteral(kType.serialName()),
context.serializerObjectGetter(kType.toClassDescriptor!!)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ open class SerializerJsTranslator(
metadataPlugin: SerializationDescriptorSerializerPlugin?
) {
val serializableDesc = getSerializableClassDescriptorBySerializer(descriptor) ?: return
if (serializableDesc.isInternallySerializableEnum()) {
if (serializableDesc.isEnumWithLegacyGeneratedSerializer()) {
SerializerForEnumsTranslator(descriptor, translator, context).generate()
} else {
SerializerJsTranslator(descriptor, translator, context, metadataPlugin).generate()
Expand Down

0 comments on commit ec6a8aa

Please sign in to comment.