From 66272bfa74309f0c4f5c6086d600cb948ca16b8c Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Tue, 12 Feb 2019 14:38:24 +0300 Subject: [PATCH] Fix impossibility to make @Optional field in a class hierarchy on JS --- .../compiler/backend/js/JsCodegenUtil.kt | 13 ++++++++--- .../backend/js/SerializableJsTranslator.kt | 3 ++- .../backend/js/SerializerJsTranslator.kt | 22 +++++++++++-------- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/JsCodegenUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/JsCodegenUtil.kt index 7d4436c27e0..c592c076f67 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/JsCodegenUtil.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/JsCodegenUtil.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.js.translate.utils.JsAstUtils import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtPureClassOrObject import org.jetbrains.kotlin.resolve.descriptorUtil.classId +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlinx.serialization.compiler.backend.common.bodyPropertiesDescriptorsMap @@ -172,7 +173,13 @@ internal fun SerializerJsTranslator.serializerInstance( } } -fun TranslationContext.buildInitializersRemapping(forClass: KtPureClassOrObject): Map = forClass.run { - (bodyPropertiesDescriptorsMap(bindingContext()).mapValues { it.value.delegateExpressionOrInitializer } + - primaryPropertiesDescriptorsMap(bindingContext()).mapValues { it.value.defaultValue }) +fun TranslationContext.buildInitializersRemapping( + forClass: KtPureClassOrObject, + superClass: ClassDescriptor? +): Map { + val myMap = (forClass.bodyPropertiesDescriptorsMap(bindingContext()).mapValues { it.value.delegateExpressionOrInitializer } + + forClass.primaryPropertiesDescriptorsMap(bindingContext()).mapValues { it.value.defaultValue }) + val parentPsi = superClass?.takeIf { it.isInternalSerializable }?.findPsi() as? KtPureClassOrObject ?: return myMap + val parentMap = buildInitializersRemapping(parentPsi, superClass.getSuperClassNotAny()) + return myMap + parentMap } \ No newline at end of file diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableJsTranslator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableJsTranslator.kt index 6f0bd173d63..9897aabc98a 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableJsTranslator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableJsTranslator.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.js.translate.utils.JsAstUtils import org.jetbrains.kotlin.js.translate.utils.TranslationUtils import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtPureClassOrObject +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.anonymousInitializers @@ -44,7 +45,7 @@ class SerializableJsTranslator( val context: TranslationContext ) : SerializableCodegen(descriptor, context.bindingContext()) { - private val initMap: Map = context.buildInitializersRemapping(declaration) + private val initMap: Map = context.buildInitializersRemapping(declaration, descriptor.getSuperClassNotAny()) override fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor) { diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt index 4ec18401aff..03bbfcda72d 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils import org.jetbrains.kotlin.js.translate.utils.TranslationUtils import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtPureClassOrObject +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.types.typeUtil.builtIns import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo @@ -131,26 +132,29 @@ class SerializerJsTranslator(descriptor: ClassDescriptor, } private fun TranslationContext.referenceMethod(clazz: ClassDescriptor, name: String) = - clazz.getFuncDesc(name).single().let { getNameForDescriptor(it) } + getNameForDescriptor(clazz.getFuncDesc(name).single()) override fun generateSave(function: FunctionDescriptor) = generateFunction(function) { jsFun, ctx -> val encoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.ENCODER_CLASS) val kOutputClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.STRUCTURE_ENCODER_CLASS) val wBeginFunc = ctx.getNameForDescriptor( - encoderClass.getFuncDesc(CallingConventions.begin).single { it.valueParameters.size == 2 }) + encoderClass.getFuncDesc(CallingConventions.begin).single { it.valueParameters.size == 2 }) val serialClassDescRef = JsNameRef(context.getNameForDescriptor(anySerialDescProperty!!), JsThisRef()) - val initializersMap: Map = context.buildInitializersRemapping( - (serializableDescriptor.findPsi() as? KtPureClassOrObject) - ?: throw AssertionError("Serializable descriptor $serializableDescriptor must have source file to build initializers map") - ) + + val serializableSource = ((serializableDescriptor.findPsi() as? KtPureClassOrObject) + ?: throw AssertionError("Serializable descriptor $serializableDescriptor must have source file to build initializers map")) + val initializersMap: Map = + context.buildInitializersRemapping(serializableSource, serializableDescriptor.getSuperClassNotAny()) // output.writeBegin(desc, []) val typeParams = serializableDescriptor.declaredTypeParameters.mapIndexed { idx, _ -> JsNameRef(context.scope().declareName("$typeArgPrefix$idx"), JsThisRef()) } - val call = JsInvocation(JsNameRef(wBeginFunc, JsNameRef(jsFun.parameters[0].name)), - serialClassDescRef, - JsArrayLiteral(typeParams)) + val call = JsInvocation( + JsNameRef(wBeginFunc, JsNameRef(jsFun.parameters[0].name)), + serialClassDescRef, + JsArrayLiteral(typeParams) + ) val objRef = JsNameRef(jsFun.parameters[1].name) // output = output.writeBegin... val localOutputName = jsFun.scope.declareFreshName("output")