mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Fix an infinite recursion in PyNamedParameterImpl#getTypeFromUsages
Use `context.assumeType` to avoid an infinite recursion while processing local variables and getting the type from usages See tests `PyTypeTest#testAnyIsNone` and `PyTypeTest.testParameterFromUsages` for an example (cherry picked from commit c68125b556e264d99a0bd5217827e11a666ca2e4) IJ-MR-172702 GitOrigin-RevId: b0ee153f1164033aa97195f9a2f015c771ce7c44
This commit is contained in:
committed by
intellij-monorepo-bot
parent
27e5a7690d
commit
ccacedc456
+33
-26
@@ -205,36 +205,43 @@ public class PyNamedParameterImpl extends PyBaseElementImpl<PyNamedParameterStub
|
||||
}
|
||||
}
|
||||
}
|
||||
// Guess the type from file-local calls
|
||||
if (context.allowCallContext(this)) {
|
||||
final List<PyType> types = new ArrayList<>();
|
||||
final PyResolveContext resolveContext = PyResolveContext.defaultContext(context);
|
||||
final PyCallableParameter parameter = PyCallableParameterImpl.psi(this);
|
||||
// Guess the type under an assumed type to prevent recursion
|
||||
final PyType assumedResult = context.assumeType(this, null, ctx -> {
|
||||
// Guess the type from file-local calls
|
||||
if (ctx.allowCallContext(this)) {
|
||||
final List<PyType> types = new ArrayList<>();
|
||||
final PyResolveContext resolveContext = PyResolveContext.defaultContext(ctx);
|
||||
final PyCallableParameter parameter = PyCallableParameterImpl.psi(this);
|
||||
|
||||
processLocalCalls(
|
||||
func, call -> {
|
||||
StreamEx
|
||||
.of(call.multiMapArguments(resolveContext))
|
||||
.flatCollection(mapping -> mapping.getMappedParameters().entrySet())
|
||||
.filter(entry -> parameter.equals(entry.getValue()))
|
||||
.map(Map.Entry::getKey)
|
||||
.nonNull()
|
||||
.map(context::getType)
|
||||
.nonNull()
|
||||
.forEach(types::add);
|
||||
return true;
|
||||
processLocalCalls(
|
||||
func, call -> {
|
||||
StreamEx
|
||||
.of(call.multiMapArguments(resolveContext))
|
||||
.flatCollection(mapping -> mapping.getMappedParameters().entrySet())
|
||||
.filter(entry -> parameter.equals(entry.getValue()))
|
||||
.map(Map.Entry::getKey)
|
||||
.nonNull()
|
||||
.map(ctx::getType)
|
||||
.nonNull()
|
||||
.forEach(types::add);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
if (!types.isEmpty()) {
|
||||
return PyUnionType.createWeakType(PyUnionType.union(types));
|
||||
}
|
||||
);
|
||||
|
||||
if (!types.isEmpty()) {
|
||||
return PyUnionType.createWeakType(PyUnionType.union(types));
|
||||
}
|
||||
}
|
||||
if (context.maySwitchToAST(this)) {
|
||||
final PyType typeFromUsages = getTypeFromUsages(context);
|
||||
if (typeFromUsages != null) {
|
||||
return typeFromUsages;
|
||||
if (ctx.maySwitchToAST(this)) {
|
||||
final PyType typeFromUsages = getTypeFromUsages(ctx);
|
||||
if (typeFromUsages != null) {
|
||||
return typeFromUsages;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
if (assumedResult != null) {
|
||||
return assumedResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
package com.jetbrains.python;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.intellij.openapi.util.RecursionManager;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.jetbrains.python.documentation.docstrings.DocStringFormat;
|
||||
import com.jetbrains.python.fixtures.PyTestCase;
|
||||
@@ -783,6 +785,8 @@ public class PyTypeTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void testParameterFromUsages() {
|
||||
RecursionManager.assertOnRecursionPrevention(myFixture.getTestRootDisposable());
|
||||
Registry.get("python.use.better.control.flow.type.inference").setValue(true);
|
||||
final String text = """
|
||||
def foo(bar):
|
||||
expr = bar
|
||||
|
||||
Reference in New Issue
Block a user