[FIR] Serialize generated classes into Klib metadata

^KT-57781 Fixed
This commit is contained in:
Dmitriy Novozhilov
2023-04-04 17:17:03 +03:00
committed by Space Team
parent 0f8c797d7c
commit 37e4a05878
4 changed files with 49 additions and 27 deletions
@@ -30,12 +30,10 @@ import org.jetbrains.kotlin.fir.extensions.typeAttributeExtensions
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.scopes.impl.nestedClassifierScope
import org.jetbrains.kotlin.fir.serialization.constant.*
import org.jetbrains.kotlin.fir.serialization.constant.toConstantValue
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
@@ -182,16 +180,7 @@ class FirElementSerializer private constructor(
}
}
fun FirClass.nestedClassifiers(): List<FirClassifierSymbol<*>> {
val scope =
defaultType().scope(session, scopeSession, FakeOverrideTypeCalculator.DoNothing, requiredPhase = null) ?: return emptyList()
return buildList {
scope.getClassifierNames().mapNotNullTo(this) { scope.getSingleClassifier(it) }
addAll(providedDeclarationsService.getProvidedNestedClassifiers(classSymbol, scopeSession))
}
}
val nestedClassifiers = klass.nestedClassifiers()
val nestedClassifiers = computeNestedClassifiersForClass(classSymbol)
for (nestedClassifier in nestedClassifiers) {
if (nestedClassifier is FirTypeAliasSymbol) {
typeAliasProto(nestedClassifier.fir)?.let { builder.addTypeAlias(it) }
@@ -265,6 +254,14 @@ class FirElementSerializer private constructor(
return builder
}
fun computeNestedClassifiersForClass(classSymbol: FirClassSymbol<*>): List<FirClassifierSymbol<*>> {
val scope = session.nestedClassifierScope(classSymbol.fir) ?: return emptyList()
return buildList {
scope.getClassifierNames().mapNotNullTo(this) { scope.getSingleClassifier(it) }
addAll(providedDeclarationsService.getProvidedNestedClassifiers(classSymbol, scopeSession))
}
}
private fun FirClass.memberDeclarations(): List<FirCallableDeclaration> {
return collectDeclarations<FirCallableDeclaration, FirCallableSymbol<*>> { memberScope, addDeclarationIfNeeded ->
memberScope.processAllFunctions { addDeclarationIfNeeded(it) }
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.packageFqName
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.SerializableStringTable
@@ -24,8 +25,11 @@ fun serializeSingleFirFile(
languageVersionSettings: LanguageVersionSettings,
): ProtoBuf.PackageFragment {
val approximator = TypeApproximatorForMetadataSerializer(session)
val packageSerializer = FirElementSerializer.createTopLevel(session, scopeSession, serializerExtension, approximator,
languageVersionSettings)
val packageSerializer = FirElementSerializer.createTopLevel(
session, scopeSession, serializerExtension,
approximator,
languageVersionSettings
)
// TODO: typealiases (see klib serializer)
// TODO: split package fragment (see klib serializer)
@@ -33,20 +37,28 @@ fun serializeSingleFirFile(
val packageProto = packageSerializer.packagePartProto(file.packageFqName, listOf(file), actualizedExpectDeclarations).build()
fun List<FirDeclaration>.makeClassesProtoWithNested(): List<Pair<ProtoBuf.Class, Int>> {
return filterIsInstance<FirClass>().filter { it.shouldBeSerialized(actualizedExpectDeclarations) }
val classesProto = mutableListOf<Pair<ProtoBuf.Class, Int>>()
fun List<FirClassSymbol<*>>.makeClassesProtoWithNested() {
val classSymbols = this
.filter { it.fir.shouldBeSerialized(actualizedExpectDeclarations) }
.sortedBy { it.classId.asFqNameString() }
.flatMap {
val classSerializer = FirElementSerializer.create(
session, scopeSession, it, serializerExtension, null,
approximator, languageVersionSettings
)
val index = classSerializer.stringTable.getFqNameIndex(it)
listOf(classSerializer.classProto(it).build() to index) + it.declarations.makeClassesProtoWithNested()
}
for (symbol in classSymbols) {
val klass = symbol.fir
val classSerializer = FirElementSerializer.create(
session, scopeSession, klass, serializerExtension, null,
approximator, languageVersionSettings
)
val index = classSerializer.stringTable.getFqNameIndex(klass)
classesProto += classSerializer.classProto(klass).build() to index
classSerializer.computeNestedClassifiersForClass(symbol).filterIsInstance<FirClassSymbol<*>>().makeClassesProtoWithNested()
}
}
val classesProto = serializerExtension.processFile(file) { file.declarations.makeClassesProtoWithNested() }
serializerExtension.processFile(file) {
file.declarations.mapNotNull { it.symbol as? FirClassSymbol<*> }.makeClassesProtoWithNested()
}
val hasTopLevelDeclarations = file.declarations.any {
it is FirMemberDeclaration && it.shouldBeSerialized(actualizedExpectDeclarations) &&
@@ -63,4 +63,12 @@ class K2KotlinxSerializationIT : KGPBaseTest() {
build(":compileProductionExecutableKotlinJs")
}
}
@DisplayName("Compile test sourceset with kotlinx.serialization to JS. KT-57781")
@GradleTest
fun `test kotlinx serialization compile test source set to JS`() {
project("kotlinxSerializationK2WithJs", gradleVersion) {
build(":compileTestKotlinJs")
}
}
}
@@ -0,0 +1,5 @@
class SimpleTest {
fun test() {
ErrorResponse.serializer()
}
}