[python] Move TypeEvalContextCacheImpl to intellij.python.psi.impl, leaving TypeEvalContextCache in intellij.python.psi

It will allow moving the implementation of TypeEvalContext to intellij.python.psi.impl
as well, making more platform and Python plugin APIs available in it.

GitOrigin-RevId: c04a2dc4d892d213f5407bcce35aeb5a3aba42dc
This commit is contained in:
Mikhail Golubev
2025-04-07 14:48:20 +03:00
committed by intellij-monorepo-bot
parent b619e21989
commit fb6554a342
3 changed files with 3 additions and 4 deletions

View File

@@ -43,8 +43,4 @@
interface="com.jetbrains.python.documentation.PythonDocumentationQuickInfoProvider"
dynamic="true"/>
</extensionPoints>
<extensions defaultExtensionNs="com.intellij">
<projectService serviceInterface="com.jetbrains.python.psi.types.TypeEvalContextCache"
serviceImplementation="com.jetbrains.python.psi.types.TypeEvalContextCacheImpl"/>
</extensions>
</idea-plugin>

View File

@@ -1,50 +0,0 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.psi.types;
import com.intellij.openapi.project.Project;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.ConcurrentMap;
/**
* Caches context by their constraints (to prevent context cache loss). Flushes cache every PSI change or low memory conditions.
* Class is thread safe.
* See {@link #getContext(TypeEvalContext)}
*
* @author Ilya.Kazakevich
*/
final class TypeEvalContextCacheImpl implements TypeEvalContextCache {
private final @NotNull CachedValue<ConcurrentMap<TypeEvalConstraints, TypeEvalContext>> myCachedMapStorage;
TypeEvalContextCacheImpl(@NotNull Project project) {
myCachedMapStorage = CachedValuesManager.getManager(project).createCachedValue(new CachedValueProvider<>() {
@Override
public @NotNull CachedValueProvider.Result<ConcurrentMap<TypeEvalConstraints, TypeEvalContext>> compute() {
// This method is called if cache is empty. Create new map for it.
// Concurrent map allows several threads to call get and put, so it is thread safe but not atomic
final ConcurrentMap<TypeEvalConstraints, TypeEvalContext> map = ContainerUtil.createConcurrentSoftValueMap();
return new CachedValueProvider.Result<>(map, PsiModificationTracker.MODIFICATION_COUNT);
}
});
}
@Override
public @NotNull TypeEvalContext getContext(@NotNull TypeEvalContext standard) {
// map is thread safe but not atomic nor getValue() is, so in worst case several threads may produce same result
// both explicit locking and computeIfAbsent leads to deadlock
final ConcurrentMap<TypeEvalConstraints, TypeEvalContext> map = myCachedMapStorage.getValue();
final TypeEvalConstraints key = standard.getConstraints();
final TypeEvalContext cachedContext = map.get(key);
if (cachedContext != null) {
return cachedContext;
}
TypeEvalContext oldValue =
map.putIfAbsent(key, standard);// ConcurrentMap guarantees happens-before so from this moment get() should work in other threads
return oldValue == null ? standard : oldValue;
}
}