[LL FIR] KT-57743 Build dependency symbol providers lazily

- Because `KtModule`s and thereby sessions may depend on each other
  cyclically, we must not create a session during the creation of
  another session. Otherwise, let's say session A and B depend on each
  other. Then we get the following nested creation: session A -> session
  B -> session A -> session B, and so on.
- Dependency symbol providers are in part taken from dependency
  sessions. Hence, we have to create dependency symbol providers lazily.
- For the creation of dependency symbol providers we only need to access
  the non-dependency symbol providers of a session dependency, so we
  don't need to access the dependency's dependency symbol providers.
  Hence, the lazy construction won't run into issues with cycles later
  on.

^KT-57743 fixed
This commit is contained in:
Marco Pennekamp
2023-06-29 14:34:08 +02:00
committed by Space Team
parent 2d279c5f25
commit abc1be2ee0
2 changed files with 45 additions and 35 deletions
@@ -104,12 +104,19 @@ internal class LLFirModuleWithDependenciesSymbolProvider(
internal class LLFirDependenciesSymbolProvider( internal class LLFirDependenciesSymbolProvider(
session: FirSession, session: FirSession,
val providers: List<FirSymbolProvider>, val computeProviders: () -> List<FirSymbolProvider>,
) : FirSymbolProvider(session) { ) : FirSymbolProvider(session) {
init { /**
require(providers.all { it !is LLFirModuleWithDependenciesSymbolProvider }) { * Dependency symbol providers are lazy to support cyclic dependencies between modules. If a module A and a module B depend on each
"${LLFirDependenciesSymbolProvider::class.simpleName} may not contain ${LLFirModuleWithDependenciesSymbolProvider::class.simpleName}:" + * other and session creation tries to access dependency symbol providers eagerly, the creation of session A would try to create session
" dependency providers must be flattened during session creation." * B (to get its symbol providers), which in turn would try to create session A, and so on.
*/
val providers: List<FirSymbolProvider> by lazy {
computeProviders().also { providers ->
require(providers.all { it !is LLFirModuleWithDependenciesSymbolProvider }) {
"${LLFirDependenciesSymbolProvider::class.simpleName} may not contain ${LLFirModuleWithDependenciesSymbolProvider::class.simpleName}:" +
" dependency providers must be flattened during session creation."
}
} }
} }
@@ -80,7 +80,7 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
builtinTypes, builtinTypes,
scope scope
), ),
LLFirDependenciesSymbolProvider(session, listOf(builtinSymbolProvider)), LLFirDependenciesSymbolProvider(session) { listOf(builtinSymbolProvider) },
) )
} }
@@ -101,8 +101,6 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider) val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider)
val dependencies = collectSourceModuleDependencies(module)
val session = LLFirScriptSession(module, components, builtinsSession.builtinTypes) val session = LLFirScriptSession(module, components, builtinsSession.builtinTypes)
components.session = session components.session = session
@@ -130,10 +128,12 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
register(FirProvider::class, provider) register(FirProvider::class, provider)
register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver()) register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver())
val dependencyProvider = LLFirDependenciesSymbolProvider(this, buildList { val dependencyProvider = LLFirDependenciesSymbolProvider(this) {
addDependencySymbolProvidersTo(session, dependencies, this) buildList {
add(builtinsSession.symbolProvider) addDependencySymbolProvidersTo(session, collectSourceModuleDependencies(module), this)
}) add(builtinsSession.symbolProvider)
}
}
val javaSymbolProvider = LLFirJavaSymbolProvider(this, moduleData, project, provider.searchScope) val javaSymbolProvider = LLFirJavaSymbolProvider(this, moduleData, project, provider.searchScope)
register(JavaSymbolProvider::class, javaSymbolProvider) register(JavaSymbolProvider::class, javaSymbolProvider)
@@ -212,7 +212,7 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
register(FirProvider::class, provider) register(FirProvider::class, provider)
register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver()) register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver())
val dependencyProvider = LLFirDependenciesSymbolProvider(this, listOf(builtinsSession.symbolProvider)) val dependencyProvider = LLFirDependenciesSymbolProvider(this) { listOf(builtinsSession.symbolProvider) }
register( register(
FirSymbolProvider::class, FirSymbolProvider::class,
@@ -254,7 +254,6 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider) val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider)
val dependencies = collectSourceModuleDependencies(module)
val session = LLFirSourcesSession(module, components, builtinsSession.builtinTypes) val session = LLFirSourcesSession(module, components, builtinsSession.builtinTypes)
components.session = session components.session = session
@@ -284,10 +283,12 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
registerCompilerPluginExtensions(project, module) registerCompilerPluginExtensions(project, module)
registerCommonComponentsAfterExtensionsAreConfigured() registerCommonComponentsAfterExtensionsAreConfigured()
val dependencyProvider = LLFirDependenciesSymbolProvider(this, buildList { val dependencyProvider = LLFirDependenciesSymbolProvider(this) {
addDependencySymbolProvidersTo(session, dependencies, this) buildList {
add(builtinsSession.symbolProvider) addDependencySymbolProvidersTo(session, collectSourceModuleDependencies(module), this)
}) add(builtinsSession.symbolProvider)
}
}
register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider) register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider)
register(LLFirFirClassByPsiClassProvider::class, LLFirFirClassByPsiClassProvider(this)) register(LLFirFirClassByPsiClassProvider::class, LLFirFirClassByPsiClassProvider(this))
@@ -372,30 +373,32 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
register(FirRegisteredPluginAnnotations::class, LLFirIdeRegisteredPluginAnnotations(this, annotationsResolver)) register(FirRegisteredPluginAnnotations::class, LLFirIdeRegisteredPluginAnnotations(this, annotationsResolver))
register(FirPredicateBasedProvider::class, FirEmptyPredicateBasedProvider) register(FirPredicateBasedProvider::class, FirEmptyPredicateBasedProvider)
val dependencyProvider = LLFirDependenciesSymbolProvider(this, buildList { val dependencyProvider = LLFirDependenciesSymbolProvider(this) {
add(builtinsSession.symbolProvider) buildList {
add(builtinsSession.symbolProvider)
// Script dependencies are self-contained and should not depend on other libraries // Script dependencies are self-contained and should not depend on other libraries
if (module !is KtScriptDependencyModule) { if (module !is KtScriptDependencyModule) {
// Add all libraries excluding the current one // Add all libraries excluding the current one
val librariesSearchScope = ProjectScope.getLibrariesScope(project) val librariesSearchScope = ProjectScope.getLibrariesScope(project)
.intersectWith(GlobalSearchScope.notScope(libraryModule.contentScope)) .intersectWith(GlobalSearchScope.notScope(libraryModule.contentScope))
val restLibrariesProvider = createProjectLibraryProvidersForScope( val restLibrariesProvider = createProjectLibraryProvidersForScope(
session, moduleData, scopeProvider, session, moduleData, scopeProvider,
project, builtinTypes, librariesSearchScope project, builtinTypes, librariesSearchScope
) )
addAll(restLibrariesProvider) addAll(restLibrariesProvider)
moduleAnchorSession?.let { moduleAnchorSession?.let {
(it.symbolProvider as LLFirModuleWithDependenciesSymbolProvider).also { moduleSymbolProvider -> (it.symbolProvider as LLFirModuleWithDependenciesSymbolProvider).also { moduleSymbolProvider ->
addAll(moduleSymbolProvider.providers) addAll(moduleSymbolProvider.providers)
addAll(moduleSymbolProvider.dependencyProvider.providers) addAll(moduleSymbolProvider.dependencyProvider.providers)
}
} }
} }
} }
}) }
register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider) register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider)
register(LLFirFirClassByPsiClassProvider::class, LLFirFirClassByPsiClassProvider(this)) register(LLFirFirClassByPsiClassProvider::class, LLFirFirClassByPsiClassProvider(this))