mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-13 21:55:01 +07:00
[python] Rm obsolete registry key python.use.better.control.flow.type.inference
GitOrigin-RevId: 47ca59e692de12376ca17604b8b9ab2439882a45
This commit is contained in:
committed by
intellij-monorepo-bot
parent
55f264d1e3
commit
dd58eaacfc
@@ -24,7 +24,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
|
||||
@@ -50,21 +49,9 @@ public sealed class TypeEvalContext {
|
||||
|
||||
private final ThreadLocal<ProcessingContext> myProcessingContext = ThreadLocal.withInitial(ProcessingContext::new);
|
||||
|
||||
protected final Map<PyTypedElement, PyType> myEvaluated = createMap();
|
||||
protected final Map<PyCallable, PyType> myEvaluatedReturn = createMap();
|
||||
protected final Map<Pair<PyExpression, Object>, PyType> contextTypeCache = createMap();
|
||||
/**
|
||||
* AssumptionContext invariant requires that if type is in the map,
|
||||
* it's dependencies are also in the map, so we can't use softValueMap.
|
||||
* Temporary solution until we know assumeType works as expected.
|
||||
* @see TypeEvalContext#assumeType(PyTypedElement, PyType, Function)
|
||||
*/
|
||||
private static <T> Map<T, PyType> createMap() {
|
||||
if (Registry.is("python.use.better.control.flow.type.inference")) {
|
||||
return new ConcurrentHashMap<>();
|
||||
}
|
||||
return CollectionFactory.createConcurrentSoftValueMap();
|
||||
}
|
||||
protected final Map<PyTypedElement, PyType> myEvaluated = CollectionFactory.createConcurrentSoftValueMap();
|
||||
protected final Map<PyCallable, PyType> myEvaluatedReturn = CollectionFactory.createConcurrentSoftValueMap();
|
||||
protected final Map<Pair<PyExpression, Object>, PyType> contextTypeCache = CollectionFactory.createConcurrentSoftValueMap();
|
||||
|
||||
private TypeEvalContext(boolean allowDataFlow, boolean allowStubToAST, boolean allowCallContext, @Nullable PsiFile origin) {
|
||||
myConstraints = new TypeEvalConstraints(allowDataFlow, allowStubToAST, allowCallContext, origin);
|
||||
|
||||
@@ -493,9 +493,6 @@
|
||||
<categoryKey>INTN.category.python</categoryKey>
|
||||
</intentionAction>
|
||||
|
||||
<registryKey defaultValue="false"
|
||||
description="Enable experimental better handling of recursive cases in type inference"
|
||||
key="python.use.better.control.flow.type.inference"/>
|
||||
<registryKey defaultValue="true"
|
||||
description="Enable pyi stubs distributed with numpy (see https://github.com/numpy/numpy/issues/18565)"
|
||||
key="enable.numpy.pyi.stubs"/>
|
||||
|
||||
-84
@@ -2,13 +2,11 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.codeInsight.controlflow.ConditionalInstruction;
|
||||
import com.intellij.codeInsight.controlflow.ControlFlowUtil;
|
||||
import com.intellij.codeInsight.controlflow.Instruction;
|
||||
import com.intellij.diagnostic.PluginException;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.FileContextUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
@@ -17,7 +15,6 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PythonRuntimeService;
|
||||
import com.jetbrains.python.ast.PyAstFunction;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache;
|
||||
import com.jetbrains.python.codeInsight.controlflow.PyTypeAssertionEvaluator;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ReadWriteInstruction;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
|
||||
@@ -485,87 +482,6 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
|
||||
@NotNull TypeEvalContext context,
|
||||
@NotNull PyExpression anchor,
|
||||
@NotNull ScopeOwner scopeOwner) {
|
||||
if (!Registry.is("python.use.better.control.flow.type.inference")) {
|
||||
return getTypeByControlFlowOld(name, context, anchor, scopeOwner);
|
||||
}
|
||||
|
||||
final PyAugAssignmentStatement augAssignment = PsiTreeUtil.getParentOfType(anchor, PyAugAssignmentStatement.class);
|
||||
final PyElement element = augAssignment != null ? augAssignment : anchor;
|
||||
|
||||
final Instruction[] flow = ControlFlowCache.getControlFlow(scopeOwner).getInstructions();
|
||||
final int thisInstructionIdx = ControlFlowUtil.findInstructionNumberByElement(flow, element);
|
||||
if (thisInstructionIdx == -1) return null;
|
||||
final Instruction thisInstruction = flow[thisInstructionIdx];
|
||||
|
||||
final List<Instruction> defs = PyDefUseUtil.getLatestDefs(scopeOwner, name, element, true, false, context);
|
||||
|
||||
// null means empty set of possible types, Ref(null) means Any
|
||||
final @Nullable Ref<PyType> typeOfEarlierDefinitions = StreamEx.of(defs)
|
||||
.filter(def -> def.num() < thisInstruction.num())
|
||||
.map(def -> getTypeFromInstruction(context, anchor, def))
|
||||
.nonNull()
|
||||
.collect(PyTypeUtil.toUnionFromRef());
|
||||
|
||||
// If earlier definitions were not found, variable may be unbound. Choose Any as type.
|
||||
PyType deducedType = Ref.deref(typeOfEarlierDefinitions);
|
||||
|
||||
final var laterDefs = StreamEx.of(defs).filter(def -> def.num() > thisInstruction.num()).toList();
|
||||
if (laterDefs.isEmpty()) {
|
||||
return deducedType;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_CFG_ITERATIONS; i++) {
|
||||
final @Nullable Ref<PyType> typeOfLaterDefinitions = context.assumeType(anchor, deducedType, (ctx) -> {
|
||||
return StreamEx.of(laterDefs)
|
||||
.map(def -> getTypeFromInstruction(ctx, anchor, def))
|
||||
.nonNull()
|
||||
.collect(PyTypeUtil.toUnionFromRef());
|
||||
});
|
||||
|
||||
if (typeOfLaterDefinitions == null) {
|
||||
return deducedType;
|
||||
}
|
||||
PyType newType = PyUnionType.union(deducedType, typeOfLaterDefinitions.get());
|
||||
if (Objects.equals(deducedType, newType)) {
|
||||
return deducedType;
|
||||
}
|
||||
deducedType = newType;
|
||||
}
|
||||
|
||||
return deducedType;
|
||||
}
|
||||
|
||||
private static @Nullable Ref<PyType> getTypeFromInstruction(@NotNull TypeEvalContext context,
|
||||
@NotNull PyExpression anchor,
|
||||
@NotNull Instruction instr) {
|
||||
if (instr instanceof ReadWriteInstruction readWriteInstruction) {
|
||||
return readWriteInstruction.getType(context, anchor);
|
||||
}
|
||||
if (instr instanceof ConditionalInstruction conditionalInstruction) {
|
||||
final PyType conditionType = context.getType((PyTypedElement)conditionalInstruction.getCondition());
|
||||
if (conditionType instanceof PyNarrowedType narrowedType && narrowedType.isBound()) {
|
||||
var arguments = narrowedType.getOriginal().getArguments(null);
|
||||
if (!arguments.isEmpty()) {
|
||||
var firstArgument = arguments.get(0);
|
||||
PyType type = narrowedType.getNarrowedType();
|
||||
if (firstArgument instanceof PyReferenceExpression && type != null) {
|
||||
@Nullable PyType initial = context.getType(firstArgument);
|
||||
boolean positive = conditionalInstruction.getResult() ^ narrowedType.getNegated();
|
||||
if (narrowedType.getTypeIs()) {
|
||||
return PyTypeAssertionEvaluator.createAssertionType(initial, type, positive, context);
|
||||
}
|
||||
return Ref.create((positive) ? type : initial);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PyType getTypeByControlFlowOld(@NotNull String name,
|
||||
@NotNull TypeEvalContext context,
|
||||
@NotNull PyExpression anchor,
|
||||
@NotNull ScopeOwner scopeOwner) {
|
||||
final PyAugAssignmentStatement augAssignment = PsiTreeUtil.getParentOfType(anchor, PyAugAssignmentStatement.class);
|
||||
final PyElement element = augAssignment != null ? augAssignment : anchor;
|
||||
try {
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.intellij.codeInsight.controlflow.Instruction;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.Version;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.QualifiedName;
|
||||
import com.jetbrains.python.PyLanguageFacadeKt;
|
||||
@@ -86,7 +85,7 @@ public final class PyDefUseUtil {
|
||||
result.add(typeGuardInstruction);
|
||||
return ControlFlowUtil.Operation.CONTINUE;
|
||||
}
|
||||
if (isNotBackEdge(instruction.num(), startNum) &&
|
||||
if (instruction.num() < startNum &&
|
||||
context.getOrigin() == callInstruction.getElement().getContainingFile()) {
|
||||
var newContext = (MAX_CONTROL_FLOW_SIZE > instructions.length)
|
||||
? TypeEvalContext.codeAnalysis(context.getOrigin().getProject(), context.getOrigin())
|
||||
@@ -95,7 +94,7 @@ public final class PyDefUseUtil {
|
||||
}
|
||||
}
|
||||
final PsiElement element = instruction.getElement();
|
||||
if (isNotBackEdge(instruction.num(), startNum)
|
||||
if (instruction.num() < startNum
|
||||
&& acceptTypeAssertions && instruction instanceof ConditionalInstruction conditionalInstruction) {
|
||||
if (conditionalInstruction.getCondition() instanceof PyTypedElement typedElement && context.getOrigin() == typedElement.getContainingFile()) {
|
||||
var newContext = (MAX_CONTROL_FLOW_SIZE > instructions.length)
|
||||
@@ -110,8 +109,8 @@ public final class PyDefUseUtil {
|
||||
}
|
||||
if (instruction instanceof ReadWriteInstruction rwInstruction) {
|
||||
final ReadWriteInstruction.ACCESS access = rwInstruction.getAccess();
|
||||
if (access.isWriteAccess() ||
|
||||
acceptTypeAssertions && access.isAssertTypeAccess() && isNotBackEdge(instruction.num(), startNum)) {
|
||||
if (access.isWriteAccess() ||
|
||||
acceptTypeAssertions && access.isAssertTypeAccess() && instruction.num() < startNum) {
|
||||
final String name = elementName(element);
|
||||
if (Comparing.strEqual(name, varName)) {
|
||||
if (isReachableWithVersionChecks(rwInstruction, languageLevel)) {
|
||||
@@ -134,17 +133,6 @@ public final class PyDefUseUtil {
|
||||
return new ArrayList<>(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* New analysis handles back edges separately.
|
||||
* @see com.jetbrains.python.psi.impl.PyReferenceExpressionImpl#getTypeByControlFlow(String, TypeEvalContext, PyExpression, ScopeOwner)
|
||||
*/
|
||||
private static boolean isNotBackEdge(int instNum, int startNum) {
|
||||
if (Registry.is("python.use.better.control.flow.type.inference")) {
|
||||
return true;
|
||||
}
|
||||
return instNum < startNum;
|
||||
}
|
||||
|
||||
private static int findStartInstructionId(@NotNull PsiElement startAnchor, Instruction @NotNull [] instructions) {
|
||||
PsiElement realCfgAnchor = startAnchor;
|
||||
final PyAugAssignmentStatement augAssignment = PyAugAssignmentStatementNavigator.getStatementByTarget(startAnchor);
|
||||
|
||||
Reference in New Issue
Block a user