From dba6396e95ee20f6f5f15334220c59726ff2f60b Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Fri, 12 Oct 2018 17:26:35 +0300 Subject: [PATCH] Support enums according to new design --- .../compiler/backend/ir/GeneratorHelpers.kt | 59 ++++++++++++++----- .../backend/ir/SerializerIrGenerator.kt | 3 +- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt index 5b90ba16155..c40c96d2d81 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt @@ -107,7 +107,6 @@ interface IrBuilderExtension { } fun IrBuilderWithScope.createArrayOfExpression( - resultingType: IrType, arrayElementType: IrType, arrayElements: List ): IrExpression { @@ -116,7 +115,7 @@ interface IrBuilderExtension { val arg0 = IrVarargImpl(startOffset, endOffset, arrayType, arrayElementType, arrayElements) val typeArguments = listOf(arrayElementType) - return irCall(compilerContext.ir.symbols.arrayOf, resultingType, typeArguments = typeArguments).apply { + return irCall(compilerContext.ir.symbols.arrayOf, arrayType, typeArguments = typeArguments).apply { putValueArgument(0, arg0) } } @@ -381,6 +380,21 @@ interface IrBuilderExtension { ) } + fun findEnumValuesMethod(enumClass: ClassDescriptor): IrFunction { + assert(enumClass.kind == ClassKind.ENUM_CLASS) + return compilerContext.externalSymbols.referenceClass(enumClass).owner.functions + .find { it.origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER && it.name == Name.identifier("values") } + ?: throw AssertionError("Enum class does not have .values() function") + } + + private fun getEnumMembersNames(enumClass: ClassDescriptor): Sequence { + assert(enumClass.kind == ClassKind.ENUM_CLASS) + return enumClass.unsubstitutedMemberScope.getContributedDescriptors().asSequence() + .filterIsInstance() + .filter { it.kind == ClassKind.ENUM_ENTRY } + .map { it.name.toString() } + } + // Does not use sti and therefore does not perform encoder calls optimization fun IrBuilderWithScope.serializerTower(generator: SerializerIrGenerator, property: SerializableProperty): IrExpression? { val nullableSerClass = @@ -400,33 +414,48 @@ interface IrBuilderExtension { fun IrBuilderWithScope.serializerInstance( enclosingGenerator: SerializerIrGenerator, serializableDescriptor: ClassDescriptor, - serializerClass: ClassDescriptor?, + serializerClassOriginal: ClassDescriptor?, module: ModuleDescriptor, kType: KotlinType, genericIndex: Int? = null ): IrExpression? { val nullableSerClass = compilerContext.externalSymbols.referenceClass(module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer)) - if (serializerClass == null) { + if (serializerClassOriginal == null) { if (genericIndex == null) return null val thiz = enclosingGenerator.irClass.thisReceiver!! val prop = enclosingGenerator.localSerializersFieldsDescriptors[genericIndex] return irGetField(irGet(thiz), compilerContext.localSymbolTable.referenceField(prop).owner) } - if (serializerClass.kind == ClassKind.OBJECT) { - return irGetObject(serializerClass) + if (serializerClassOriginal.kind == ClassKind.OBJECT) { + return irGetObject(serializerClassOriginal) } else { - // todo: special instantiation of enum serializer according to new design - var args = if (serializerClass.classId == enumSerializerId || serializerClass.classId == contextSerializerId) - listOf(classReference(kType)) - else kType.arguments.map { - val argSer = enclosingGenerator.findTypeSerializerOrContext(module, it.type, sourceElement = serializerClass.findPsi()) - val expr = serializerInstance(enclosingGenerator, serializableDescriptor, argSer, module, it.type, it.type.genericIndex) - ?: return null - if (it.type.isMarkedNullable) irInvoke(null, nullableSerClass.constructors.toList()[0], expr) else expr + var serializerClass = serializerClassOriginal + var args: List = when (serializerClassOriginal.classId) { + contextSerializerId -> listOf(classReference(kType)) + enumSerializerId -> { + serializerClass = serializableDescriptor.getClassFromInternalSerializationPackage("CommonEnumSerializer") + kType.toClassDescriptor!!.let { enumDesc -> + listOf( + irString(enumDesc.name.toString()), + irCall(findEnumValuesMethod(enumDesc)), + createArrayOfExpression( + compilerContext.irBuiltIns.stringType, + getEnumMembersNames(enumDesc).map { irString(it) }.toList() + ) + ) + } + } + else -> kType.arguments.map { + val argSer = enclosingGenerator.findTypeSerializerOrContext(module, it.type, sourceElement = serializerClassOriginal.findPsi()) + val expr = serializerInstance(enclosingGenerator, serializableDescriptor, argSer, module, it.type, it.type.genericIndex) + ?: return null + if (it.type.isMarkedNullable) irInvoke(null, nullableSerClass.constructors.toList()[0], expr) else expr + } } - if (serializerClass.classId == referenceArraySerializerId) + if (serializerClassOriginal.classId == referenceArraySerializerId) args = listOf(classReference(kType.arguments[0].type)) + args + val serializable = getSerializableClassDescriptorBySerializer(serializerClass) val ctor = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) { requireNotNull( diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt index e01cecaa7e0..9502771b3c7 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt @@ -142,10 +142,9 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext: serializerTower(this@SerializerIrGenerator, it)) { "Property ${it.name} must have a serializer" } } - val arrayOfKSerType = irFun.returnType val kSer = serializableDescriptor.module.getClassFromSerializationPackage(KSERIALIZER_NAME.identifier) val kSerType = compilerContext.externalSymbols.referenceClass(kSer).owner.defaultType - val array = createArrayOfExpression(arrayOfKSerType, kSerType, allSerializers) + val array = createArrayOfExpression(kSerType, allSerializers) +irReturn(array) }