[LL FIR] allow recursive access to the same FirThreadSafeCache

^KT-56721 fixed
This commit is contained in:
Ilya Kirillov
2023-02-16 14:10:26 +01:00
committed by Space Team
parent d670e5a695
commit c60fd38e05
4 changed files with 11 additions and 10 deletions
@@ -13,17 +13,9 @@ internal class FirThreadSafeCache<K : Any, V, CONTEXT>(
private val createValue: (K, CONTEXT) -> V private val createValue: (K, CONTEXT) -> V
) : FirCache<K, V, CONTEXT>() { ) : FirCache<K, V, CONTEXT>() {
private val updating: ThreadLocal<Boolean> = ThreadLocal.withInitial { false }
override fun getValue(key: K, context: CONTEXT): V = override fun getValue(key: K, context: CONTEXT): V =
map.getOrPutWithNullableValue(key) { map.getOrPutWithNullableValue(key) {
if (updating.get()) error("Recursive update") createValue(it, context)
try {
updating.set(true)
createValue(it, context)
} finally {
updating.set(false)
}
} }
override fun getValueIfComputed(key: K): V? = override fun getValueIfComputed(key: K): V? =
@@ -19,6 +19,6 @@ internal inline fun <KEY : Any, RESULT> ConcurrentMap<KEY, Any>.getOrPutWithNull
key: KEY, key: KEY,
crossinline compute: (KEY) -> Any? crossinline compute: (KEY) -> Any?
): RESULT { ): RESULT {
val value = computeIfAbsent(key) { compute(key) ?: NullValue } val value = getOrPut(key) { compute(key) ?: NullValue }
return value.nullValueToNull() return value.nullValueToNull()
} }
@@ -23,6 +23,12 @@ import kotlin.reflect.KClass
* TODO: * TODO:
* - check that annotations or meta-annotations is not empty * - check that annotations or meta-annotations is not empty
*/ */
/**
* All `generate*` members have the contract that the computation should be side-effect-free.
* That means that all `generate*` function implementations should not modify any state or leak the generated `FirElement` or `FirBasedSymbol` (e.g., by putting it to some cache).
* This restriction is imposed by the corresponding IDE cache implementation, which might retry the computation several times.
*/
abstract class FirDeclarationGenerationExtension(session: FirSession) : FirExtension(session) { abstract class FirDeclarationGenerationExtension(session: FirSession) : FirExtension(session) {
companion object { companion object {
val NAME = FirExtensionPointName("ExistingClassModification") val NAME = FirExtensionPointName("ExistingClassModification")
@@ -15,6 +15,9 @@ abstract class FirCachesFactory : FirSessionComponent {
* *
* [FirCache.getValue] should not be called inside [createValue] * [FirCache.getValue] should not be called inside [createValue]
* *
* Note, that [createValue] might be called multiple times for the same value,
* but all threads will always get the same value
*
* Where: * Where:
* [CONTEXT] -- type of value which be used to create value by [createValue] * [CONTEXT] -- type of value which be used to create value by [createValue]
*/ */