FIR JS: Convert KLib symbol provider for handling multiple libs

This commit is contained in:
Ilya Chernikov
2022-10-27 15:25:25 +02:00
parent b28dd95621
commit 92ec8e6a3e
2 changed files with 93 additions and 84 deletions
@@ -65,12 +65,8 @@ object FirJsSessionFactory : FirAbstractSessionFactory() {
registerExtraComponents = { it.registerJsSpecificResolveComponents() }, registerExtraComponents = { it.registerJsSpecificResolveComponents() },
createKotlinScopeProvider = { FirKotlinScopeProvider { _, declaredMemberScope, _, _ -> declaredMemberScope } }, createKotlinScopeProvider = { FirKotlinScopeProvider { _, declaredMemberScope, _, _ -> declaredMemberScope } },
createProviders = { session, builtinsModuleData, kotlinScopeProvider -> createProviders = { session, builtinsModuleData, kotlinScopeProvider ->
val klibProviders = resolvedLibraries.map {
KlibBasedSymbolProvider(session, moduleDataProvider, kotlinScopeProvider, it)
}
klibProviders +
listOf( listOf(
KlibBasedSymbolProvider(session, moduleDataProvider, kotlinScopeProvider, resolvedLibraries),
FirCloneableSymbolProvider(session, builtinsModuleData, kotlinScopeProvider), FirCloneableSymbolProvider(session, builtinsModuleData, kotlinScopeProvider),
// (Most) builtins should be taken from the dependencies in JS compilation, therefore builtins provider is the last one // (Most) builtins should be taken from the dependencies in JS compilation, therefore builtins provider is the last one
// TODO: consider using "poisoning" provider for builtins to ensure that proper ones are taken from dependencies // TODO: consider using "poisoning" provider for builtins to ensure that proper ones are taken from dependencies
@@ -24,32 +24,44 @@ import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerAbiStability import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerAbiStability
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
import org.jetbrains.kotlin.utils.SmartList
import java.nio.file.Paths import java.nio.file.Paths
class KlibBasedSymbolProvider( class KlibBasedSymbolProvider(
session: FirSession, session: FirSession,
moduleDataProvider: ModuleDataProvider, moduleDataProvider: ModuleDataProvider,
kotlinScopeProvider: FirKotlinScopeProvider, kotlinScopeProvider: FirKotlinScopeProvider,
private val resolvedLibrary: KotlinResolvedLibrary, private val resolvedLibraries: Collection<KotlinResolvedLibrary>,
defaultDeserializationOrigin: FirDeclarationOrigin = FirDeclarationOrigin.Library defaultDeserializationOrigin: FirDeclarationOrigin = FirDeclarationOrigin.Library
) : AbstractFirDeserializedSymbolProvider( ) : AbstractFirDeserializedSymbolProvider(
session, moduleDataProvider, kotlinScopeProvider, defaultDeserializationOrigin, KlibMetadataSerializerProtocol session, moduleDataProvider, kotlinScopeProvider, defaultDeserializationOrigin, KlibMetadataSerializerProtocol
) { ) {
private val moduleHeader by lazy { private val moduleHeaders by lazy {
resolvedLibrary.loadModuleHeader(resolvedLibrary.library) resolvedLibraries.associate { it to it.loadModuleHeader(it.library) }
} }
private val fragmentNameList by lazy { private val fragmentNamesInLibraries: Map<String, List<KotlinResolvedLibrary>> by lazy {
moduleHeader.packageFragmentNameList.toSet() buildMap<String, SmartList<KotlinResolvedLibrary>> {
for ((library, header) in moduleHeaders) {
for (fragmentName in header.packageFragmentNameList) {
getOrPut(fragmentName) { SmartList() }
.add(library)
}
}
}
} }
private val annotationDeserializer = KlibBasedAnnotationDeserializer(session) private val annotationDeserializer = KlibBasedAnnotationDeserializer(session)
private val constDeserializer = FirConstDeserializer(session, KlibMetadataSerializerProtocol) private val constDeserializer = FirConstDeserializer(session, KlibMetadataSerializerProtocol)
private val deserializationConfiguration = CompilerDeserializationConfiguration(session.languageVersionSettings) private val deserializationConfiguration = CompilerDeserializationConfiguration(session.languageVersionSettings)
private val cachedFragments = mutableMapOf<Pair<String, String>, ProtoBuf.PackageFragment>() private val cachedFragments = mutableMapOf<KotlinResolvedLibrary, MutableMap<Pair<String, String>, ProtoBuf.PackageFragment>>()
private fun getPackageFragment(packageStringName: String, packageMetadataPart: String): ProtoBuf.PackageFragment { private fun getPackageFragment(
return cachedFragments.getOrPut(packageStringName to packageMetadataPart) { resolvedLibrary: KotlinResolvedLibrary, packageStringName: String, packageMetadataPart: String
): ProtoBuf.PackageFragment {
return cachedFragments.getOrPut(resolvedLibrary) {
mutableMapOf()
}.getOrPut(packageStringName to packageMetadataPart) {
resolvedLibrary.loadPackageFragment(resolvedLibrary.library, packageStringName, packageMetadataPart) resolvedLibrary.loadPackageFragment(resolvedLibrary.library, packageStringName, packageMetadataPart)
} }
} }
@@ -57,12 +69,11 @@ class KlibBasedSymbolProvider(
override fun computePackagePartsInfos(packageFqName: FqName): List<PackagePartsCacheData> { override fun computePackagePartsInfos(packageFqName: FqName): List<PackagePartsCacheData> {
val packageStringName = if (packageFqName.isRoot) "" else packageFqName.asString() val packageStringName = if (packageFqName.isRoot) "" else packageFqName.asString()
if (packageStringName !in fragmentNameList) { val librariesWithFragment = fragmentNamesInLibraries[packageStringName] ?: return emptyList()
return emptyList()
}
return resolvedLibrary.library.packageMetadataParts(packageStringName).mapNotNull { return librariesWithFragment.flatMap { resolvedLibrary ->
val fragment = getPackageFragment(packageStringName, it) resolvedLibrary.library.packageMetadataParts(packageStringName).mapNotNull {
val fragment = getPackageFragment(resolvedLibrary, packageStringName, it)
val libraryPath = Paths.get(resolvedLibrary.library.libraryFile.path) val libraryPath = Paths.get(resolvedLibrary.library.libraryFile.path)
val moduleData = moduleDataProvider.getModuleData(libraryPath) ?: return@mapNotNull null val moduleData = moduleDataProvider.getModuleData(libraryPath) ?: return@mapNotNull null
@@ -84,18 +95,18 @@ class KlibBasedSymbolProvider(
) )
} }
} }
}
@OptIn(SymbolInternals::class) @OptIn(SymbolInternals::class)
override fun extractClassMetadata(classId: ClassId, parentContext: FirDeserializationContext?): ClassMetadataFindResult? { override fun extractClassMetadata(classId: ClassId, parentContext: FirDeserializationContext?): ClassMetadataFindResult? {
val packageStringName = classId.packageFqName.asString() val packageStringName = classId.packageFqName.asString()
if (packageStringName !in fragmentNameList) { val librariesWithFragment = fragmentNamesInLibraries[packageStringName] ?: return null
return null
}
resolvedLibrary.library.packageMetadataParts(packageStringName).forEach { for (resolvedLibrary in librariesWithFragment) {
for (packageMetadataPart in resolvedLibrary.library.packageMetadataParts(packageStringName)) {
val libraryPath = Paths.get(resolvedLibrary.library.libraryFile.path) val libraryPath = Paths.get(resolvedLibrary.library.libraryFile.path)
val fragment = getPackageFragment(packageStringName, it) val fragment = getPackageFragment(resolvedLibrary, packageStringName, packageMetadataPart)
val nameResolver = NameResolverImpl( val nameResolver = NameResolverImpl(
fragment.strings, fragment.strings,
@@ -103,7 +114,7 @@ class KlibBasedSymbolProvider(
) )
val finder = KlibMetadataClassDataFinder(fragment, nameResolver) val finder = KlibMetadataClassDataFinder(fragment, nameResolver)
val classProto = finder.findClassData(classId)?.classProto ?: return@forEach val classProto = finder.findClassData(classId)?.classProto ?: continue
val moduleData = moduleDataProvider.getModuleData(libraryPath) ?: return null val moduleData = moduleDataProvider.getModuleData(libraryPath) ?: return null
@@ -111,7 +122,8 @@ class KlibBasedSymbolProvider(
val source = object : DeserializedContainerSource { val source = object : DeserializedContainerSource {
override val incompatibility: IncompatibleVersionErrorData<*>? = null override val incompatibility: IncompatibleVersionErrorData<*>? = null
override val isPreReleaseInvisible = override val isPreReleaseInvisible =
deserializationConfiguration.reportErrorsOnPreReleaseDependencies && (moduleHeader.flags and 1) != 0 deserializationConfiguration.reportErrorsOnPreReleaseDependencies &&
(moduleHeaders[resolvedLibrary]!!.flags and 1) != 0
override val abiStability = DeserializedContainerAbiStability.STABLE override val abiStability = DeserializedContainerAbiStability.STABLE
override val presentableString = "Package '${classId.packageFqName}'" override val presentableString = "Package '${classId.packageFqName}'"
@@ -136,6 +148,7 @@ class KlibBasedSymbolProvider(
symbol.fir.isNewPlaceForBodyGeneration = isNewPlaceForBodyGeneration(classProto) symbol.fir.isNewPlaceForBodyGeneration = isNewPlaceForBodyGeneration(classProto)
} }
} }
}
return null return null
} }
@@ -143,7 +156,7 @@ class KlibBasedSymbolProvider(
override fun isNewPlaceForBodyGeneration(classProto: ProtoBuf.Class) = false override fun isNewPlaceForBodyGeneration(classProto: ProtoBuf.Class) = false
override fun getPackage(fqName: FqName): FqName? { override fun getPackage(fqName: FqName): FqName? {
return if (fqName.toString() in fragmentNameList) { return if (fqName.toString() in fragmentNamesInLibraries) {
fqName fqName
} else { } else {
null null