mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-18598 Support function type annotation of format: (...) -> rtype
This commit is contained in:
committed by
Andrey Vlasovskikh
parent
13480914a4
commit
c4d83386ed
@@ -97,7 +97,10 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
final PyCallableType functionType = as(result.getType(), PyCallableType.class);
|
||||
if (functionType != null) {
|
||||
final List<PyCallableParameter> paramTypes = functionType.getParameters(context);
|
||||
assert paramTypes != null;
|
||||
// Function annotation of kind (...) -> Type
|
||||
if (paramTypes == null) {
|
||||
return Ref.create();
|
||||
}
|
||||
final PyParameter[] funcParams = func.getParameterList().getParameters();
|
||||
final int startOffset = omitFirstParamInTypeComment(func) ? 1 : 0;
|
||||
for (int paramIndex = 0; paramIndex < funcParams.length; paramIndex++) {
|
||||
@@ -357,12 +360,13 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
paramListTypePositions.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (!paramListTypePositions.isEmpty()) {
|
||||
if (!("typing.Callable".equals(qualifiedName) && paramListTypePositions.equals(Collections.singletonList(0)))) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ("typing.Union".equals(qualifiedName)) {
|
||||
return PyUnionType.union(elementTypes);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.intellij.psi.util.QualifiedName;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.hash.HashMap;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.codeInsight.PyTypingTypeProvider;
|
||||
@@ -45,6 +46,7 @@ import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.*;
|
||||
|
||||
import static com.jetbrains.python.psi.PyUtil.as;
|
||||
import static com.jetbrains.python.psi.types.PyTypeTokenTypes.IDENTIFIER;
|
||||
import static com.jetbrains.python.psi.types.PyTypeTokenTypes.PARAMETER;
|
||||
import static com.jetbrains.python.psi.types.functionalParser.FunctionalParserBase.*;
|
||||
@@ -414,30 +416,46 @@ public class PyTypeParser {
|
||||
})
|
||||
.named("param-expr");
|
||||
|
||||
final FunctionalParser<ParseResult, PyElementType> ellipsis = op("...").map(token -> EMPTY_RESULT.withType(EllipsisType.INSTANCE));
|
||||
|
||||
final FunctionalParser<ParseResult, PyElementType> paramTypes = argExpr.then(many(op(",").skipThen(argExpr))).map(pair -> {
|
||||
final List<PyType> types = new ArrayList<>();
|
||||
final ParseResult first = pair.getFirst();
|
||||
final List<ParseResult> second = pair.getSecond();
|
||||
ParseResult result = first;
|
||||
types.add(first.getType());
|
||||
for (ParseResult r : second) {
|
||||
result = result.merge(r);
|
||||
types.add(r.getType());
|
||||
}
|
||||
return result.withType(new PyTypeParser.ParameterListType(types));
|
||||
});
|
||||
|
||||
final FunctionalParser<ParseResult, PyElementType> funcExpr =
|
||||
op("(").skipThen(maybe(argExpr.then(many(op(",").skipThen(argExpr))))).thenSkip(op(")")).thenSkip(op("->")).then(typeExpr)
|
||||
.map(value -> {
|
||||
final List<PyCallableParameter> parameters = new ArrayList<PyCallableParameter>();
|
||||
final ParseResult returnResult = value.getSecond();
|
||||
ParseResult result;
|
||||
final Pair<ParseResult, List<ParseResult>> firstPair = value.getFirst();
|
||||
if (firstPair != null) {
|
||||
final ParseResult first = firstPair.getFirst();
|
||||
final List<ParseResult> second = firstPair.getSecond();
|
||||
result = first;
|
||||
parameters.add(new PyCallableParameterImpl(null, first.getType()));
|
||||
for (ParseResult r : second) {
|
||||
result = result.merge(r);
|
||||
parameters.add(new PyCallableParameterImpl(null, r.getType()));
|
||||
}
|
||||
result = result.merge(returnResult);
|
||||
}
|
||||
else {
|
||||
result = returnResult;
|
||||
}
|
||||
return result.withType(new PyCallableTypeImpl(parameters, returnResult.getType()));
|
||||
})
|
||||
.named("func-expr");
|
||||
op("(").skipThen(maybe(paramTypes.or(ellipsis))).thenSkip(op(")"))
|
||||
.thenSkip(op("->")).then(typeExpr)
|
||||
.map(value -> {
|
||||
final ParseResult paramsResult = value.getFirst(), returnResult = value.getSecond();
|
||||
final List<PyCallableParameter> parameters;
|
||||
ParseResult result = returnResult;
|
||||
if (paramsResult != null) {
|
||||
result = result.merge(paramsResult);
|
||||
final ParameterListType paramsType = as(paramsResult.getType(), ParameterListType.class);
|
||||
if (paramsType != null) {
|
||||
parameters = ContainerUtil.map(paramsType.getTypes(), type -> new PyCallableParameterImpl(null, type));
|
||||
}
|
||||
// ellipsis
|
||||
else {
|
||||
parameters = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
parameters = Collections.emptyList();
|
||||
result = returnResult;
|
||||
}
|
||||
return result.withType(new PyCallableTypeImpl(parameters, returnResult.getType()));
|
||||
})
|
||||
.named("func-expr");
|
||||
|
||||
final FunctionalParser<ParseResult, PyElementType> typeFile =
|
||||
funcExpr
|
||||
@@ -758,4 +776,12 @@ public class PyTypeParser {
|
||||
return myTypes;
|
||||
}
|
||||
}
|
||||
|
||||
public static class EllipsisType extends PyTypeAdapter {
|
||||
public static final EllipsisType INSTANCE = new EllipsisType();
|
||||
|
||||
private EllipsisType() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -504,6 +504,16 @@ public class PyTypingTest extends PyTestCase {
|
||||
|
||||
}
|
||||
|
||||
// PY-18598
|
||||
public void testFunctionTypeCommentEllipsisParameters() {
|
||||
doTest("(x: Any, y: Any, z: Any) -> int",
|
||||
"def f(x, y=42, z='foo'):\n" +
|
||||
" # type: (...) -> int \n" +
|
||||
" pass\n" +
|
||||
"\n" +
|
||||
"expr = f");
|
||||
}
|
||||
|
||||
// PY-18386
|
||||
public void testRecursiveType() {
|
||||
doTest("Union[int, Any]",
|
||||
|
||||
Reference in New Issue
Block a user