Support new ContextSerializer signature

This commit is contained in:
Leonid Startsev
2020-06-18 15:11:17 +03:00
parent 7ea1700b78
commit 5208bbcd21
3 changed files with 242 additions and 212 deletions
@@ -29,10 +29,7 @@ import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
import org.jetbrains.kotlinx.serialization.compiler.backend.common.AbstractSerialGenerator import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
import org.jetbrains.kotlinx.serialization.compiler.backend.common.allSealedSerializableSubclassesFor
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
import org.jetbrains.kotlinx.serialization.compiler.backend.common.serialName
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.* import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.*
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.*
@@ -567,7 +564,7 @@ interface IrBuilderExtension {
} }
if (serializerClassOriginal.kind == ClassKind.OBJECT) { if (serializerClassOriginal.kind == ClassKind.OBJECT) {
return irGetObject(serializerClassOriginal) return irGetObject(serializerClassOriginal)
} else { }
fun instantiate(serializer: ClassDescriptor?, type: KotlinType): IrExpression? { fun instantiate(serializer: ClassDescriptor?, type: KotlinType): IrExpression? {
val expr = serializerInstance( val expr = serializerInstance(
enclosingGenerator, enclosingGenerator,
@@ -579,14 +576,42 @@ interface IrBuilderExtension {
) ?: return null ) ?: return null
return wrapWithNullableSerializerIfNeeded(module, type, expr, nullableSerClass) return wrapWithNullableSerializerIfNeeded(module, type, expr, nullableSerClass)
} }
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.toIrType()
val hasNewCtxSerCtor =
serializerClassOriginal.classId == contextSerializerId && compilerContext.referenceConstructors(serializerClass.fqNameSafe)
.any { it.owner.valueParameters.size == 3 }
when (serializerClassOriginal.classId) { when (serializerClassOriginal.classId) {
contextSerializerId, polymorphicSerializerId -> { contextSerializerId, polymorphicSerializerId -> {
args = listOf(classReference(kType)) args = listOf(classReference(kType))
typeArgs = listOf(thisIrType) typeArgs = listOf(thisIrType)
if (hasNewCtxSerCtor) {
// new signature of context serializer
args = args + mutableListOf<IrExpression>().apply {
val fallbackDefaultSerializer = findTypeSerializer(module, kType)
add(instantiate(fallbackDefaultSerializer, kType) ?: irNull())
add(
createArrayOfExpression(
wrapIrTypeIntoKSerializerIrType(
module,
thisIrType,
variance = Variance.OUT_VARIANCE
),
kType.arguments.map {
val argSer = enclosingGenerator.findTypeSerializerOrContext(
module,
it.type,
sourceElement = serializerClassOriginal.findPsi()
)
instantiate(argSer, it.type)!!
})
)
}
}
} }
objectSerializerId -> { objectSerializerId -> {
args = listOf(irString(kType.serialName()), irGetObject(kType.toClassDescriptor!!)) args = listOf(irString(kType.serialName()), irGetObject(kType.toClassDescriptor!!))
@@ -679,7 +704,6 @@ interface IrBuilderExtension {
val substitutedReturnType = ctorDecl.returnType.substitute(typeParameters, typeArgs) val substitutedReturnType = ctorDecl.returnType.substitute(typeParameters, typeArgs)
return irInvoke(null, ctor, typeArguments = typeArgs, valueArguments = args, returnTypeHint = substitutedReturnType) return irInvoke(null, ctor, typeArguments = typeArgs, valueArguments = args, returnTypeHint = substitutedReturnType)
} }
}
private fun findSerializerConstructorForTypeArgumentsSerializers(serializer: ClassDescriptor): IrConstructorSymbol? { private fun findSerializerConstructorForTypeArgumentsSerializers(serializer: ClassDescriptor): IrConstructorSymbol? {
val serializableImplementationTypeArguments = extractKSerializerArgumentFromImplementation(serializer)?.arguments val serializableImplementationTypeArguments = extractKSerializerArgumentFromImplementation(serializer)?.arguments
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2010-2020 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.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ */
package org.jetbrains.kotlinx.serialization.compiler.backend.js package org.jetbrains.kotlinx.serialization.compiler.backend.js
@@ -151,12 +140,27 @@ internal fun AbstractSerialGenerator.serializerInstance(
} }
if (serializerClass.kind == ClassKind.OBJECT) { if (serializerClass.kind == ClassKind.OBJECT) {
return context.serializerObjectGetter(serializerClass) return context.serializerObjectGetter(serializerClass)
} else { }
val hasNewCtxSerCtor =
serializerClass.classId == contextSerializerId && serializerClass.constructors.any { it.valueParameters.size == 3 }
fun instantiate(serializer: ClassDescriptor?, type: KotlinType): JsExpression? { fun instantiate(serializer: ClassDescriptor?, type: KotlinType): JsExpression? {
val expr = serializerInstance(context, serializer, module, type, type.genericIndex, genericGetter) ?: return null val expr = serializerInstance(context, serializer, module, type, type.genericIndex, genericGetter) ?: return null
return if (type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr return if (type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr
} }
var args = when { var args = when {
hasNewCtxSerCtor -> {
mutableListOf<JsExpression>().apply {
add(ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!))
val fallbackDefaultSerializer = findTypeSerializer(module, kType)
add(instantiate(fallbackDefaultSerializer, kType) ?: JsNullLiteral())
add(JsArrayLiteral(kType.arguments.map {
val argSer = findTypeSerializerOrContext(module, it.type, sourceElement = serializerClass.findPsi())
instantiate(argSer, it.type)!!
}))
}
}
serializerClass.classId == contextSerializerId || serializerClass.classId == polymorphicSerializerId -> listOf( serializerClass.classId == contextSerializerId || serializerClass.classId == polymorphicSerializerId -> listOf(
ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!) ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!)
) )
@@ -223,7 +227,6 @@ internal fun AbstractSerialGenerator.serializerInstance(
} }
return ref return ref
} }
}
fun TranslationContext.buildInitializersRemapping( fun TranslationContext.buildInitializersRemapping(
forClass: KtPureClassOrObject, forClass: KtPureClassOrObject,
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2010-2020 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.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ */
package org.jetbrains.kotlinx.serialization.compiler.backend.jvm package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
@@ -302,6 +291,20 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
aconst(codegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT)) aconst(codegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT))
AsmUtil.wrapJavaClassIntoKClass(this) AsmUtil.wrapJavaClassIntoKClass(this)
signature.append(AsmTypes.K_CLASS_TYPE.descriptor) signature.append(AsmTypes.K_CLASS_TYPE.descriptor)
if (serializer.classId == contextSerializerId && serializer.constructors.any { it.valueParameters.size == 3 }) {
// append new additional arguments
val fallbackDefaultSerializer = findTypeSerializer(module, kType)
if (fallbackDefaultSerializer != null) {
instantiate(kType to fallbackDefaultSerializer, writeSignature = false)
} else {
aconst(null)
}
signature.append(kSerializerType.descriptor)
fillArray(kSerializerType, argSerializers) { _, serializer ->
instantiate(serializer, writeSignature = false)
}
signature.append(kSerializerArrayType.descriptor)
}
} }
referenceArraySerializerId -> { referenceArraySerializerId -> {
// a special way to instantiate reference array serializer -- need an element KClass reference // a special way to instantiate reference array serializer -- need an element KClass reference