[LL] Fix computeIfAbsent contract violation during dangling file session creation

- To avoid recursive updates, we can create sessions which cannot be
  created in isolation outside `computeIfAbsent`. Note that this is the
  current behavior of the default implementation of
  `ConcurrentMap.computeIfAbsent`, which will be replaced soon with
  the stricter behavior of `CleanableSoftValueCache` (see KT-61222).

^KT-65683 fixed
This commit is contained in:
Marco Pennekamp
2024-02-08 17:07:45 +01:00
committed by Space Team
parent 2e2e592cc3
commit b24c75d04c
@@ -88,9 +88,18 @@ class LLFirSessionCache(private val project: Project) {
private fun <T : KtModule> getCachedSession(module: T, storage: SessionStorage, factory: (T) -> LLFirSession): LLFirSession {
checkCanceled()
val session = storage.computeIfAbsent(module) { factory(module) }
checkSessionValidity(session)
val session = if (module.supportsIsolatedSessionCreation) {
storage.computeIfAbsent(module) { factory(module) }
} else {
// Non-isolated session creation may need to access other sessions, so we should create the session outside `computeIfAbsent` to
// avoid recursive update exceptions.
storage[module] ?: run {
val danglingSession = factory(module)
storage.computeIfAbsent(module) { danglingSession }
}
}
checkSessionValidity(session)
return session
}
@@ -199,6 +208,13 @@ class LLFirSessionCache(private val project: Project) {
}
}
/**
* Whether the session for [module] can be created without getting other sessions from the cache. Should be kept in sync with
* [createSession].
*/
private val KtModule.supportsIsolatedSessionCreation: Boolean
get() = this !is KtDanglingFileModule
private fun createSession(module: KtModule): LLFirSession {
val sessionFactory = createPlatformAwareSessionFactory(module)
return when (module) {