diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/build.gradle.kts b/plugins/kotlin-serialization/kotlin-serialization-compiler/build.gradle.kts
index d40a79db9b0..45aab860288 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/build.gradle.kts
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/build.gradle.kts
@@ -5,6 +5,7 @@ apply { plugin("kotlin") }
dependencies {
compileOnly(ideaSdkCoreDeps("intellij-core"))
+ compileOnly(project(":jps-plugin"))
compileOnly(project(":compiler:plugin-api"))
compileOnly(project(":compiler:frontend"))
compileOnly(project(":compiler:backend"))
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/plugin.xml b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/plugin.xml
index 47067b63923..c577b332d8d 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/plugin.xml
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/plugin.xml
@@ -1,7 +1,7 @@
Kotlin-serialization
org.jetbrains.kotlinx.serialization
- 0.1-SNAPSHOT
+ 0.2
org.jetbrains.kotlin
@@ -11,4 +11,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/services/org.jetbrains.kotlin.jps.build.KotlinJpsCompilerArgumentsProvider b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/services/org.jetbrains.kotlin.jps.build.KotlinJpsCompilerArgumentsProvider
new file mode 100644
index 00000000000..c44d1917ec1
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/services/org.jetbrains.kotlin.jps.build.KotlinJpsCompilerArgumentsProvider
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+
+org.jetbrains.kotlinx.serialization.jps.KotlinSerializationJpsPlugin
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCompanionCodegen.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCompanionCodegen.kt
new file mode 100644
index 00000000000..b69efb52a8b
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCompanionCodegen.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+package org.jetbrains.kotlinx.serialization.compiler.backend.common
+
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.psi.KtPureClassOrObject
+import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
+import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
+
+abstract class SerializableCompanionCodegen(declaration: KtPureClassOrObject, bindingContext: BindingContext) {
+ protected val companionDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext)
+ protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorByCompanion(companionDescriptor)!!
+
+ fun generate() {
+ val fser = KSerializerDescriptorResolver.createSerializerGetterDescriptor(companionDescriptor, serializableDescriptor)
+ generateSerializerGetter(fser)
+ }
+
+ protected abstract fun generateSerializerGetter(methodDescriptor: FunctionDescriptor)
+}
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt
index e217f52e317..3522211710f 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt
@@ -25,8 +25,8 @@ import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
-import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
+import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties
abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContext: BindingContext) {
@@ -43,12 +43,17 @@ abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContex
val load = generateLoadIfNeeded()
if (save || load || prop)
generateSerialDesc()
+ if (serializableDescriptor.declaredTypeParameters.isNotEmpty()) {
+ generateGenericFieldsAndConstructor(createTypedSerializerConstructorDescriptor(serializerDescriptor, serializableDescriptor))
+ }
}
protected val serialDescPropertyDescriptor = getPropertyToGenerate(serializerDescriptor, KSerializerDescriptorResolver.SERIAL_DESC_FIELD,
serializerDescriptor::checkSerializableClassPropertyResult)
protected abstract fun generateSerialDesc()
+ protected abstract fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ConstructorDescriptor)
+
protected abstract fun generateSerializableClassProperty(property: PropertyDescriptor)
protected abstract fun generateSave(function: FunctionDescriptor)
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt
index b5414c51ca9..767bf5c2e72 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt
@@ -28,9 +28,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationDescriptor
import org.jetbrains.kotlin.types.KotlinType
-import org.jetbrains.kotlin.types.typeUtil.containsTypeProjectionsInTopLevelArguments
-import org.jetbrains.kotlin.types.typeUtil.isBoolean
-import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
+import org.jetbrains.kotlin.types.typeUtil.*
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.polymorphicSerializerId
@@ -47,6 +45,7 @@ open class SerialTypeInfo(
fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
val T = property.type
return when {
+ T.isTypeParameter() -> SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", null)
T.isPrimitiveNumberType() or T.isBoolean() -> SerialTypeInfo(property,
T.nameIfStandardType.toString().capitalize())
KotlinBuiltIns.isString(T) -> SerialTypeInfo(property, "String")
@@ -71,6 +70,7 @@ fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? {
return if (kType.requiresPolymorphism()) findPolymorphicSerializer(module)
+ else if (kType.isTypeParameter()) return null
else kType.typeSerializer.toClassDescriptor // check for serializer defined on the type
?: findStandardKotlinTypeSerializer(module, kType) // otherwise see if there is a standard serializer
?: findEnumTypeSerializer(module, kType)
@@ -89,6 +89,7 @@ fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType
"D", "kotlin.Double" -> "DoubleSerializer"
"C", "kotlin.Char" -> "CharSerializer"
"kotlin.String" -> "StringSerializer"
+ "kotlin.Pair" -> "PairSerializer"
"kotlin.collections.Collection", "kotlin.collections.List", "kotlin.collections.ArrayList" -> "ArrayListSerializer"
"kotlin.collections.Set", "kotlin.collections.LinkedHashSet" -> "LinkedHashSetSerializer"
"kotlin.collections.HashSet" -> "HashSetSerializer"
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableCompanionJsTranslator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableCompanionJsTranslator.kt
new file mode 100644
index 00000000000..aac2cd1337f
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableCompanionJsTranslator.kt
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package org.jetbrains.kotlinx.serialization.compiler.backend.js
+
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.js.backend.ast.JsInvocation
+import org.jetbrains.kotlin.js.backend.ast.JsNameRef
+import org.jetbrains.kotlin.js.backend.ast.JsReturn
+import org.jetbrains.kotlin.js.translate.context.TranslationContext
+import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor
+import org.jetbrains.kotlin.psi.KtPureClassOrObject
+import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
+import org.jetbrains.kotlinx.serialization.compiler.resolve.*
+
+class SerializableCompanionJsTranslator(declaration: KtPureClassOrObject,
+ val translator: DeclarationBodyVisitor,
+ val context: TranslationContext): SerializableCompanionCodegen(declaration, context.bindingContext()) {
+ override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
+ val f = context.buildFunction(methodDescriptor) {jsFun, context ->
+ val serializer = serializableDescriptor.classSerializer?.toClassDescriptor!!
+ val stmt = if (serializableDescriptor.declaredTypeParameters.isEmpty()) {
+ context.getQualifiedReference(serializer)
+ } else {
+ val args = jsFun.parameters.map { JsNameRef(it.name) }
+ val ref = context.getInnerNameForDescriptor(
+ KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializer, serializableDescriptor))
+ JsInvocation(ref.makeRef(), args)
+ }
+ +JsReturn(stmt)
+ }
+ translator.addFunction(methodDescriptor, f, null)
+ }
+
+ companion object {
+ fun translate(declaration: KtPureClassOrObject, descriptor: ClassDescriptor, translator: DeclarationBodyVisitor, context: TranslationContext) {
+ val serializableClass = getSerializableClassDescriptorByCompanion(descriptor) ?: return
+ if (serializableClass.isInternalSerializable)
+ SerializableCompanionJsTranslator(declaration, translator, context).generate()
+ }
+ }
+}
\ No newline at end of file
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 5bb53d9c74b..4e715929db2 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
@@ -19,12 +19,14 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.js
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.js.backend.ast.*
+import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor
import org.jetbrains.kotlin.js.translate.declaration.DefaultPropertyTranslator
import org.jetbrains.kotlin.js.translate.general.Translation
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
+import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
@@ -39,6 +41,7 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerialize
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
+import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.typeArgPrefix
class SerializerJsTranslator(declaration: KtPureClassOrObject,
val translator: DeclarationBodyVisitor,
@@ -94,6 +97,22 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
translator.addProperty(propDesc, getterExpr, null)
}
+ override fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ConstructorDescriptor) {
+ val f = context.buildFunction(typedConstructorDescriptor) { jsFun, context ->
+ val thiz = jsFun.scope.declareName(Namer.ANOTHER_THIS_PARAMETER_NAME).makeRef()
+
+ +JsVars(JsVars.JsVar(thiz.name, JsNew(getQualifiedClassReferenceName(serializerDescriptor))))
+ jsFun.parameters.forEachIndexed { i, parameter ->
+ val thisFRef = JsNameRef(context.scope().declareName("$typeArgPrefix$i"), thiz)
+ +JsAstUtils.assignment(thisFRef, JsNameRef(parameter.name)).makeStmt()
+ }
+ +JsReturn(thiz)
+ }
+
+ f.name = context.getInnerNameForDescriptor(typedConstructorDescriptor);
+ context.addDeclarationStatement(f.makeStmt())
+ }
+
private fun ClassDescriptor.getFuncDesc(funcName: String) =
unsubstitutedMemberScope.getDescriptorsFiltered { it == Name.identifier(funcName) }
@@ -120,7 +139,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
if (property.transient) continue
// output.writeXxxElementValue(classDesc, index, value)
val sti = getSerialTypeInfo(property)
- val innerSerial = if (sti.serializer == null) null else serializerInstance(sti.serializer, property.module, property.type)
+ val innerSerial = serializerInstance(sti.serializer, property.module, property.type, property.genericIndex)
if (innerSerial == null) {
val writeFunc =
kOutputClass.getFuncDesc("write${sti.elementMethodPrefix}ElementValue").single()
@@ -152,9 +171,13 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
return context.getQualifiedReference(classDescriptor)
}
- private fun serializerInstance(serializerClass: ClassDescriptor, module: ModuleDescriptor, kType: KotlinType): JsExpression? {
- val nullableSerClass = getQualifiedClassReferenceName(
- serializerClass.getClassFromInternalSerializationPackage("NullableSerializer"))
+ private fun serializerInstance(serializerClass: ClassDescriptor?, module: ModuleDescriptor, kType: KotlinType, genericIndex: Int? = null): JsExpression? {
+ val nullableSerClass = getQualifiedClassReferenceName(requireNotNull(
+ module.findClassAcrossModuleDependencies(ClassId(internalPackageFqName, Name.identifier("NullableSerializer")))))
+ if (serializerClass == null) {
+ if (genericIndex == null) return null
+ return JsNameRef(context.scope().declareName("$typeArgPrefix$genericIndex"), JsThisRef())
+ }
if (serializerClass.kind == ClassKind.OBJECT) {
return getQualifiedClassReferenceName(serializerClass)
}
@@ -162,13 +185,20 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
var args = if (serializerClass.classId == enumSerializerId || serializerClass.classId == contextSerializerId)
listOf(createGetKClassExpression(kType.toClassDescriptor!!))
else kType.arguments.map {
- val argSer = findTypeSerializer(module, it.type) ?: return null
- val expr = serializerInstance(argSer, module, it.type) ?: return null
+ val argSer = findTypeSerializer(module, it.type)
+ val expr = serializerInstance(argSer, module, it.type, it.type.genericIndex) ?: return null
if (it.type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr
}
if (serializerClass.classId == referenceArraySerializerId)
args = listOf(createGetKClassExpression(kType.arguments[0].type.toClassDescriptor!!)) + args
- return JsNew(getQualifiedClassReferenceName(serializerClass), args)
+ val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
+ val ref = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
+ val desc = KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializerClass, serializableDescriptor)
+ JsInvocation(context.getInnerNameForDescriptor(desc).makeRef(), args)
+ } else {
+ JsNew(getQualifiedClassReferenceName(serializerClass), args)
+ }
+ return ref
}
}
@@ -229,7 +259,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
case(JsIntLiteral(i)) {
// input.readXxxElementValue
val sti = getSerialTypeInfo(property)
- val innerSerial = if (sti.serializer == null) null else serializerInstance(sti.serializer, property.module, property.type)
+ val innerSerial = serializerInstance(sti.serializer, property.module, property.type, property.genericIndex)
val call = if (innerSerial == null) {
val unknownSer = (sti.elementMethodPrefix.isEmpty())
val readFunc =
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt
index 2e50508b13a..30775e8f4a4 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt
@@ -32,6 +32,7 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.common.findEnumTypeS
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findPolymorphicSerializer
import org.jetbrains.kotlinx.serialization.compiler.backend.common.requiresPolymorphism
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
+import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.typeArgPrefix
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
@@ -71,10 +72,12 @@ internal fun InstructionAdapter.genExceptionThrow(exceptionClass: String, messag
athrow()
}
-fun InstructionAdapter.genKOutputMethodCall(property: SerializableProperty, classCodegen: ImplementationBodyCodegen, expressionCodegen: ExpressionCodegen, propertyOwnerType: Type, ownerVar: Int) {
+fun InstructionAdapter.genKOutputMethodCall(property: SerializableProperty, classCodegen: ImplementationBodyCodegen, expressionCodegen: ExpressionCodegen,
+ propertyOwnerType: Type, ownerVar: Int, fromClassStartVar: Int? = null) {
val propertyType = classCodegen.typeMapper.mapType(property.type)
val sti = getSerialTypeInfo(property, propertyType)
- val useSerializer = stackValueSerializerInstance(classCodegen, sti)
+ val useSerializer = if (fromClassStartVar == null) stackValueSerializerInstanceFromSerializer(classCodegen, sti)
+ else stackValueSerializerInstanceFromClass(classCodegen, sti, fromClassStartVar)
if (!sti.unit) classCodegen.genPropertyOnStack(this, expressionCodegen.context, property.descriptor, propertyOwnerType, ownerVar)
invokevirtual(kOutputType.internalName,
"write" + sti.elementMethodPrefix + (if (useSerializer) "Serializable" else "") + "ElementValue",
@@ -114,16 +117,32 @@ internal val polymorphicSerializerId = ClassId(packageFqName, Name.identifier("P
internal val referenceArraySerializerId = ClassId(internalPackageFqName, Name.identifier("ReferenceArraySerializer"))
internal val contextSerializerId = ClassId(packageFqName, Name.identifier("ContextSerializer"))
-// returns false is property should not use serializer
-internal fun InstructionAdapter.stackValueSerializerInstance(codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo): Boolean {
+
+internal fun InstructionAdapter.stackValueSerializerInstanceFromClass(codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo, varIndexStart: Int): Boolean {
val serializer = sti.serializer ?: return false
- return stackValueSerializerInstance(codegen, sti.property.module, sti.property.type, serializer, this)
+ return stackValueSerializerInstance(codegen, sti.property.module, sti.property.type, serializer, this, sti.property.genericIndex) { idx ->
+ load(varIndexStart + idx, kSerializerType)
+ }
+}
+
+internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo): Boolean {
+ val serializer = sti.serializer ?: return false
+ return stackValueSerializerInstance(codegen, sti.property.module, sti.property.type, serializer, this, sti.property.genericIndex) { idx ->
+ load(0, kSerializerType)
+ getfield(codegen.typeMapper.mapClass(codegen.descriptor).internalName, "$typeArgPrefix$idx", kSerializerType.descriptor)
+ }
}
// returns false is cannot not use serializer
// use iv == null to check only (do not emit serializer onto stack)
-internal fun stackValueSerializerInstance(codegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, serializer: ClassDescriptor,
- iv: InstructionAdapter?): Boolean {
+internal fun stackValueSerializerInstance(codegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?,
+ iv: InstructionAdapter?, genericIndex: Int? = null, genericSerializerFieldGetter: (InstructionAdapter.(Int) -> Unit)? = null): Boolean {
+ if (genericIndex != null) {
+ // get field from serializer object
+ iv?.run { genericSerializerFieldGetter?.invoke(this, genericIndex) }
+ return true
+ }
+ val serializer = requireNotNull(maybeSerializer)
if (serializer.kind == ClassKind.OBJECT) {
// singleton serializer -- just get it
if (iv != null)
@@ -133,11 +152,12 @@ internal fun stackValueSerializerInstance(codegen: ClassBodyCodegen, module: Mod
// serializer is not singleton object and shall be instantiated
val argSerializers = kType.arguments.map { projection ->
// bail out from stackValueSerializerInstance if any type argument is not serializable
- val argSerializer = findTypeSerializer(module, projection.type, codegen.typeMapper.mapType(projection.type)) ?: return false
+ val argType = projection.type
+ val argSerializer = findTypeSerializer(module, argType, codegen.typeMapper.mapType(argType)) ?: return false
// check if it can be properly serialized with its args recursively
- if (!stackValueSerializerInstance(codegen, module, projection.type, argSerializer, null))
+ if (!stackValueSerializerInstance(codegen, module, argType, argSerializer, null, argType.genericIndex, genericSerializerFieldGetter))
return false
- Pair(projection.type, argSerializer)
+ Pair(argType, argSerializer)
}
// new serializer if needed
iv?.apply {
@@ -163,7 +183,7 @@ internal fun stackValueSerializerInstance(codegen: ClassBodyCodegen, module: Mod
}
// all serializers get arguments with serializers of their generic types
argSerializers.forEach { (argType, argSerializer) ->
- assert(stackValueSerializerInstance(codegen, module, argType, argSerializer, this))
+ assert(stackValueSerializerInstance(codegen, module, argType, argSerializer, this, argType.genericIndex, genericSerializerFieldGetter))
// wrap into nullable serializer if argType is nullable
if (argType.isMarkedNullable) {
invokestatic("kotlinx/serialization/internal/BuiltinSerializersKt", "makeNullable",
@@ -261,5 +281,6 @@ internal val org.jetbrains.org.objectweb.asm.Type.standardSerializer: String? ge
"Ljava/util/Map;", "Ljava/util/LinkedHashMap;" -> "LinkedHashMapSerializer"
"Ljava/util/HashMap;" -> "HashMapSerializer"
"Ljava/util/Map\$Entry;" -> "MapEntrySerializer"
+ "Lkotlin/Pair;" -> "PairSerializer"
else -> null
}
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt
index d863e95562f..feba3a0ecbf 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt
@@ -26,14 +26,13 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
+import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.anonymousInitializers
import org.jetbrains.kotlinx.serialization.compiler.backend.common.bodyPropertiesDescriptorsMap
import org.jetbrains.kotlinx.serialization.compiler.backend.common.primaryPropertiesDescriptorsMap
-import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties
-import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperty
-import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable
+import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
@@ -73,22 +72,29 @@ class SerializableCodegenImpl(
val thisI = 0
val outputI = 1
val serialDescI = 2
-// val offsetI = 3
+ val offsetI = 3
val superClass = serializableDescriptor.getSuperClassOrAny()
val myPropsStart: Int
if (superClass.isInternalSerializable) {
myPropsStart = SerializableProperties(superClass, classCodegen.bindingContext).serializableProperties.size
+ val superTypeArguments = serializableDescriptor.typeConstructor.supertypes.single { it.toClassDescriptor?.isInternalSerializable == true }.arguments
//super.writeSelf(output, serialDesc)
load(thisI, thisAsmType)
load(outputI, kOutputType)
load(serialDescI, descType)
- invokespecial(classCodegen.typeMapper.mapType(superClass).internalName, signature.asmMethod.name, signature.asmMethod.descriptor, false)
+ superTypeArguments.forEach {
+ val genericIdx = serializableDescriptor.defaultType.arguments.indexOf(it).let { if (it == -1) null else it }
+ val serial = findTypeSerializer(serializableDescriptor.module, it.type, classCodegen.typeMapper.mapType(it.type))
+ stackValueSerializerInstance(classCodegen, serializableDescriptor.module, it.type, serial, this, genericIdx) {
+ load(offsetI + it, kSerializerType)
+ }
+ }
+ val superSignature = classCodegen.typeMapper.mapSignatureSkipGeneric(KSerializerDescriptorResolver.createWriteSelfFunctionDescriptor(superClass))
+ invokespecial(classCodegen.typeMapper.mapType(superClass).internalName, superSignature.asmMethod.name, superSignature.asmMethod.descriptor, false)
}
else {
myPropsStart = 0
- // offset = 0
-// iconst(0)
}
for (i in myPropsStart until properties.serializableProperties.size) {
@@ -97,7 +103,7 @@ class SerializableCodegenImpl(
load(outputI, kOutputType)
load(serialDescI, descType)
iconst(i)
- genKOutputMethodCall(property, classCodegen, exprCodegen, thisAsmType, thisI)
+ genKOutputMethodCall(property, classCodegen, exprCodegen, thisAsmType, thisI, offsetI)
}
areturn(Type.VOID_TYPE)
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCompanionCodegenImpl.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCompanionCodegenImpl.kt
new file mode 100644
index 00000000000..5677a36199e
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCompanionCodegenImpl.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
+
+import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.resolve.descriptorUtil.module
+import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
+import org.jetbrains.kotlinx.serialization.compiler.resolve.*
+
+class SerializableCompanionCodegenImpl(private val codegen: ImplementationBodyCodegen) :
+ SerializableCompanionCodegen(codegen.myClass, codegen.bindingContext) {
+
+ companion object {
+ fun generateSerializableExtensions(codegen: ImplementationBodyCodegen) {
+ val serializableClass = getSerializableClassDescriptorByCompanion(codegen.descriptor) ?: return
+ if (serializableClass.isInternalSerializable)
+ SerializableCompanionCodegenImpl(codegen).generate()
+ }
+ }
+
+ override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
+ val serial = serializableDescriptor.classSerializer?.toClassDescriptor ?: return
+ codegen.generateMethod(methodDescriptor) {sig, expr ->
+ stackValueSerializerInstance(codegen, serializableDescriptor.module, serializableDescriptor.defaultType, serial, this, null) {
+ load(it+1, kSerializerType)
+ }
+ areturn(kSerializerType)
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt
index 7d3700fb48e..d66a2dc29d8 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt
@@ -18,6 +18,7 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.annotationVarsAndDesc
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
+import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.typeArgPrefix
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorBySerializer
import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable
import org.jetbrains.org.objectweb.asm.Label
@@ -50,6 +52,25 @@ class SerializerCodegenImpl(
}
}
+ override fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ConstructorDescriptor) {
+ serializableDescriptor.declaredTypeParameters.forEachIndexed { i, _ ->
+ codegen.v.newField(OtherOrigin(codegen.myClass.psiOrParent), ACC_PRIVATE or ACC_SYNTHETIC,
+ "$typeArgPrefix$i", kSerializerType.descriptor, null, null )
+ }
+
+ codegen.generateMethod(typedConstructorDescriptor) { sig, exprCodegen ->
+ load(0, serializerAsmType)
+ invokespecial("java/lang/Object", "", "()V", false)
+ serializableDescriptor.declaredTypeParameters.forEachIndexed { i, _ ->
+ load(0, serializerAsmType)
+ load(i+1, kSerializerType)
+ putfield(serializerAsmType.internalName, "$typeArgPrefix$i", kSerializerType.descriptor)
+ }
+ areturn(Type.VOID_TYPE)
+ }
+
+ }
+
override fun generateSerialDesc() {
codegen.v.newField(OtherOrigin(codegen.myClass.psiOrParent), ACC_PRIVATE or ACC_STATIC or ACC_FINAL or ACC_SYNTHETIC,
serialDescField, descType.descriptor, null, null)
@@ -126,12 +147,19 @@ class SerializerCodegenImpl(
")" + kOutputType.descriptor, false)
store(outputVar, kOutputType)
if (serializableDescriptor.isInternalSerializable) {
+ val sig = StringBuilder("(${kOutputType.descriptor}${descType.descriptor}")
// call obj.write$Self(output, classDesc)
load(objVar, objType)
load(outputVar, kOutputType)
load(descVar, descType)
+ serializableDescriptor.declaredTypeParameters.forEachIndexed {i, _ ->
+ load(0, kSerializerType)
+ getfield(codegen.typeMapper.mapClass(codegen.descriptor).internalName, "$typeArgPrefix$i", kSerializerType.descriptor)
+ sig.append(kSerializerType.descriptor)
+ }
+ sig.append(")V")
invokevirtual(objType.internalName, KSerializerDescriptorResolver.WRITE_SELF_NAME.asString(),
- "(${kOutputType.descriptor}${descType.descriptor})V", false)
+ sig.toString(), false)
}
else {
// loop for all properties
@@ -235,7 +263,7 @@ class SerializerCodegenImpl(
iconst(labelNum)
val sti = getSerialTypeInfo(property, propertyType)
- val useSerializer = stackValueSerializerInstance(codegen, sti)
+ val useSerializer = stackValueSerializerInstanceFromSerializer(codegen, sti)
val unknownSer = (!useSerializer && sti.elementMethodPrefix.isEmpty())
if (unknownSer) {
aconst(codegen.typeMapper.mapType(property.type))
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationCodegenExtension.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationCodegenExtension.kt
index e5d71867d1c..37074b6654c 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationCodegenExtension.kt
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationCodegenExtension.kt
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerialInfoCodegenImpl
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCodegenImpl
+import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCompanionCodegenImpl
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializerCodegenImpl
class SerializationCodegenExtension : ExpressionCodegenExtension {
@@ -27,5 +28,6 @@ class SerializationCodegenExtension : ExpressionCodegenExtension {
SerialInfoCodegenImpl.generateSerialInfoImplBody(codegen)
SerializableCodegenImpl.generateSerializableExtensions(codegen)
SerializerCodegenImpl.generateSerializerExtensions(codegen)
+ SerializableCompanionCodegenImpl.generateSerializableExtensions(codegen)
}
}
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationJsExtension.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationJsExtension.kt
index 1847bd7062b..4d447a27a22 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationJsExtension.kt
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationJsExtension.kt
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor
import org.jetbrains.kotlin.js.translate.extensions.JsSyntheticTranslateExtension
import org.jetbrains.kotlin.psi.KtPureClassOrObject
+import org.jetbrains.kotlinx.serialization.compiler.backend.js.SerializableCompanionJsTranslator
import org.jetbrains.kotlinx.serialization.compiler.backend.js.SerializableJsTranslator
import org.jetbrains.kotlinx.serialization.compiler.backend.js.SerializerJsTranslator
@@ -28,5 +29,6 @@ class SerializationJsExtension: JsSyntheticTranslateExtension {
override fun generateClassSyntheticParts(declaration: KtPureClassOrObject, descriptor: ClassDescriptor, translator: DeclarationBodyVisitor, context: TranslationContext) {
SerializerJsTranslator.translate(declaration, descriptor, translator, context)
SerializableJsTranslator.translate(declaration, descriptor, translator, context)
+ SerializableCompanionJsTranslator.translate(declaration, descriptor, translator, context)
}
}
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt
index 99dae84ab05..3f5997f8ba2 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt
@@ -31,16 +31,17 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.serialInfoFqName
import java.util.*
class SerializationResolveExtension : SyntheticResolveExtension {
- override fun getSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List {
- if (thisDescriptor.annotations.hasAnnotation(serialInfoFqName))
- return listOf(KSerializerDescriptorResolver.IMPL_NAME)
- else
- return listOf()
+ override fun getSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List = when {
+ thisDescriptor.annotations.hasAnnotation(serialInfoFqName) -> listOf(KSerializerDescriptorResolver.IMPL_NAME)
+ thisDescriptor.isInternalSerializable -> listOf(KSerializerDescriptorResolver.SERIALIZER_CLASS_NAME)
+ else -> listOf()
}
override fun generateSyntheticClasses(thisDescriptor: ClassDescriptor, name: Name, ctx: LazyClassContext, declarationProvider: ClassMemberDeclarationProvider, result: MutableSet) {
if (thisDescriptor.annotations.hasAnnotation(serialInfoFqName) && name == KSerializerDescriptorResolver.IMPL_NAME)
result.add(KSerializerDescriptorResolver.addSerialInfoImplClass(thisDescriptor, declarationProvider, ctx))
+ else if (thisDescriptor.isInternalSerializable && name == KSerializerDescriptorResolver.SERIALIZER_CLASS_NAME)
+ result.add(KSerializerDescriptorResolver.addSerializerImplClass(thisDescriptor, declarationProvider, ctx))
return
}
@@ -50,12 +51,12 @@ class SerializationResolveExtension : SyntheticResolveExtension {
override fun addSyntheticSupertypes(thisDescriptor: ClassDescriptor, supertypes: MutableList) {
KSerializerDescriptorResolver.addSerialInfoSuperType(thisDescriptor, supertypes)
- KSerializerDescriptorResolver.addSerializableSupertypes(thisDescriptor, supertypes)
KSerializerDescriptorResolver.addSerializerSupertypes(thisDescriptor, supertypes)
}
override fun generateSyntheticMethods(thisDescriptor: ClassDescriptor, name: Name, fromSupertypes: List, result: MutableCollection) {
KSerializerDescriptorResolver.generateSerializerMethods(thisDescriptor, fromSupertypes, name, result)
+ KSerializerDescriptorResolver.generateCompanionObjectMethods(thisDescriptor, fromSupertypes, name, result)
}
override fun generateSyntheticProperties(thisDescriptor: ClassDescriptor, name: Name, fromSupertypes: ArrayList, result: MutableSet) {
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt
index bf59da60a15..ef6a154965f 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt
@@ -17,17 +17,16 @@
package org.jetbrains.kotlinx.serialization.compiler.resolve
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
-import org.jetbrains.kotlin.descriptors.ClassDescriptor
-import org.jetbrains.kotlin.descriptors.PropertyDescriptor
-import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
+import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
-import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.module
+import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
+import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.SERIALIZER_CLASS_NAME
internal val packageFqName = FqName("kotlinx.serialization")
internal val internalPackageFqName = FqName("kotlinx.serialization.internal")
@@ -123,7 +122,9 @@ internal val ClassDescriptor?.classSerializer: KotlinType?
// serializer annotation on class?
annotations.serializableWith?.let { return it }
// default serializable?
- if (isInternalSerializable) return companionObjectDescriptor?.defaultType
+ if (isInternalSerializable) return this.unsubstitutedMemberScope
+ .getDescriptorsFiltered(nameFilter = {it == SERIALIZER_CLASS_NAME})
+ .filterIsInstance().singleOrNull()?.defaultType
return null
}
@@ -131,11 +132,20 @@ internal val ClassDescriptor?.classSerializer: KotlinType?
val KotlinType.typeSerializer: KotlinType?
get() = this.annotations.serializableWith ?: (this.toClassDescriptor).classSerializer
+val KotlinType.genericIndex: Int?
+ get() = (this.constructor.declarationDescriptor as? TypeParameterDescriptor)?.index
+
+fun getSerializableClassDescriptorByCompanion(thisDescriptor: ClassDescriptor): ClassDescriptor? {
+ if (!thisDescriptor.isCompanionObject) return null
+ val classDescriptor = (thisDescriptor.containingDeclaration as? ClassDescriptor) ?: return null
+ if (!classDescriptor.isInternalSerializable) return null
+ return classDescriptor
+}
fun getSerializableClassDescriptorBySerializer(serializerDescriptor: ClassDescriptor): ClassDescriptor? {
val serializerForClass = serializerDescriptor.annotations.serializerForClass
if (serializerForClass != null) return serializerForClass.toClassDescriptor
- if (!serializerDescriptor.isCompanionObject) return null
+ if (serializerDescriptor.name != SERIALIZER_CLASS_NAME) return null
val classDescriptor = (serializerDescriptor.containingDeclaration as? ClassDescriptor) ?: return null
if (!classDescriptor.isInternalSerializable) return null
return classDescriptor
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt
index e5da709df37..f04ecdf879f 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt
@@ -28,8 +28,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.lazy.LazyClassContext
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor
-import org.jetbrains.kotlin.types.KotlinType
-import org.jetbrains.kotlin.types.Variance
+import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.createProjection
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import java.util.*
@@ -39,6 +38,9 @@ object KSerializerDescriptorResolver {
val SERIAL_DESC_FIELD = "serialClassDesc"
val SAVE = "save"
val LOAD = "load"
+ val SERIALIZER_CLASS = "\$serializer"
+
+ internal val typeArgPrefix = "typeSerial"
val SERIAL_DESC_FIELD_NAME = Name.identifier(SERIAL_DESC_FIELD)
val SAVE_NAME = Name.identifier(SAVE)
@@ -46,13 +48,8 @@ object KSerializerDescriptorResolver {
val DUMMY_PARAM_NAME = Name.identifier("serializationConstructorMarker")
val WRITE_SELF_NAME = Name.identifier("write\$Self") //todo: add it as a supertype to synthetic resolving
val IMPL_NAME = Name.identifier("Impl")
-
-
- fun addSerializableSupertypes(classDescriptor: ClassDescriptor, supertypes: MutableList) {
- if (classDescriptor.isInternalSerializable && supertypes.none(::isJavaSerializable)) {
- classDescriptor.getJavaSerializableType()?.let { supertypes.add(it) }
- }
- }
+ val SERIALIZER_CLASS_NAME = Name.identifier(SERIALIZER_CLASS)
+ val SERIALIZER_PROVIDER_NAME = Name.identifier("serializer")
fun isSerialInfoImpl(thisDescriptor: ClassDescriptor): Boolean {
return thisDescriptor.name == IMPL_NAME
@@ -90,17 +87,40 @@ object KSerializerDescriptorResolver {
false)
}
+ fun addSerializerImplClass(thisDescriptor: ClassDescriptor, declarationProvider: ClassMemberDeclarationProvider, ctx: LazyClassContext): ClassDescriptor {
+ val thisDeclaration = declarationProvider.correspondingClassOrObject!!
+ val scope = ctx.declarationScopeProvider.getResolutionScopeForDeclaration(declarationProvider.ownerInfo!!.scopeAnchor)
+ val serializerKind = if (thisDescriptor.declaredTypeParameters.isNotEmpty()) ClassKind.CLASS else ClassKind.OBJECT
+ return SyntheticClassOrObjectDescriptor(ctx,
+ thisDeclaration,
+ thisDescriptor, SERIALIZER_CLASS_NAME, thisDescriptor.source,
+ scope,
+ Modality.FINAL, Visibilities.PUBLIC, Visibilities.PRIVATE,
+ serializerKind, false)
+ }
+
fun generateSerializerProperties(thisDescriptor: ClassDescriptor,
fromSupertypes: ArrayList,
name: Name,
result: MutableSet) {
- val classDescriptor = getSerializableClassDescriptorBySerializer(thisDescriptor) ?: return
+ val classDescriptor = getSerializableClassDescriptorBySerializer(thisDescriptor) ?: return
if (name == SERIAL_DESC_FIELD_NAME && result.none(thisDescriptor::checkSerializableClassPropertyResult) &&
- fromSupertypes.none { thisDescriptor.checkSerializableClassPropertyResult(it) && it.modality == Modality.FINAL} )
- result.add(createSerializableClassPropertyDescriptor(thisDescriptor, classDescriptor))
+ fromSupertypes.none { thisDescriptor.checkSerializableClassPropertyResult(it) && it.modality == Modality.FINAL })
+ result.add(createSerializableClassPropertyDescriptor(thisDescriptor, classDescriptor))
}
+ fun generateCompanionObjectMethods(thisDescriptor: ClassDescriptor,
+ fromSupertypes: List,
+ name: Name,
+ result: MutableCollection) {
+ val classDescriptor = getSerializableClassDescriptorByCompanion(thisDescriptor) ?: return
+
+ if (name == SERIALIZER_PROVIDER_NAME && result.none { it.valueParameters.size == classDescriptor.declaredTypeParameters.size }) {
+ result.add(createSerializerGetterDescriptor(thisDescriptor, classDescriptor))
+ }
+ }
+
fun generateSerializerMethods(thisDescriptor: ClassDescriptor,
fromSupertypes: List,
name: Name,
@@ -228,6 +248,71 @@ object KSerializerDescriptorResolver {
return functionDescriptor
}
+ fun createTypedSerializerConstructorDescriptor(classDescriptor: ClassDescriptor, serializableDescriptor: ClassDescriptor): ConstructorDescriptor {
+ val constrDesc = ClassConstructorDescriptorImpl.createSynthesized(
+ classDescriptor,
+ Annotations.EMPTY,
+ false,
+ classDescriptor.source
+ )
+ val serializerClass = classDescriptor.getClassFromSerializationPackage("KSerializer")
+ val targs = mutableListOf()
+ val args = serializableDescriptor.declaredTypeParameters.mapIndexed { index, _ ->
+ val targ = TypeParameterDescriptorImpl.createWithDefaultBound(constrDesc, Annotations.EMPTY, false, Variance.INVARIANT,
+ Name.identifier("T$index"), index)
+
+ val pType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(targ.defaultType)))
+
+ targs.add(targ)
+ ValueParameterDescriptorImpl(constrDesc, null, index, Annotations.EMPTY, Name.identifier("$typeArgPrefix$index"), pType,
+ false, false, false, null, constrDesc.source)
+ }
+
+ constrDesc.initialize(args, Visibilities.PUBLIC, targs)
+ constrDesc.returnType = classDescriptor.defaultType
+ return constrDesc
+ }
+
+ fun createSerializerGetterDescriptor(thisClass: ClassDescriptor, serializableClass: ClassDescriptor): SimpleFunctionDescriptor {
+ val f = SimpleFunctionDescriptorImpl.create(thisClass, Annotations.EMPTY, SERIALIZER_PROVIDER_NAME, CallableMemberDescriptor.Kind.SYNTHESIZED, thisClass.source)
+ val serializerClass = thisClass.getClassFromSerializationPackage("KSerializer")
+
+ val args = mutableListOf()
+ val typeArgs = mutableListOf()
+ var i = 0
+
+ serializableClass.declaredTypeParameters.forEach { it ->
+ val targ = TypeParameterDescriptorImpl.createWithDefaultBound(f, Annotations.EMPTY, false, Variance.INVARIANT,
+ Name.identifier("T$i"), i)
+
+ val pType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(targ.defaultType)))
+
+ args.add(ValueParameterDescriptorImpl(
+ f,
+ null,
+ i,
+ Annotations.EMPTY,
+ Name.identifier("$typeArgPrefix${i}"),
+ pType,
+ false,
+ false,
+ false,
+ null,
+ f.source
+ ))
+
+ typeArgs.add(targ)
+ i++
+ }
+
+ val newSerializableType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializableClass, typeArgs.map { TypeProjectionImpl(it.defaultType) })
+ val serialReturnType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(newSerializableType)))
+
+ f.initialize(null, thisClass.thisAsReceiverParameter, typeArgs, args, serialReturnType, Modality.FINAL, Visibilities.PUBLIC)
+ return f
+ }
+
+
private fun KotlinType.makeNullableIfNotPrimitive() =
if (KotlinBuiltIns.isPrimitiveType(this)) this
else this.makeNullable()
@@ -266,6 +351,24 @@ object KSerializerDescriptorResolver {
f.source)
)
+ val kSerialClass = thisClass.getClassFromSerializationPackage("KSerializer").toSimpleType(false)
+
+ thisClass.declaredTypeParameters.forEach {
+ args.add(ValueParameterDescriptorImpl(
+ f,
+ null,
+ i++,
+ Annotations.EMPTY,
+ Name.identifier("$typeArgPrefix${i-3}"),
+ kSerialClass,
+ false,
+ false,
+ false,
+ null,
+ f.source
+ ))
+ }
+
f.initialize(
null,
thisClass.thisAsReceiverParameter,
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt
index b63fbf12b24..0fb2dc3d097 100644
--- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module
class SerializableProperty(val descriptor: PropertyDescriptor, val isConstructorParameterWithDefault: Boolean) {
val name = descriptor.annotations.serialNameValue ?: descriptor.name.asString()
val type = descriptor.type
+ val genericIndex = type.genericIndex
val module = descriptor.module
val serializableWith = descriptor.annotations.serializableWith
val optional = descriptor.annotations.serialOptional
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/jps/KotlinSerializationJpsPlugin.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/jps/KotlinSerializationJpsPlugin.kt
new file mode 100644
index 00000000000..06152e5e418
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/jps/KotlinSerializationJpsPlugin.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+
+
+package org.jetbrains.kotlinx.serialization.jps
+
+import com.intellij.util.PathUtil
+import org.jetbrains.jps.incremental.CompileContext
+import org.jetbrains.jps.incremental.ModuleBuildTarget
+import org.jetbrains.kotlin.jps.build.KotlinJpsCompilerArgumentsProvider
+import java.io.File
+
+class KotlinSerializationJpsPlugin : KotlinJpsCompilerArgumentsProvider {
+ val JAR_FILE_NAME = "kotlinx-serialization-compiler-plugin.jar"
+
+ override fun getExtraArguments(moduleBuildTarget: ModuleBuildTarget, context: CompileContext): List {
+ return emptyList()
+ }
+
+ override fun getClasspath(moduleBuildTarget: ModuleBuildTarget, context: CompileContext): List {
+ val inJar = File(PathUtil.getJarPathForClass(this::class.java)).isFile
+ return listOf(
+ if (inJar) {
+ File(PathUtil.getJarPathForClass(this::class.java)).absolutePath
+ } else {
+ // We're in tests now
+ val kotlinProjectDirectory = File(PathUtil.getJarPathForClass(javaClass)).parentFile.parentFile.parentFile
+ File(kotlinProjectDirectory, "dist/artifacts/Serialization/lib/$JAR_FILE_NAME").absolutePath
+ })
+ }
+}