mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-18254 IDEA-CR-8433 Represent types of varargs annotated with **T or *T as dicts and raw tuples
Type of vararg parameter should be seen differently inside method body and at the call site. For instance, in case of positional vararg, it should be represented as "Iterable[T]" in function quick doc, but as "Tuple[T, ...]" inside its body, because without the latter type checker might complain about missing tuple's methods called on such parameter. Unfortunately, we're not able to represent homogeneous tuples of arbitrary length in our type system so far, so it's just raw tuple for now. The same thing applies to keyword varargs, since collections.Mapping doesn't contain all methods defined for built-in dict. At least we can parametrize type of the standard dict properly with the types of its keys and values.
This commit is contained in:
@@ -403,20 +403,20 @@ public class PyTypeParser {
|
||||
return paramResult;
|
||||
}
|
||||
else if (starCount == 1) {
|
||||
final PyType type = getTypeByName(anchor, PyNames.COLLECTIONS + "." + PyNames.ITERABLE);
|
||||
if (type instanceof PyClassType) {
|
||||
final PyClass pyClass = ((PyClassType)type).getPyClass();
|
||||
final PyCollectionTypeImpl iterableType = new PyCollectionTypeImpl(pyClass, false, Collections.singletonList(paramType));
|
||||
return paramResult.withType(iterableType);
|
||||
final PyClassType tupleType = PyBuiltinCache.getInstance(anchor).getTupleType();;
|
||||
// TODO How to represent unbound homogeneous tuple?
|
||||
if (tupleType != null) {
|
||||
return paramResult.withType(tupleType);
|
||||
}
|
||||
return EMPTY_RESULT;
|
||||
}
|
||||
else if (starCount == 2) {
|
||||
final PyType type = getTypeByName(anchor, PyNames.COLLECTIONS + "." + PyNames.MAPPING);
|
||||
if (type instanceof PyClassType) {
|
||||
final PyClass pyClass = ((PyClassType)type).getPyClass();
|
||||
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(anchor);
|
||||
final PyClassType type = builtinCache.getDictType();
|
||||
if (type != null) {
|
||||
final PyClass pyClass = type.getPyClass();
|
||||
return paramResult.withType(new PyCollectionTypeImpl(pyClass, false,
|
||||
Arrays.asList(getTypeByName(anchor, "str"), paramType)));
|
||||
Arrays.asList(builtinCache.getStrType(), paramType)));
|
||||
}
|
||||
return EMPTY_RESULT;
|
||||
}
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
def f(*args, **kwargs):
|
||||
# type: (*str, **str) -> None
|
||||
args.index('foo')
|
||||
kwargs.pop('bar')
|
||||
@@ -291,15 +291,13 @@ public class PyTypeParserTest extends PyTestCase {
|
||||
assertNotNull(type2);
|
||||
assertEquals("MyObject", type2.getName());
|
||||
|
||||
final PyCollectionType type3 = as(parameterTypes.get(2).getType(context), PyCollectionType.class);
|
||||
final PyClassType type3 = as(parameterTypes.get(2).getType(context), PyClassType.class);
|
||||
assertNotNull(type3);
|
||||
assertEquals("Iterable", type3.getName());
|
||||
assertSize(1, type3.getElementTypes(context));
|
||||
assertEquals("str", type3.getElementTypes(context).get(0).getName());
|
||||
assertEquals("tuple", type3.getName());
|
||||
|
||||
final PyCollectionType type4 = as(parameterTypes.get(3).getType(context), PyCollectionType.class);
|
||||
assertNotNull(type4);
|
||||
assertEquals("Mapping", type4.getName());
|
||||
assertEquals("dict", type4.getName());
|
||||
assertSize(2, type4.getElementTypes(context));
|
||||
assertEquals("str", type4.getElementTypes(context).get(0).getName());
|
||||
assertEquals("int", type4.getElementTypes(context).get(1).getName());
|
||||
|
||||
@@ -451,7 +451,7 @@ public class PyTypingTest extends PyTestCase {
|
||||
|
||||
// PY-18254
|
||||
public void testFunctionTypeComment() {
|
||||
doTest("(x: int, args: Iterable[float], kwargs: Mapping[str, str]) -> List[bool]",
|
||||
doTest("(x: int, args: tuple, kwargs: Dict[str, str]) -> List[bool]",
|
||||
"from typing import List\n" +
|
||||
"\n" +
|
||||
"def f(x, *args, **kwargs):\n" +
|
||||
|
||||
+5
@@ -537,6 +537,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-18254
|
||||
public void testVarargsAnnotatedWithFunctionComment() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<? extends PyInspection> getInspectionClass() {
|
||||
|
||||
Reference in New Issue
Block a user