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.makeNotNullable
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
import org.jetbrains.kotlinx.serialization.compiler.backend.common.AbstractSerialGenerator
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.common.*
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.*
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
@@ -567,118 +564,145 @@ interface IrBuilderExtension {
}
if (serializerClassOriginal.kind == ClassKind.OBJECT) {
return irGetObject(serializerClassOriginal)
} else {
fun instantiate(serializer: ClassDescriptor?, type: KotlinType): IrExpression? {
val expr = serializerInstance(
enclosingGenerator,
serializer,
module,
type,
type.genericIndex,
genericGetter
) ?: return null
return wrapWithNullableSerializerIfNeeded(module, type, expr, nullableSerClass)
}
var serializerClass = serializerClassOriginal
var args: List<IrExpression>
var typeArgs: List<IrType?>
val thisIrType = kType.toIrType()
when (serializerClassOriginal.classId) {
contextSerializerId, polymorphicSerializerId -> {
args = listOf(classReference(kType))
typeArgs = listOf(thisIrType)
}
objectSerializerId -> {
args = listOf(irString(kType.serialName()), irGetObject(kType.toClassDescriptor!!))
typeArgs = listOf(thisIrType)
}
sealedSerializerId -> {
args = mutableListOf<IrExpression>().apply {
add(irString(kType.serialName()))
add(classReference(kType))
val (subclasses, subSerializers) = enclosingGenerator.allSealedSerializableSubclassesFor(
kType.toClassDescriptor!!,
module
)
val projectedOutCurrentKClass = kClassTypeFor(TypeProjectionImpl(Variance.OUT_VARIANCE, kType))
add(
createArrayOfExpression(
projectedOutCurrentKClass.toIrType(),
subclasses.map { classReference(it) }
)
)
add(
createArrayOfExpression(
wrapIrTypeIntoKSerializerIrType(module, thisIrType, variance = Variance.OUT_VARIANCE),
subSerializers.mapIndexed { i, serializer ->
val type = subclasses[i]
val expr = serializerInstance(
enclosingGenerator,
serializer,
module,
type,
type.genericIndex
) { _, genericType ->
serializerInstance(
enclosingGenerator,
module.getClassFromSerializationPackage(
SpecialBuiltins.polymorphicSerializer
),
module,
(genericType.constructor.declarationDescriptor as TypeParameterDescriptor).representativeUpperBound
)!!
}!!
wrapWithNullableSerializerIfNeeded(module, type, expr, nullableSerClass)
}
)
)
}
typeArgs = listOf(thisIrType)
}
enumSerializerId -> {
serializerClass = module.getClassFromInternalSerializationPackage(SpecialBuiltins.enumSerializer)
args = kType.toClassDescriptor!!.let { enumDesc ->
listOf(
irString(enumDesc.serialName()),
irCall(findEnumValuesMethod(enumDesc))
)
}
typeArgs = listOf(thisIrType)
}
else -> {
args = kType.arguments.map {
val argSer = enclosingGenerator.findTypeSerializerOrContext(
module,
it.type,
sourceElement = serializerClassOriginal.findPsi()
)
instantiate(argSer, it.type) ?: return null
}
typeArgs = kType.arguments.map { it.type.toIrType() }
}
}
if (serializerClassOriginal.classId == referenceArraySerializerId) {
args = listOf(classReference(kType.arguments[0].type)) + args
typeArgs = listOf(typeArgs[0].makeNotNull()) + typeArgs
}
val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
val ctor = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
requireNotNull(
findSerializerConstructorForTypeArgumentsSerializers(serializerClass)
) { "Generated serializer does not have constructor with required number of arguments" }
} else {
compilerContext.referenceConstructors(serializerClass.fqNameSafe).single { it.owner.isPrimary }
}
// Return type should be correctly substituted
assert(ctor.isBound)
val ctorDecl = ctor.owner
val typeParameters = ctorDecl.parentAsClass.typeParameters
val substitutedReturnType = ctorDecl.returnType.substitute(typeParameters, typeArgs)
return irInvoke(null, ctor, typeArguments = typeArgs, valueArguments = args, returnTypeHint = substitutedReturnType)
}
fun instantiate(serializer: ClassDescriptor?, type: KotlinType): IrExpression? {
val expr = serializerInstance(
enclosingGenerator,
serializer,
module,
type,
type.genericIndex,
genericGetter
) ?: return null
return wrapWithNullableSerializerIfNeeded(module, type, expr, nullableSerClass)
}
var serializerClass = serializerClassOriginal
var args: List<IrExpression>
var typeArgs: List<IrType?>
val thisIrType = kType.toIrType()
val hasNewCtxSerCtor =
serializerClassOriginal.classId == contextSerializerId && compilerContext.referenceConstructors(serializerClass.fqNameSafe)
.any { it.owner.valueParameters.size == 3 }
when (serializerClassOriginal.classId) {
contextSerializerId, polymorphicSerializerId -> {
args = listOf(classReference(kType))
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 -> {
args = listOf(irString(kType.serialName()), irGetObject(kType.toClassDescriptor!!))
typeArgs = listOf(thisIrType)
}
sealedSerializerId -> {
args = mutableListOf<IrExpression>().apply {
add(irString(kType.serialName()))
add(classReference(kType))
val (subclasses, subSerializers) = enclosingGenerator.allSealedSerializableSubclassesFor(
kType.toClassDescriptor!!,
module
)
val projectedOutCurrentKClass = kClassTypeFor(TypeProjectionImpl(Variance.OUT_VARIANCE, kType))
add(
createArrayOfExpression(
projectedOutCurrentKClass.toIrType(),
subclasses.map { classReference(it) }
)
)
add(
createArrayOfExpression(
wrapIrTypeIntoKSerializerIrType(module, thisIrType, variance = Variance.OUT_VARIANCE),
subSerializers.mapIndexed { i, serializer ->
val type = subclasses[i]
val expr = serializerInstance(
enclosingGenerator,
serializer,
module,
type,
type.genericIndex
) { _, genericType ->
serializerInstance(
enclosingGenerator,
module.getClassFromSerializationPackage(
SpecialBuiltins.polymorphicSerializer
),
module,
(genericType.constructor.declarationDescriptor as TypeParameterDescriptor).representativeUpperBound
)!!
}!!
wrapWithNullableSerializerIfNeeded(module, type, expr, nullableSerClass)
}
)
)
}
typeArgs = listOf(thisIrType)
}
enumSerializerId -> {
serializerClass = module.getClassFromInternalSerializationPackage(SpecialBuiltins.enumSerializer)
args = kType.toClassDescriptor!!.let { enumDesc ->
listOf(
irString(enumDesc.serialName()),
irCall(findEnumValuesMethod(enumDesc))
)
}
typeArgs = listOf(thisIrType)
}
else -> {
args = kType.arguments.map {
val argSer = enclosingGenerator.findTypeSerializerOrContext(
module,
it.type,
sourceElement = serializerClassOriginal.findPsi()
)
instantiate(argSer, it.type) ?: return null
}
typeArgs = kType.arguments.map { it.type.toIrType() }
}
}
if (serializerClassOriginal.classId == referenceArraySerializerId) {
args = listOf(classReference(kType.arguments[0].type)) + args
typeArgs = listOf(typeArgs[0].makeNotNull()) + typeArgs
}
val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
val ctor = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
requireNotNull(
findSerializerConstructorForTypeArgumentsSerializers(serializerClass)
) { "Generated serializer does not have constructor with required number of arguments" }
} else {
compilerContext.referenceConstructors(serializerClass.fqNameSafe).single { it.owner.isPrimary }
}
// Return type should be correctly substituted
assert(ctor.isBound)
val ctorDecl = ctor.owner
val typeParameters = ctorDecl.parentAsClass.typeParameters
val substitutedReturnType = ctorDecl.returnType.substitute(typeParameters, typeArgs)
return irInvoke(null, ctor, typeArguments = typeArgs, valueArguments = args, returnTypeHint = substitutedReturnType)
}
private fun findSerializerConstructorForTypeArgumentsSerializers(serializer: ClassDescriptor): IrConstructorSymbol? {
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.
* 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.
*/
package org.jetbrains.kotlinx.serialization.compiler.backend.js
@@ -151,78 +140,92 @@ internal fun AbstractSerialGenerator.serializerInstance(
}
if (serializerClass.kind == ClassKind.OBJECT) {
return context.serializerObjectGetter(serializerClass)
} else {
fun instantiate(serializer: ClassDescriptor?, type: KotlinType): JsExpression? {
val expr = serializerInstance(context, serializer, module, type, type.genericIndex, genericGetter) ?: return null
return if (type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr
}
var args = when {
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,
DescriptorUtils.ENUM_VALUES
)
).makeRef()
)
)
serializerClass.classId == objectSerializerId -> listOf(
JsStringLiteral(kType.serialName()),
context.serializerObjectGetter(kType.toClassDescriptor!!)
)
serializerClass.classId == sealedSerializerId -> mutableListOf<JsExpression>().apply {
add(JsStringLiteral(kType.serialName()))
add(ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!))
val (subclasses, subSerializers) = allSealedSerializableSubclassesFor(
kType.toClassDescriptor!!,
module
)
add(JsArrayLiteral(subclasses.map {
ExpressionVisitor.getObjectKClass(
context,
it.toClassDescriptor!!
)
}))
add(JsArrayLiteral(subSerializers.mapIndexed { i, serializer ->
val type = subclasses[i]
val expr = serializerInstance(context, serializer, module, type, type.genericIndex) { _, genericType ->
serializerInstance(
context,
module.getClassFromSerializationPackage(SpecialBuiltins.polymorphicSerializer),
module,
(genericType.constructor.declarationDescriptor as TypeParameterDescriptor).representativeUpperBound
)!!
}!!
if (type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr
}))
}
else -> kType.arguments.map {
val argSer = findTypeSerializerOrContext(module, it.type, sourceElement = serializerClass.findPsi())
instantiate(argSer, it.type) ?: return null
}
}
if (serializerClass.classId == referenceArraySerializerId)
args = listOf(ExpressionVisitor.getObjectKClass(context, kType.arguments[0].type.toClassDescriptor!!)) + args
val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
val ref = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
val desc = requireNotNull(
findSerializerConstructorForTypeArgumentsSerializers(serializerClass)
) { "Generated serializer does not have constructor with required number of arguments" }
if (!desc.isPrimary)
JsInvocation(context.getInnerReference(desc), args)
else
JsNew(context.getInnerReference(desc), args)
} else {
JsNew(context.translateQualifiedReference(serializerClass), args)
}
return ref
}
val hasNewCtxSerCtor =
serializerClass.classId == contextSerializerId && serializerClass.constructors.any { it.valueParameters.size == 3 }
fun instantiate(serializer: ClassDescriptor?, type: KotlinType): JsExpression? {
val expr = serializerInstance(context, serializer, module, type, type.genericIndex, genericGetter) ?: return null
return if (type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr
}
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(
ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!)
)
serializerClass.classId == enumSerializerId -> listOf(
JsStringLiteral(kType.serialName()),
// EnumClass.values() invocation
JsInvocation(
context.getInnerNameForDescriptor(
DescriptorUtils.getFunctionByName(
kType.toClassDescriptor!!.staticScope,
DescriptorUtils.ENUM_VALUES
)
).makeRef()
)
)
serializerClass.classId == objectSerializerId -> listOf(
JsStringLiteral(kType.serialName()),
context.serializerObjectGetter(kType.toClassDescriptor!!)
)
serializerClass.classId == sealedSerializerId -> mutableListOf<JsExpression>().apply {
add(JsStringLiteral(kType.serialName()))
add(ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!))
val (subclasses, subSerializers) = allSealedSerializableSubclassesFor(
kType.toClassDescriptor!!,
module
)
add(JsArrayLiteral(subclasses.map {
ExpressionVisitor.getObjectKClass(
context,
it.toClassDescriptor!!
)
}))
add(JsArrayLiteral(subSerializers.mapIndexed { i, serializer ->
val type = subclasses[i]
val expr = serializerInstance(context, serializer, module, type, type.genericIndex) { _, genericType ->
serializerInstance(
context,
module.getClassFromSerializationPackage(SpecialBuiltins.polymorphicSerializer),
module,
(genericType.constructor.declarationDescriptor as TypeParameterDescriptor).representativeUpperBound
)!!
}!!
if (type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr
}))
}
else -> kType.arguments.map {
val argSer = findTypeSerializerOrContext(module, it.type, sourceElement = serializerClass.findPsi())
instantiate(argSer, it.type) ?: return null
}
}
if (serializerClass.classId == referenceArraySerializerId)
args = listOf(ExpressionVisitor.getObjectKClass(context, kType.arguments[0].type.toClassDescriptor!!)) + args
val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
val ref = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
val desc = requireNotNull(
findSerializerConstructorForTypeArgumentsSerializers(serializerClass)
) { "Generated serializer does not have constructor with required number of arguments" }
if (!desc.isPrimary)
JsInvocation(context.getInnerReference(desc), args)
else
JsNew(context.getInnerReference(desc), args)
} else {
JsNew(context.translateQualifiedReference(serializerClass), args)
}
return ref
}
fun TranslationContext.buildInitializersRemapping(
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.
* 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.
*/
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))
AsmUtil.wrapJavaClassIntoKClass(this)
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 -> {
// a special way to instantiate reference array serializer -- need an element KClass reference