mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Update provided type for typing.Callable (PY-28177)
Use custom type inheriting class-like type to suppress `Callable[...]` warnings. Remove some checks against `Callable` in type checker because they are processed below when matching callable types. Update custom type to detemine ability to call from the name as well.
This commit is contained in:
@@ -25,6 +25,7 @@ import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.util.Processor;
|
||||
import com.jetbrains.NotNullPredicate;
|
||||
import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import com.jetbrains.python.psi.resolve.RatedResolveResult;
|
||||
@@ -117,7 +118,7 @@ public class PyCustomType implements PyClassLikeType {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
@Override
|
||||
public final List<? extends RatedResolveResult> resolveMember(@NotNull final String name,
|
||||
@Nullable final PyExpression location,
|
||||
@@ -128,9 +129,8 @@ public class PyCustomType implements PyClassLikeType {
|
||||
|
||||
// Delegate calls to classes, we mimic but filter if filter is set.
|
||||
for (final PyClassLikeType typeToMimic : myTypesToMimic) {
|
||||
final List<? extends RatedResolveResult> results = typeToMimic.toInstance().resolveMember(
|
||||
name, location, direction, resolveContext, inherited
|
||||
);
|
||||
final List<? extends RatedResolveResult> results =
|
||||
typeToMimic.toInstance().resolveMember(name, location, direction, resolveContext, inherited);
|
||||
|
||||
if (results != null) {
|
||||
globalResult.addAll(Collections2.filter(results, new ResolveFilter()));
|
||||
@@ -158,7 +158,7 @@ public class PyCustomType implements PyClassLikeType {
|
||||
|
||||
@Override
|
||||
public final boolean isCallable() {
|
||||
if (!myInstanceType) {
|
||||
if (!myInstanceType || PyTypingTypeProvider.CALLABLE.equals(myQualifiedName)) {
|
||||
return true; // Due to ctor
|
||||
}
|
||||
for (final PyClassLikeType typeToMimic : myTypesToMimic) {
|
||||
@@ -182,7 +182,7 @@ public class PyCustomType implements PyClassLikeType {
|
||||
return getReturnType(context);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
@Override
|
||||
public final List<? extends RatedResolveResult> resolveMember(@NotNull final String name,
|
||||
@Nullable final PyExpression location,
|
||||
|
||||
+2
-1
@@ -6,6 +6,7 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyConstantExpressionEvaluator;
|
||||
import com.jetbrains.python.psi.types.*;
|
||||
@@ -65,7 +66,7 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
if (args.length == 1 && args[0] instanceof PyReferenceExpression) {
|
||||
final PyReferenceExpression target = (PyReferenceExpression)args[0];
|
||||
|
||||
pushAssertion(target, myPositive, false, context -> new PyCallableTypeImpl(null, null));
|
||||
pushAssertion(target, myPositive, false, context -> PyTypingTypeProvider.createTypingCallableType(node));
|
||||
}
|
||||
}
|
||||
else if (node.isCalleeText(PyNames.ISSUBCLASS)) {
|
||||
|
||||
@@ -65,7 +65,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
public static final String PROTOCOL = "typing.Protocol";
|
||||
public static final String TYPE = "typing.Type";
|
||||
public static final String ANY = "typing.Any";
|
||||
private static final String CALLABLE = "typing.Callable";
|
||||
public static final String CALLABLE = "typing.Callable";
|
||||
private static final String LIST = "typing.List";
|
||||
private static final String DICT = "typing.Dict";
|
||||
private static final String DEFAULT_DICT = "typing.DefaultDict";
|
||||
@@ -169,7 +169,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
// Check for the exact name in advance for performance reasons
|
||||
if ("Callable".equals(referenceExpression.getName())) {
|
||||
if (resolveToQualifiedNames(referenceExpression, context).contains(CALLABLE)) {
|
||||
return createTypingCallableType();
|
||||
return createTypingCallableType(referenceExpression);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -357,8 +357,8 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PyType createTypingCallableType() {
|
||||
return new PyCallableTypeImpl(null, null);
|
||||
public static PyType createTypingCallableType(@NotNull PsiElement anchor) {
|
||||
return new PyCustomType(CALLABLE, null, false, PyBuiltinCache.getInstance(anchor).getObjectType());
|
||||
}
|
||||
|
||||
private static boolean omitFirstParamInTypeComment(@NotNull PyFunction func, @NotNull PyFunctionTypeAnnotation annotation) {
|
||||
@@ -476,7 +476,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
// Depends on typing.Callable defined as a target expression
|
||||
if (CALLABLE.equals(target.getQualifiedName())) {
|
||||
return createTypingCallableType();
|
||||
return createTypingCallableType(referenceTarget);
|
||||
}
|
||||
|
||||
final PyType collection = getCollection(target, context);
|
||||
|
||||
@@ -216,19 +216,10 @@ public class PyTypeChecker {
|
||||
else if (matchClasses(superClass, subClass, context)) {
|
||||
return true;
|
||||
}
|
||||
else if (actualClassType.isDefinition() && PyNames.CALLABLE.equals(expected.getName())) {
|
||||
return true;
|
||||
}
|
||||
if (expected.equals(actual)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (actual instanceof PyFunctionTypeImpl && expectedClassType != null) {
|
||||
final PyClass superClass = expectedClassType.getPyClass();
|
||||
if (PyNames.CALLABLE.equals(superClass.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (actual instanceof PyStructuralType && ((PyStructuralType)actual).isInferredFromUsages()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
from typing import TypeVar, Tuple, Generic, Callable, Type, ClassVar, Union, Optional, List, Dict, \
|
||||
DefaultDict, Set, FrozenSet, Counter, Deque, ChainMap, Protocol
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
# special forms
|
||||
print(Tuple[T])
|
||||
print(Generic[T])
|
||||
print(Protocol[T])
|
||||
print(Callable[[T], T])
|
||||
print(Type[T])
|
||||
print(ClassVar[T])
|
||||
|
||||
# aliases
|
||||
print(Union[T])
|
||||
print(Optional[T])
|
||||
print(List[T])
|
||||
print(Dict[T, T])
|
||||
print(DefaultDict[T, T])
|
||||
print(Set[T])
|
||||
print(FrozenSet[T])
|
||||
print(Counter[T])
|
||||
print(Deque[T])
|
||||
print(ChainMap[T, T])
|
||||
+5
@@ -220,6 +220,11 @@ public class Py3UnresolvedReferencesInspectionTest extends PyInspectionTestCase
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-28177
|
||||
public void testTypingOpaqueNameDunderGetItem() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-21655
|
||||
public void testUsageOfFunctionDecoratedWithAsyncioCoroutine() {
|
||||
doMultiFileTest("a.py");
|
||||
|
||||
Reference in New Issue
Block a user