[LL FIR] do not fail on cycle in module dependencies

This commit is contained in:
Ilya Kirillov
2022-07-19 13:09:29 +02:00
parent 22b8fd636f
commit 237ce187ab
4 changed files with 64 additions and 38 deletions
@@ -41,12 +41,7 @@ internal class LLFirLibrarySessionFactory(
ConcurrentHashMap<KtBinaryModule, LLFirLibrarySession>()
}
fun getLibrarySessionsForModule(module: KtModule): List<LLFirLibraryLikeSession> = buildList {
LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(module.platform).let(::add)
return module.allDirectDependenciesOfType<KtBinaryModule>().mapTo(this) { getLibrarySession(it) }
}
private fun getLibrarySession(ktBinaryModule: KtBinaryModule): LLFirLibrarySession {
fun getLibrarySession(ktBinaryModule: KtBinaryModule): LLFirLibrarySession {
return librarySessionByModule.getOrPut(ktBinaryModule) { createModuleLibrariesSession(ktBinaryModule) }
}
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.resolve.providers.FirDependenciesSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
@@ -78,21 +79,15 @@ internal class LLFirModuleWithDependenciesSymbolProvider(
providers.firstNotNullOfOrNull { it.getPackage(fqName) }
}
internal class LLFirDependentModuleProviders(
internal abstract class LLFirDependentModuleProviders(
session: FirSession,
private val providers: List<FirSymbolProvider>
) : FirDependenciesSymbolProvider(session) {
val dependenciesAsSessions: List<LLFirSession>
get() = buildList {
providers.mapTo(this) { it.session as LLFirSession }
}
constructor(session: FirSession, createSubProviders: MutableList<FirSymbolProvider>.() -> Unit)
: this(session, buildList { createSubProviders() })
abstract val dependentProviders: List<FirSymbolProvider>
abstract val dependentSessions: List<LLFirSession>
override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? =
providers.firstNotNullOfOrNull { provider ->
dependentProviders.firstNotNullOfOrNull { provider ->
when (provider) {
is LLFirModuleWithDependenciesSymbolProvider -> provider.getClassLikeSymbolByFqNameWithoutDependencies(classId)
else -> provider.getClassLikeSymbolByClassId(classId)
@@ -102,10 +97,11 @@ internal class LLFirDependentModuleProviders(
@FirSymbolProviderInternals
override fun getTopLevelCallableSymbolsTo(destination: MutableList<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) {
providers.forEach { provider ->
dependentProviders.forEach { provider ->
when (provider) {
is LLFirModuleWithDependenciesSymbolProvider ->
provider.getTopLevelCallableSymbolsToWithoutDependencies(destination, packageFqName, name)
else -> provider.getTopLevelCallableSymbolsTo(destination, packageFqName, name)
}
}
@@ -113,10 +109,11 @@ internal class LLFirDependentModuleProviders(
@FirSymbolProviderInternals
override fun getTopLevelFunctionSymbolsTo(destination: MutableList<FirNamedFunctionSymbol>, packageFqName: FqName, name: Name) {
providers.forEach { provider ->
dependentProviders.forEach { provider ->
when (provider) {
is LLFirModuleWithDependenciesSymbolProvider ->
provider.getTopLevelFunctionSymbolsToWithoutDependencies(destination, packageFqName, name)
else -> provider.getTopLevelFunctionSymbolsTo(destination, packageFqName, name)
}
}
@@ -124,20 +121,47 @@ internal class LLFirDependentModuleProviders(
@FirSymbolProviderInternals
override fun getTopLevelPropertySymbolsTo(destination: MutableList<FirPropertySymbol>, packageFqName: FqName, name: Name) {
providers.forEach { provider ->
dependentProviders.forEach { provider ->
when (provider) {
is LLFirModuleWithDependenciesSymbolProvider ->
provider.getTopLevelPropertySymbolsToWithoutDependencies(destination, packageFqName, name)
else -> provider.getTopLevelPropertySymbolsTo(destination, packageFqName, name)
}
}
}
override fun getPackage(fqName: FqName): FqName? =
providers.firstNotNullOfOrNull { provider ->
dependentProviders.firstNotNullOfOrNull { provider ->
when (provider) {
is LLFirModuleWithDependenciesSymbolProvider -> provider.getPackageWithoutDependencies(fqName)
else -> provider.getPackage(fqName)
}
}
}
internal class LLFirDependentModuleProvidersBySessions(
session: FirSession,
override val dependentSessions: List<LLFirSession>
) : LLFirDependentModuleProviders(session) {
override val dependentProviders: List<FirSymbolProvider> by lazy(LazyThreadSafetyMode.PUBLICATION) {
dependentSessions.map { it.symbolProvider }
}
constructor(session: FirSession, createSessions: MutableList<LLFirSession>.() -> Unit)
: this(session, buildList { createSessions() })
}
internal class LLFirDependentModuleProvidersByProviders(
session: FirSession,
override val dependentProviders: List<FirSymbolProvider>,
) : LLFirDependentModuleProviders(session) {
override val dependentSessions: List<LLFirSession>
get() = dependentProviders.map { it.session as LLFirSession }
constructor(session: FirSession, createProviders: MutableList<FirSymbolProvider>.() -> Unit)
: this(session, buildList { createProviders() })
}
@@ -55,6 +55,8 @@ internal object LLFirSessionFactory {
): LLFirSourcesSession {
sessionsCache[module]?.let { return it as LLFirSourcesSession }
val platform = module.platform
val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform)
val languageVersionSettings = object : LanguageVersionSettings by module.languageVersionSettings {
override fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State =
if (feature == LanguageFeature.EnableDfaWarningsInK2) LanguageFeature.State.ENABLED
@@ -71,12 +73,11 @@ internal object LLFirSessionFactory {
val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider)
val contentScope = module.contentScope
val dependentModules = module.directRegularDependenciesOfType<KtSourceModule>()
val session = LLFirSourcesSession(
module,
project,
components,
LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform).builtinTypes
builtinsSession.builtinTypes
)
sessionsCache[module] = session
components.session = session
@@ -109,21 +110,27 @@ internal object LLFirSessionFactory {
register(FirSwitchableExtensionDeclarationsSymbolProvider::class, it)
}
val dependencyProvider = LLFirDependentModuleProviders(this) {
librariesSessionFactory.getLibrarySessionsForModule(module).mapTo(this) { it.symbolProvider }
dependentModules
.mapTo(this) { dependentSourceModule ->
val dependentSourceSession = createSourcesSession(
project,
dependentSourceModule,
globalResolveComponents,
sessionInvalidator,
sessionsCache,
librariesSessionFactory = librariesSessionFactory,
configureSession = configureSession,
)
dependentSourceSession.symbolProvider
val dependencyProvider = LLFirDependentModuleProvidersBySessions(this) {
module.directRegularDependencies.mapNotNullTo(this) { dependency ->
when (dependency) {
is KtBuiltinsModule -> null // build in is already added
is KtBinaryModule -> LLFirLibrarySessionFactory.getInstance(project).getLibrarySession(dependency)
is KtSourceModule -> {
createSourcesSession(
project,
dependency,
globalResolveComponents,
sessionInvalidator,
sessionsCache,
librariesSessionFactory = librariesSessionFactory,
configureSession = configureSession,
)
}
is KtNotUnderContentRootModule -> error("Module $module cannot depend on ${dependency::class}: $dependency")
is KtLibrarySourceModule -> error("Module $module cannot depend on ${dependency::class}: $dependency")
}
}
add(builtinsSession)
}
val javaSymbolProvider = createJavaSymbolProvider(this, moduleData, project, contentScope)
@@ -205,7 +212,7 @@ internal object LLFirSessionFactory {
register(FirRegisteredPluginAnnotations::class, LLFirIdeRegisteredPluginAnnotations(this@session, annotationsResolver))
register(FirPredicateBasedProvider::class, FirEmptyPredicateBasedProvider())
val dependencyProvider = LLFirDependentModuleProviders(this) {
val dependencyProvider = LLFirDependentModuleProvidersByProviders(this) {
// <all libraries scope> - <current library scope>
val librariesSearchScope =
ProjectScope.getLibrariesScope(project).intersectWith(GlobalSearchScope.notScope(libraryModule.contentScope))
@@ -24,7 +24,7 @@ class LLFirSessionProvider internal constructor(
) : FirSessionProvider() {
private val moduleToSession = moduleToResolvableSession + moduleToResolvableSession.values.flatMap { module ->
(module.dependenciesSymbolProvider as LLFirDependentModuleProviders).dependenciesAsSessions
(module.dependenciesSymbolProvider as LLFirDependentModuleProviders).dependentSessions
}.associateBy { it.ktModule }
override fun getSession(moduleData: FirModuleData): LLFirSession {