PY-78304 Use SoftReference to store types in TypeEvalContext

GitOrigin-RevId: d0e2c405ff0bec6fd9b677a55255929f8100217a
This commit is contained in:
Andrey Vokin
2025-03-21 08:54:55 +01:00
committed by intellij-monorepo-bot
parent 652a953e11
commit 6a5d65a5de
2 changed files with 48 additions and 22 deletions

View File

@@ -0,0 +1,21 @@
// Copyright 2000-2025 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.psi.PsiElement
import com.intellij.util.ProcessingContext
import com.jetbrains.python.psi.AccessDirection
import com.jetbrains.python.psi.PyExpression
import com.jetbrains.python.psi.resolve.PyResolveContext
import com.jetbrains.python.psi.resolve.RatedResolveResult
object PyNullType : PyType {
override fun resolveMember(name: String, location: PyExpression?, direction: AccessDirection, resolveContext: PyResolveContext): List<RatedResolveResult?>? = null
override fun getCompletionVariants(completionPrefix: String?, location: PsiElement?, context: ProcessingContext?): Array<out Any?>? = null
override fun getName(): String = "Null"
override fun isBuiltin(): Boolean = false
override fun assertValid(message: String?) {}
}

View File

@@ -8,6 +8,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.ProcessingContext;
import com.intellij.util.containers.CollectionFactory;
import com.jetbrains.python.psi.PyCallable;
import com.jetbrains.python.psi.PyTypedElement;
import com.jetbrains.python.psi.impl.PyTypeProvider;
@@ -16,7 +17,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -43,8 +43,8 @@ public final class TypeEvalContext {
private final ThreadLocal<ProcessingContext> myProcessingContext = ThreadLocal.withInitial(ProcessingContext::new);
private final Map<PyTypedElement, PyType> myEvaluated = new HashMap<>();
private final Map<PyCallable, PyType> myEvaluatedReturn = new HashMap<>();
private final Map<PyTypedElement, PyType> myEvaluated = CollectionFactory.createConcurrentSoftValueMap();
private final Map<PyCallable, PyType> myEvaluatedReturn = CollectionFactory.createConcurrentSoftValueMap();
private TypeEvalContext(boolean allowDataFlow, boolean allowStubToAST, boolean allowCallContext, @Nullable PsiFile origin) {
myConstraints = new TypeEvalConstraints(allowDataFlow, allowStubToAST, allowCallContext, origin);
@@ -173,19 +173,22 @@ public final class TypeEvalContext {
Pair.create(element, this),
false,
() -> {
synchronized (myEvaluated) {
if (myEvaluated.containsKey(element)) {
final PyType type = myEvaluated.get(element);
assertValid(type, element);
return type;
PyType cachedType = myEvaluated.get(element);
if (cachedType != null) {
if (cachedType == PyNullType.INSTANCE) {
cachedType = null;
}
assertValid(cachedType, element);
return cachedType;
}
final PyType type = element.getType(this, Key.INSTANCE);
PyType type = element.getType(this, Key.INSTANCE);
assertValid(type, element);
synchronized (myEvaluated) {
myEvaluated.put(element, type);
if (type == null) {
type = PyNullType.INSTANCE;
}
return type;
myEvaluated.put(element, type);
return type == PyNullType.INSTANCE ? null : type;
}
);
}
@@ -195,19 +198,21 @@ public final class TypeEvalContext {
Pair.create(callable, this),
false,
() -> {
synchronized (myEvaluatedReturn) {
if (myEvaluatedReturn.containsKey(callable)) {
final PyType type = myEvaluatedReturn.get(callable);
assertValid(type, callable);
return type;
PyType cachedType = myEvaluatedReturn.get(callable);
if (cachedType != null) {
if (cachedType == PyNullType.INSTANCE) {
cachedType = null;
}
assertValid(cachedType, callable);
return cachedType;
}
PyType type = callable.getReturnType(this, Key.INSTANCE);
if (type == null) {
type = PyNullType.INSTANCE;
}
final PyType type = callable.getReturnType(this, Key.INSTANCE);
assertValid(type, callable);
synchronized (myEvaluatedReturn) {
myEvaluatedReturn.put(callable, type);
}
return type;
myEvaluatedReturn.put(callable, type);
return type == PyNullType.INSTANCE ? null : type;
}
);
}