[FIR] Try to load properties in order according to kotlinx.serialization metadata extension
Move metadata extension with property order from kotlinx.serialization to core After fix of KT-54792 properties will be deserialized in declaration order if corresponding class was compiled with modern compiler. But this order is needed for kotlinx.serialization for binaries compiled with any kotlin compiler >= 1.4. Since we don't plan to add any extension points into (de)serialization into FIR, we need to take into account existing metadata extension from kotlinx.serialization in compiler itself ^KT-57769 Fixed
This commit is contained in:
committed by
Space Team
parent
7685284cb7
commit
94f77add49
+15
-1
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.toLookupTag
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.SerializationPluginMetadataExtensions
|
||||
import org.jetbrains.kotlin.metadata.deserialization.*
|
||||
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.name.*
|
||||
@@ -139,7 +140,7 @@ fun deserializeClassToSymbol(
|
||||
)
|
||||
|
||||
addDeclarations(
|
||||
classProto.propertyList.map {
|
||||
classProto.propertiesInOrder(context).map {
|
||||
classDeserializer.loadProperty(it, classProto, symbol)
|
||||
}
|
||||
)
|
||||
@@ -320,4 +321,17 @@ class JvmDeserializedClassConfigurator(session: FirSession): DeserializedClassCo
|
||||
}
|
||||
}
|
||||
|
||||
private fun ProtoBuf.ClassOrBuilder.propertiesInOrder(context: FirDeserializationContext): List<ProtoBuf.Property> {
|
||||
val properties = propertyList
|
||||
val versionRequirements = VersionRequirement.create(this, context.nameResolver, context.versionRequirementTable)
|
||||
if (versionRequirements.any { it.version.major >= 2 }) return properties
|
||||
val order = getExtension(SerializationPluginMetadataExtensions.propertiesNamesInProgramOrder)
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?: return properties
|
||||
val propertiesByName = properties.groupBy { it.name }
|
||||
return order.flatMap { propertiesByName[it] ?: emptyList() }.also {
|
||||
assert(it.size == properties.size)
|
||||
}
|
||||
}
|
||||
|
||||
val FirSession.deserializedClassConfigurator: DeserializedClassConfigurator? by FirSession.nullableSessionComponentAccessor()
|
||||
|
||||
+3
-3
@@ -1,13 +1,13 @@
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: plugins/kotlinx-serialization/kotlinx-serialization.k1/src/class_extensions.proto
|
||||
// source: core/metadata/src/properties_order_extension.proto
|
||||
|
||||
package org.jetbrains.kotlinx.serialization.compiler.extensions;
|
||||
package org.jetbrains.kotlin.metadata;
|
||||
|
||||
public final class SerializationPluginMetadataExtensions {
|
||||
private SerializationPluginMetadataExtensions() {}
|
||||
public static void registerAllExtensions(
|
||||
org.jetbrains.kotlin.protobuf.ExtensionRegistryLite registry) {
|
||||
registry.add(org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginMetadataExtensions.propertiesNamesInProgramOrder);
|
||||
registry.add(org.jetbrains.kotlin.metadata.SerializationPluginMetadataExtensions.propertiesNamesInProgramOrder);
|
||||
}
|
||||
public static final int PROPERTIES_NAMES_IN_PROGRAM_ORDER_FIELD_NUMBER = 18000;
|
||||
/**
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
package org.jetbrains.kotlin.metadata.deserialization
|
||||
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.protobuf.MessageLite
|
||||
import org.jetbrains.kotlin.protobuf.MessageLiteOrBuilder
|
||||
|
||||
class VersionRequirementTable private constructor(private val infos: List<ProtoBuf.VersionRequirement>) {
|
||||
operator fun get(id: Int): ProtoBuf.VersionRequirement? = infos.getOrNull(id)
|
||||
@@ -81,7 +81,7 @@ class VersionRequirement(
|
||||
"since $version $level" + (if (errorCode != null) " error $errorCode" else "") + (if (message != null) ": $message" else "")
|
||||
|
||||
companion object {
|
||||
fun create(proto: MessageLite, nameResolver: NameResolver, table: VersionRequirementTable): List<VersionRequirement> {
|
||||
fun create(proto: MessageLiteOrBuilder, nameResolver: NameResolver, table: VersionRequirementTable): List<VersionRequirement> {
|
||||
val ids = when (proto) {
|
||||
is ProtoBuf.Class -> proto.versionRequirementList
|
||||
is ProtoBuf.Constructor -> proto.versionRequirementList
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.jetbrains.kotlinx.serialization.compiler.extensions;
|
||||
package org.jetbrains.kotlin.metadata;
|
||||
|
||||
import "core/metadata/src/metadata.proto";
|
||||
import "core/metadata/src/ext_options.proto";
|
||||
@@ -46,6 +46,7 @@ class ProtoPath(val file: String, val generateDebug: Boolean = true) {
|
||||
val PROTO_PATHS: List<ProtoPath> = listOf(
|
||||
ProtoPath("core/metadata/src/metadata.proto"),
|
||||
ProtoPath("core/metadata/src/builtins.proto"),
|
||||
ProtoPath("core/metadata/src/properties_order_extension.proto", generateDebug = false),
|
||||
ProtoPath("js/js.serializer/src/js.proto"),
|
||||
ProtoPath("js/js.serializer/src/js-ast.proto", false),
|
||||
ProtoPath("core/metadata.jvm/src/jvm_metadata.proto"),
|
||||
@@ -54,7 +55,6 @@ val PROTO_PATHS: List<ProtoPath> = listOf(
|
||||
ProtoPath("compiler/util-klib-metadata/src/KlibMetadataProtoBuf.proto"),
|
||||
ProtoPath("compiler/ir/serialization.common/src/KotlinIr.proto", false),
|
||||
ProtoPath("compiler/ir/serialization.jvm/src/JvmIr.proto", false),
|
||||
ProtoPath("plugins/kotlinx-serialization/kotlinx-serialization.k1/src/class_extensions.proto", generateDebug = false)
|
||||
)
|
||||
|
||||
private val EXT_OPTIONS_PROTO_PATH = ProtoPath("core/metadata/src/ext_options.proto")
|
||||
|
||||
+11
-2
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.gradle.testbase.*
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
|
||||
@OtherGradlePluginTests
|
||||
class KotlinxSerializationMppK2IT : KGPBaseTest() {
|
||||
class K2KotlinxSerializationIT : KGPBaseTest() {
|
||||
private val gradleVersion = GradleVersion.version(TestVersions.Gradle.MAX_SUPPORTED)
|
||||
|
||||
@DisplayName("Compile common code to metadata with kotlinx.serialization and K2")
|
||||
@@ -19,7 +19,16 @@ class KotlinxSerializationMppK2IT : KGPBaseTest() {
|
||||
project("kotlinxSerializationMppK2", gradleVersion) {
|
||||
build(":compileCommonMainKotlinMetadata") {
|
||||
assertTasksExecuted(":compileCommonMainKotlinMetadata")
|
||||
assertOutputContains("BUILD SUCCESSFUL")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("Compile code with kotlinx.serialization with K2 against K1")
|
||||
@GradleTest
|
||||
fun `test kotlinx serialization K2 against K1`() {
|
||||
project("kotlinxSerializationK2AgainstK1", gradleVersion) {
|
||||
build(":app:run") {
|
||||
assertTasksExecuted(":app:run")
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
|
||||
|
||||
plugins {
|
||||
application
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":lib"))
|
||||
}
|
||||
|
||||
val compileKotlin: KotlinCompile by tasks
|
||||
|
||||
compileKotlin.compilerOptions {
|
||||
languageVersion.set(KotlinVersion.KOTLIN_2_0)
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass.set("foo.MainKt")
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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 foo
|
||||
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class Derived(val d: Long = 1000000000000) : Base(2, "world", listOf("b", "c")) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is Derived) return false
|
||||
return a == other.a && b == other.b && c == other.c && d == other.d
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "a: $a, b: $b, c: $c, d: $d"
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val expected = Derived(12)
|
||||
val result = Json.encodeToString(Derived.serializer(), expected)
|
||||
if (result != """{"c":2,"b":"world","a":["b","c"],"d":12}""") {
|
||||
throw IllegalStateException("Error: $result")
|
||||
}
|
||||
val actual = Json.decodeFromString(Derived.serializer(), result)
|
||||
if (expected != actual) {
|
||||
throw IllegalStateException("expected: $expected\nactual: $actual")
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
plugins {
|
||||
kotlin("jvm") apply false
|
||||
kotlin("plugin.serialization") apply false
|
||||
java
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
subprojects {
|
||||
apply {
|
||||
plugin("java")
|
||||
plugin("kotlin")
|
||||
plugin("org.jetbrains.kotlin.plugin.serialization")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
|
||||
|
||||
val compileKotlin: KotlinCompile by tasks
|
||||
|
||||
compileKotlin.compilerOptions {
|
||||
languageVersion.set(KotlinVersion.KOTLIN_1_9)
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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 foo
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
open class Base(
|
||||
val c: Int = 1,
|
||||
val b: String = "hello",
|
||||
val a: List<String> = listOf("a")
|
||||
)
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
rootProject.name = "kotlinxSerializationK2AgainstK1"
|
||||
|
||||
include(":lib", "app")
|
||||
+1
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
|
||||
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter
|
||||
import org.jetbrains.kotlin.js.translate.extensions.JsSyntheticTranslateExtension
|
||||
import org.jetbrains.kotlin.library.metadata.KlibMetadataSerializerProtocol
|
||||
import org.jetbrains.kotlin.metadata.SerializationPluginMetadataExtensions
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
|
||||
|
||||
+1
@@ -8,6 +8,7 @@ package org.jetbrains.kotlinx.serialization.compiler.extensions
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.SerializationPluginMetadataExtensions
|
||||
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer
|
||||
|
||||
+1
-1
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlinx.serialization.compiler.resolve
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.metadata.SerializationPluginMetadataExtensions
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationWithInitializer
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
@@ -19,7 +20,6 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
|
||||
import org.jetbrains.kotlin.serialization.deserialization.getName
|
||||
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.SERIALIZABLE_PROPERTIES
|
||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
|
||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginMetadataExtensions
|
||||
|
||||
class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) :
|
||||
ISerializableProperties<SerializableProperty> {
|
||||
|
||||
Reference in New Issue
Block a user