mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -777,7 +777,7 @@ __builtin__.str.replace = \
|
||||
:type old: string \n\
|
||||
:type new: string \n\
|
||||
:type count: int or long \n\
|
||||
:rtype: bytes \n\
|
||||
:rtype: string \n\
|
||||
|
||||
__builtin__.str.rfind = \
|
||||
:type sub: string \n\
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiField;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
@@ -11,7 +12,9 @@ import com.jetbrains.python.psi.PyQualifiedExpression;
|
||||
import com.jetbrains.python.psi.resolve.CompletionVariantsProcessor;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import com.jetbrains.python.psi.resolve.RatedResolveResult;
|
||||
import com.jetbrains.python.psi.types.*;
|
||||
import com.jetbrains.python.psi.types.PyClassLikeType;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -98,7 +101,7 @@ public class PyJavaClassType implements PyClassLikeType {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<PyType> getParameterTypes(@NotNull TypeEvalContext context) {
|
||||
public List<Pair<String, PyType>> getParameters(@NotNull TypeEvalContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
@@ -41,7 +42,7 @@ public class PyJavaMethodType implements PyCallableType {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<PyType> getParameterTypes(@NotNull TypeEvalContext context) {
|
||||
public List<Pair<String, PyType>> getParameters(@NotNull TypeEvalContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -136,6 +136,7 @@ public class PyNames {
|
||||
|
||||
public static final String NOT_IMPLEMENTED_ERROR = "NotImplementedError";
|
||||
|
||||
public static final String UNKNOWN_TYPE = "unknown";
|
||||
|
||||
/**
|
||||
* Contains all known predefined names of "__foo__" form.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.jetbrains.python.psi.types;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.jetbrains.python.psi.PyQualifiedExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -31,8 +32,8 @@ public interface PyCallableType extends PyType {
|
||||
/**
|
||||
* Returns the list of parameter types.
|
||||
*
|
||||
* @return list of positional parameters or null if not applicable.
|
||||
* @return list of (name, type) pairs or null if not applicable. Name and type in pair may be null.
|
||||
*/
|
||||
@Nullable
|
||||
List<PyType> getParameterTypes(@NotNull TypeEvalContext context);
|
||||
List<Pair<String, PyType>> getParameters(@NotNull TypeEvalContext context);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.google.common.base.Function;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.psi.PyClass;
|
||||
import com.jetbrains.python.psi.PyFunction;
|
||||
import com.jetbrains.python.psi.types.PyClassType;
|
||||
@@ -49,7 +50,7 @@ public class PySignatureUtil {
|
||||
return type.getName();
|
||||
}
|
||||
else {
|
||||
return "unknown";
|
||||
return PyNames.UNKNOWN_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,17 +4,20 @@ import com.google.common.base.Function;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.python.psi.PyFunction;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.psi.Callable;
|
||||
import com.jetbrains.python.psi.PyNamedParameter;
|
||||
import com.jetbrains.python.psi.PyParameter;
|
||||
import com.jetbrains.python.psi.types.*;
|
||||
import com.jetbrains.python.toolbox.ChainIterable;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.jetbrains.python.documentation.DocumentationBuilderKit.$;
|
||||
@@ -24,7 +27,6 @@ import static com.jetbrains.python.documentation.DocumentationBuilderKit.combUp;
|
||||
* @author traff
|
||||
*/
|
||||
public class PyTypeModelBuilder {
|
||||
@NonNls static final String UNKNOWN = "unknown";
|
||||
private final Map<PyType, TypeModel> myVisited = Maps.newHashMap();
|
||||
private final TypeEvalContext myContext;
|
||||
|
||||
@@ -62,11 +64,11 @@ public class PyTypeModelBuilder {
|
||||
|
||||
static class CollectionOf extends TypeModel {
|
||||
private String collectionName;
|
||||
private TypeModel elementType;
|
||||
private List<TypeModel> elementTypes;
|
||||
|
||||
private CollectionOf(String collectionName, TypeModel elementType) {
|
||||
private CollectionOf(String collectionName, List<TypeModel> elementTypes) {
|
||||
this.collectionName = collectionName;
|
||||
this.elementType = elementType;
|
||||
this.elementTypes = elementTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,16 +90,34 @@ public class PyTypeModelBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
static class UnknownType extends TypeModel {
|
||||
private final TypeModel type;
|
||||
|
||||
private UnknownType(TypeModel type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
void accept(TypeVisitor visitor) {
|
||||
visitor.unknown(this);
|
||||
}
|
||||
}
|
||||
|
||||
private static TypeModel _(String name) {
|
||||
return new NamedType(name);
|
||||
}
|
||||
|
||||
static class FunctionType extends TypeModel {
|
||||
private TypeModel returnType;
|
||||
private Collection<TypeModel> parameters;
|
||||
@Nullable private Collection<TypeModel> parameters;
|
||||
|
||||
FunctionType(@NotNull TypeModel returnType, Collection<TypeModel> parameters) {
|
||||
this.returnType = returnType;
|
||||
FunctionType(@Nullable TypeModel returnType, @Nullable Collection<TypeModel> parameters) {
|
||||
if (returnType != null) {
|
||||
this.returnType = returnType;
|
||||
}
|
||||
else {
|
||||
this.returnType = _(PyNames.UNKNOWN_TYPE);
|
||||
}
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
@@ -137,7 +157,7 @@ public class PyTypeModelBuilder {
|
||||
return evaluated;
|
||||
}
|
||||
if (myVisited.containsKey(type)) { //already evaluating?
|
||||
return type != null ? _(type.getName()) : _(UNKNOWN);
|
||||
return type != null ? _(type.getName()) : _(PyNames.UNKNOWN_TYPE);
|
||||
}
|
||||
myVisited.put(type, null); //mark as evaluating
|
||||
|
||||
@@ -145,13 +165,24 @@ public class PyTypeModelBuilder {
|
||||
if (type instanceof PyCollectionType) {
|
||||
final String name = type.getName();
|
||||
final PyType elementType = ((PyCollectionType)type).getElementType(myContext);
|
||||
if (elementType != null) {
|
||||
result = new CollectionOf(name, build(elementType, true));
|
||||
final List<TypeModel> elementTypes = new ArrayList<TypeModel>();
|
||||
if (elementType instanceof PyTupleType) {
|
||||
final PyTupleType tupleType = (PyTupleType)elementType;
|
||||
final int n = tupleType.getElementCount();
|
||||
for (int i = 0; i < n; i++) {
|
||||
elementTypes.add(build(tupleType.getElementType(i), true));
|
||||
}
|
||||
}
|
||||
else if (elementType != null) {
|
||||
elementTypes.add(build(elementType, true));
|
||||
}
|
||||
if (!elementTypes.isEmpty()) {
|
||||
result = new CollectionOf(name, elementTypes);
|
||||
}
|
||||
}
|
||||
else if (type instanceof PyUnionType && allowUnions) {
|
||||
if (type instanceof PyDynamicallyEvaluatedType) {
|
||||
result = build(((PyDynamicallyEvaluatedType)type).exclude(null, myContext), true);
|
||||
if (type instanceof PyDynamicallyEvaluatedType || PyTypeChecker.isUnknown(type)) {
|
||||
result = new UnknownType(build(((PyUnionType)type).excludeNull(), true));
|
||||
}
|
||||
else {
|
||||
result = new OneOf(
|
||||
@@ -163,29 +194,45 @@ public class PyTypeModelBuilder {
|
||||
}));
|
||||
}
|
||||
}
|
||||
else if (type instanceof PyCallableType && !(type instanceof PyClassLikeType)) {
|
||||
result = build((PyCallableType)type);
|
||||
}
|
||||
if (result == null) {
|
||||
result = type != null ? _(type.getName()) : _(UNKNOWN);
|
||||
result = type != null ? _(type.getName()) : _(PyNames.UNKNOWN_TYPE);
|
||||
}
|
||||
myVisited.put(type, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private TypeModel build(@NotNull PyCallableType type) {
|
||||
List<TypeModel> parameterModels = null;
|
||||
final List<Pair<String, PyType>> parameters = type.getParameters(myContext);
|
||||
if (parameters != null) {
|
||||
parameterModels = new ArrayList<TypeModel>();
|
||||
for (Pair<String, PyType> parameter : parameters) {
|
||||
parameterModels.add(new ParamType(parameter.getFirst(), build(parameter.getSecond(), true)));
|
||||
}
|
||||
}
|
||||
final PyType ret = type.getCallType(myContext, null);
|
||||
final TypeModel returnType = build(ret, true);
|
||||
return new FunctionType(returnType, parameterModels);
|
||||
}
|
||||
|
||||
public TypeModel build(PyFunction function) {
|
||||
final PyType returnType = function.getReturnType(myContext, null);
|
||||
return new FunctionType(build(returnType, true), Collections2.transform(Lists.newArrayList(function.getParameterList().getParameters()),
|
||||
public TypeModel build(Callable callable) {
|
||||
final PyType returnType = callable.getReturnType(myContext, null);
|
||||
return new FunctionType(build(returnType, true), Collections2.transform(Lists.newArrayList(callable.getParameterList().getParameters()),
|
||||
new Function<PyParameter, TypeModel>() {
|
||||
@Override
|
||||
public TypeModel apply(PyParameter p) {
|
||||
final PyNamedParameter np = p.getAsNamed();
|
||||
if (np != null) {
|
||||
TypeModel paramType =
|
||||
_(UNKNOWN);
|
||||
TypeModel paramType = _(PyNames.UNKNOWN_TYPE);
|
||||
final PyType t = myContext.getType(np);
|
||||
if (t != null) {
|
||||
paramType = build(t, true);
|
||||
}
|
||||
return new ParamType(np.getName(), paramType);
|
||||
final String name = PyFunctionType.getParameterName(np);
|
||||
return new ParamType(name, paramType);
|
||||
}
|
||||
return new ParamType(p.toString(), null);
|
||||
}
|
||||
@@ -202,6 +249,8 @@ public class PyTypeModelBuilder {
|
||||
void function(FunctionType type);
|
||||
|
||||
void param(ParamType text);
|
||||
|
||||
void unknown(UnknownType type);
|
||||
}
|
||||
|
||||
private static class TypeToStringVisitor extends TypeNameVisitor {
|
||||
@@ -220,6 +269,15 @@ public class PyTypeModelBuilder {
|
||||
public String getString() {
|
||||
return myStringBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unknown(UnknownType type) {
|
||||
final TypeModel nested = type.type;
|
||||
if (nested != null) {
|
||||
nested.accept(this);
|
||||
}
|
||||
add(" | " + PyNames.UNKNOWN_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
private static class TypeToBodyWithLinksVisitor extends TypeNameVisitor {
|
||||
@@ -260,17 +318,15 @@ public class PyTypeModelBuilder {
|
||||
add("...");
|
||||
return;
|
||||
}
|
||||
add("one of (");
|
||||
processListCommaSeparated(oneOf.oneOfTypes);
|
||||
add(")");
|
||||
processList(oneOf.oneOfTypes, " | ");
|
||||
myDepth--;
|
||||
}
|
||||
|
||||
private void processListCommaSeparated(Collection<TypeModel> list) {
|
||||
private void processList(Collection<TypeModel> list, String separator) {
|
||||
boolean first = true;
|
||||
for (TypeModel t : list) {
|
||||
if (!first) {
|
||||
add(", ");
|
||||
add(separator);
|
||||
}
|
||||
else {
|
||||
first = false;
|
||||
@@ -290,8 +346,9 @@ public class PyTypeModelBuilder {
|
||||
return;
|
||||
}
|
||||
addType(collectionOf.collectionName);
|
||||
add(" of ");
|
||||
collectionOf.elementType.accept(this);
|
||||
add("[");
|
||||
processList(collectionOf.elementTypes, ", ");
|
||||
add("]");
|
||||
myDepth--;
|
||||
}
|
||||
|
||||
@@ -310,10 +367,15 @@ public class PyTypeModelBuilder {
|
||||
return;
|
||||
}
|
||||
add("(");
|
||||
processListCommaSeparated(function.parameters);
|
||||
final Collection<TypeModel> parameters = function.parameters;
|
||||
if (parameters != null) {
|
||||
processList(parameters, ", ");
|
||||
}
|
||||
else {
|
||||
add("...");
|
||||
}
|
||||
add(") -> ");
|
||||
function.returnType.accept(this);
|
||||
add("\n");
|
||||
myDepth--;
|
||||
}
|
||||
|
||||
@@ -335,5 +397,10 @@ public class PyTypeModelBuilder {
|
||||
}
|
||||
myDepth--;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unknown(UnknownType type) {
|
||||
type.type.accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
|
||||
if (!PyNames.INIT.equals(name)) {
|
||||
cat.addItem(escaper.apply("\nInferred type: "));
|
||||
getTypeDescription(fun, cat);
|
||||
cat.addItem(BR);
|
||||
}
|
||||
return cat;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class PyTypeCheckerInspection extends PyInspection {
|
||||
final PyExpression source = node.getForPart().getSource();
|
||||
if (source != null) {
|
||||
final PyType type = myTypeEvalContext.getType(source);
|
||||
if (type != null && !PyABCUtil.isSubtype(type, PyNames.ITERABLE)) {
|
||||
if (!PyTypeChecker.isUnknown(type) && !PyABCUtil.isSubtype(type, PyNames.ITERABLE)) {
|
||||
registerProblem(source, String.format("Expected 'collections.Iterable', got '%s' instead",
|
||||
PythonDocumentationProvider.getTypeName(type, myTypeEvalContext)));
|
||||
}
|
||||
|
||||
@@ -252,7 +252,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
|
||||
final PyBuiltinCache cache = PyBuiltinCache.getInstance(this);
|
||||
final PyClass listClass = cache.getClass("list");
|
||||
final PyStatementList statements = getStatementList();
|
||||
final Set<PyType> types = new HashSet<PyType>();
|
||||
final Set<PyType> types = new LinkedHashSet<PyType>();
|
||||
if (statements != null && listClass != null) {
|
||||
statements.accept(new PyRecursiveElementVisitor() {
|
||||
@Override
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
@@ -27,6 +26,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -235,7 +236,7 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl<PyNamedParame
|
||||
}
|
||||
// Guess the type from file-local usages
|
||||
if (context.allowLocalUsages(this)) {
|
||||
final Ref<PyType> ref = Ref.create(null);
|
||||
final List<PyType> types = new ArrayList<PyType>();
|
||||
processLocalCalls(func, new Processor<PyCallExpression>() {
|
||||
@Override
|
||||
public boolean process(@NotNull PyCallExpression call) {
|
||||
@@ -247,8 +248,8 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl<PyNamedParame
|
||||
if (argument != null) {
|
||||
final PyType type = context.getType(argument);
|
||||
if (type != null) {
|
||||
ref.set(type);
|
||||
return false;
|
||||
types.add(type);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -256,7 +257,9 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl<PyNamedParame
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return ref.get();
|
||||
if (!types.isEmpty()) {
|
||||
return PyUnionType.createWeakType(PyUnionType.union(types));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package com.jetbrains.python.psi.types;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.psi.AccessDirection;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.PyQualifiedExpression;
|
||||
@@ -17,11 +19,11 @@ import java.util.List;
|
||||
* @author vlan
|
||||
*/
|
||||
public class PyCallableTypeImpl implements PyCallableType {
|
||||
@NotNull private final List<PyType> myParameterTypes;
|
||||
@Nullable private final List<Pair<String, PyType>> myParameters;
|
||||
@Nullable private final PyType myReturnType;
|
||||
|
||||
public PyCallableTypeImpl(@NotNull List<PyType> parameterTypes, @Nullable PyType returnType) {
|
||||
myParameterTypes = parameterTypes;
|
||||
public PyCallableTypeImpl(@Nullable List<Pair<String, PyType>> parameters, @Nullable PyType returnType) {
|
||||
myParameters = parameters;
|
||||
myReturnType = returnType;
|
||||
}
|
||||
|
||||
@@ -38,8 +40,8 @@ public class PyCallableTypeImpl implements PyCallableType {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<PyType> getParameterTypes(@NotNull TypeEvalContext context) {
|
||||
return myParameterTypes;
|
||||
public List<Pair<String, PyType>> getParameters(@NotNull TypeEvalContext context) {
|
||||
return myParameters;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -60,15 +62,30 @@ public class PyCallableTypeImpl implements PyCallableType {
|
||||
@Override
|
||||
public String getName() {
|
||||
return String.format("(%s) -> %s",
|
||||
StringUtil.join(myParameterTypes,
|
||||
new Function<PyType, String>() {
|
||||
myParameters != null ?
|
||||
StringUtil.join(myParameters,
|
||||
new Function<Pair<String, PyType>, String>() {
|
||||
@Override
|
||||
public String fun(PyType type) {
|
||||
return type != null ? type.getName() : "unknown";
|
||||
public String fun(Pair<String, PyType> param) {
|
||||
if (param != null) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final String name = param.getFirst();
|
||||
final PyType type = param.getSecond();
|
||||
if (name != null) {
|
||||
builder.append(name);
|
||||
if (type != null) {
|
||||
builder.append(": ");
|
||||
}
|
||||
}
|
||||
builder.append(type != null ? type.getName() : PyNames.UNKNOWN_TYPE);
|
||||
return builder.toString();
|
||||
}
|
||||
return PyNames.UNKNOWN_TYPE;
|
||||
}
|
||||
},
|
||||
", "),
|
||||
myReturnType != null ? myReturnType.getName() : "unknown");
|
||||
", ") :
|
||||
"...",
|
||||
myReturnType != null ? myReturnType.getName() : PyNames.UNKNOWN_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -279,7 +279,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<PyType> getParameterTypes(@NotNull TypeEvalContext context) {
|
||||
public List<Pair<String, PyType>> getParameters(@NotNull TypeEvalContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.jetbrains.python.psi.types;
|
||||
|
||||
import com.jetbrains.python.PyNames;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -34,6 +35,6 @@ public class PyDynamicallyEvaluatedType extends PyUnionType {
|
||||
@Override
|
||||
public String getName() {
|
||||
PyType res = excludeNull();
|
||||
return res != null ? res.getName() : "unknown";
|
||||
return res != null ? res.getName() : PyNames.UNKNOWN_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.jetbrains.python.psi.types;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
@@ -7,6 +8,7 @@ import com.jetbrains.python.psi.resolve.RatedResolveResult;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -35,8 +37,15 @@ public class PyFunctionType implements PyCallableType {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<PyType> getParameterTypes(@NotNull TypeEvalContext context) {
|
||||
return null;
|
||||
public List<Pair<String, PyType>> getParameters(@NotNull TypeEvalContext context) {
|
||||
final List<Pair<String, PyType>> result = new ArrayList<Pair<String, PyType>>();
|
||||
for (PyParameter parameter : myCallable.getParameterList().getParameters()) {
|
||||
if (parameter instanceof PyNamedParameter) {
|
||||
final PyNamedParameter namedParameter = (PyNamedParameter)parameter;
|
||||
result.add(Pair.create(getParameterName(namedParameter), context.getType(namedParameter)));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,4 +79,16 @@ public class PyFunctionType implements PyCallableType {
|
||||
public Callable getCallable() {
|
||||
return myCallable;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getParameterName(@NotNull PyNamedParameter namedParameter) {
|
||||
String name = namedParameter.getName();
|
||||
if (namedParameter.isPositionalContainer()) {
|
||||
name = "*" + name;
|
||||
}
|
||||
else if (namedParameter.isKeywordContainer()) {
|
||||
name = "**" + name;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public class PyGenericType implements PyType {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return myBound != null ? myName + " (" + myBound.getName() + ")" : myName;
|
||||
return myBound != null ? myName + " <= " + myBound.getName() : myName;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -42,9 +42,9 @@ public class PyTupleType extends PyClassTypeImpl implements PySubscriptableType
|
||||
return "(" + StringUtil.join(myElementTypes, new Function<PyType, String>() {
|
||||
@Nullable
|
||||
public String fun(PyType pyType) {
|
||||
return pyType == null ? "unknown" : pyType.getName();
|
||||
return pyType == null ? PyNames.UNKNOWN_TYPE : pyType.getName();
|
||||
}
|
||||
}, ",") + ")";
|
||||
}, ", ") + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.jetbrains.python.psi.types;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiPolyVariantReference;
|
||||
import com.intellij.psi.PsiReference;
|
||||
@@ -144,12 +145,15 @@ public class PyTypeChecker {
|
||||
final PyCallableType expectedCallable = (PyCallableType)expected;
|
||||
final PyCallableType actualCallable = (PyCallableType)actual;
|
||||
if (expectedCallable.isCallable() && actualCallable.isCallable()) {
|
||||
final List<PyType> expectedParameters = expectedCallable.getParameterTypes(context);
|
||||
final List<PyType> actualParameters = actualCallable.getParameterTypes(context);
|
||||
final List<Pair<String, PyType>> expectedParameters = expectedCallable.getParameters(context);
|
||||
final List<Pair<String, PyType>> actualParameters = actualCallable.getParameters(context);
|
||||
if (expectedParameters != null && actualParameters != null) {
|
||||
final int size = Math.min(expectedParameters.size(), actualParameters.size());
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (!match(expectedParameters.get(i), actualParameters.get(i), context, substitutions, recursive)) {
|
||||
final Pair<String, PyType> expectedParam = expectedParameters.get(i);
|
||||
final Pair<String, PyType> actualParam = actualParameters.get(i);
|
||||
// TODO: Check named and star params, not only positional ones
|
||||
if (!match(expectedParam.getSecond(), actualParam.getSecond(), context, substitutions, recursive)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -228,6 +232,18 @@ public class PyTypeChecker {
|
||||
collectGenerics(tuple.getElementType(i), context, collected, visited);
|
||||
}
|
||||
}
|
||||
else if (type instanceof PyCallableType) {
|
||||
final PyCallableType callable = (PyCallableType)type;
|
||||
final List<Pair<String, PyType>> parameters = callable.getParameters(context);
|
||||
if (parameters != null) {
|
||||
for (Pair<String, PyType> parameter : parameters) {
|
||||
if (parameter != null) {
|
||||
collectGenerics(parameter.getSecond(), context, collected, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
collectGenerics(callable.getCallType(context, null), context, collected, visited);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -262,6 +278,19 @@ public class PyTypeChecker {
|
||||
}
|
||||
return new PyTupleType((PyTupleType)type, results.toArray(new PyType[results.size()]));
|
||||
}
|
||||
else if (type instanceof PyCallableType) {
|
||||
final PyCallableType callable = (PyCallableType)type;
|
||||
List<Pair<String, PyType>> substParams = null;
|
||||
final List<Pair<String, PyType>> parameters = callable.getParameters(context);
|
||||
if (parameters != null) {
|
||||
substParams = new ArrayList<Pair<String, PyType>>();
|
||||
for (Pair<String, PyType> parameter : parameters) {
|
||||
substParams.add(Pair.create(parameter.getFirst(), substitute(parameter.getSecond(), substitutions, context)));
|
||||
}
|
||||
}
|
||||
final PyType substResult = substitute(callable.getCallType(context, null), substitutions, context);
|
||||
return new PyCallableTypeImpl(substParams, substResult);
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ public class PyTypeParser {
|
||||
new Function<Pair<Pair<ParseResult, List<ParseResult>>, ParseResult>, ParseResult>() {
|
||||
@Override
|
||||
public ParseResult fun(Pair<Pair<ParseResult, List<ParseResult>>, ParseResult> value) {
|
||||
final List<PyType> parameterTypes = new ArrayList<PyType>();
|
||||
final List<Pair<String, PyType>> parameters = new ArrayList<Pair<String, PyType>>();
|
||||
final ParseResult returnResult = value.getSecond();
|
||||
ParseResult result;
|
||||
final Pair<ParseResult, List<ParseResult>> firstPair = value.getFirst();
|
||||
@@ -238,17 +238,17 @@ public class PyTypeParser {
|
||||
final ParseResult first = firstPair.getFirst();
|
||||
final List<ParseResult> second = firstPair.getSecond();
|
||||
result = first;
|
||||
parameterTypes.add(first.getType());
|
||||
parameters.add(Pair.<String, PyType>create(null, first.getType()));
|
||||
for (ParseResult r : second) {
|
||||
result = result.merge(r);
|
||||
parameterTypes.add(r.getType());
|
||||
parameters.add(Pair.<String, PyType>create(null, r.getType()));
|
||||
}
|
||||
result = result.merge(returnResult);
|
||||
}
|
||||
else {
|
||||
result = returnResult;
|
||||
}
|
||||
return result.withType(new PyCallableTypeImpl(parameterTypes, returnResult.getType()));
|
||||
return result.withType(new PyCallableTypeImpl(parameters, returnResult.getType()));
|
||||
}
|
||||
})
|
||||
.named("callable-expr");
|
||||
@@ -449,7 +449,7 @@ public class PyTypeParser {
|
||||
final String name = token.getText().toString();
|
||||
final TextRange range = token.getRange();
|
||||
|
||||
if ("unknown".equals(name)) {
|
||||
if (PyNames.UNKNOWN_TYPE.equals(name)) {
|
||||
return EMPTY_RESULT;
|
||||
}
|
||||
else if (PyNames.NONE.equals(name)) {
|
||||
|
||||
@@ -53,11 +53,11 @@ public class PyUnionType implements PyType {
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "one of (" + StringUtil.join(myMembers, new NullableFunction<PyType, String>() {
|
||||
public String fun(PyType pyType) {
|
||||
return pyType == null ? "unknown" : pyType.getName();
|
||||
return StringUtil.join(myMembers, new NullableFunction<PyType, String>() {
|
||||
public String fun(PyType type) {
|
||||
return type != null ? type.getName() : null;
|
||||
}
|
||||
}, ", ") + ")";
|
||||
}, " | ");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1 +1 @@
|
||||
<warning descr="'(int,int)' object is not callable">(1,2)()</warning>
|
||||
<warning descr="'(int, int)' object is not callable">(1,2)()</warning>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
def test():
|
||||
def f(x):
|
||||
"""
|
||||
:type x: T <= int or str
|
||||
:type x: T <= int | str
|
||||
:rtype: T
|
||||
"""
|
||||
pass
|
||||
|
||||
x = f(10)
|
||||
y = f('foo')
|
||||
z = f(<warning descr="Expected type 'T (one of (int, str))', got 'list' instead">[]</warning>)
|
||||
return x + <warning descr="Expected type 'one of (int, long, float, complex)', got 'str' instead">y</warning>
|
||||
z = f(<warning descr="Expected type 'T <= int | str', got 'list' instead">[]</warning>)
|
||||
return x + <warning descr="Expected type 'int | long | float | complex', got 'str' instead">y</warning>
|
||||
|
||||
@@ -9,4 +9,4 @@ def test():
|
||||
<warning descr="Expected type 'Number', got 'unicode' instead">u'bar'</warning>)
|
||||
pow(False, True)
|
||||
round(False,
|
||||
<warning descr="Expected type 'one of (Real, None)', got 'str' instead">'foo'</warning>)
|
||||
<warning descr="Expected type 'Real | None', got 'str' instead">'foo'</warning>)
|
||||
|
||||
@@ -5,4 +5,4 @@ def test_dict_generics(d):
|
||||
xs = d.items()
|
||||
d2 = dict(xs)
|
||||
for k, v in d2.items():
|
||||
print k + <warning descr="Expected type 'one of (int, long, float, complex)', got 'unicode' instead">v</warning>
|
||||
print k + <warning descr="Expected type 'int | long | float | complex', got 'unicode' instead">v</warning>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
def test():
|
||||
xs = {'foo': 1, 'bar': 2}
|
||||
for v in xs.values():
|
||||
print(v + <warning descr="Expected type 'one of (int, long, float, complex)', got 'None' instead">None</warning>)
|
||||
print(v + <warning descr="Expected type 'int | long | float | complex', got 'None' instead">None</warning>)
|
||||
for k in xs.keys():
|
||||
print(k + <warning descr="Expected type 'one of (str, unicode)', got 'None' instead">None</warning>)
|
||||
print(k + <warning descr="Expected type 'str | unicode', got 'None' instead">None</warning>)
|
||||
for k in xs:
|
||||
print(k + <warning descr="Expected type 'one of (str, unicode)', got 'None' instead">None</warning>)
|
||||
print(k + <warning descr="Expected type 'str | unicode', got 'None' instead">None</warning>)
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
def test():
|
||||
def test(p1):
|
||||
for x in 'foo':
|
||||
pass
|
||||
|
||||
for x in <warning descr="Expected 'collections.Iterable', got 'int' instead">42</warning>:
|
||||
pass
|
||||
|
||||
for x in f('foo', p1):
|
||||
pass
|
||||
|
||||
|
||||
def f(c, x):
|
||||
if c:
|
||||
return 10
|
||||
else:
|
||||
return x
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
def func(f, seq):
|
||||
"""
|
||||
:param f: my param
|
||||
:type f: (unknown) -> str
|
||||
:rtype: list[str]
|
||||
"""
|
||||
return [f(v) for v in seq]
|
||||
|
||||
|
||||
def f(x):
|
||||
return int(x)
|
||||
|
||||
|
||||
def test():
|
||||
for item in func(<warning descr="Expected type '(unknown) -> str', got '(x: unknown) -> int' instead">f</warning>, []):
|
||||
pass
|
||||
|
||||
for item in func(<warning descr="Expected type '(unknown) -> str', got 'int' instead">int</warning>, []):
|
||||
pass
|
||||
|
||||
for item in func(<warning descr="Expected type '(unknown) -> str', got '(x: unknown) -> int' instead">lambda x: int(x)</warning>, []):
|
||||
pass
|
||||
|
||||
for item in func(lambda x: str(x), []):
|
||||
pass
|
||||
|
||||
for item in func(str, []):
|
||||
pass
|
||||
@@ -79,19 +79,19 @@ def test():
|
||||
return xs
|
||||
return [
|
||||
''.join(gen(10)),
|
||||
f_1(<warning descr="Expected type 'list of int', got '__generator of str' instead">gen(11)</warning>),
|
||||
f_2(<warning descr="Expected type 'Sequence of int', got '__generator of str' instead">gen(11)</warning>),
|
||||
f_3(<warning descr="Expected type 'Container of int', got '__generator of str' instead">gen(11)</warning>),
|
||||
f_4(<warning descr="Expected type 'Iterator of int', got '__generator of str' instead">gen(11)</warning>),
|
||||
f_5(<warning descr="Expected type 'Iterable of int', got '__generator of str' instead">gen(11)</warning>),
|
||||
f_6(<warning descr="Expected type 'list', got '__generator of str' instead">gen(11)</warning>),
|
||||
f_7(<warning descr="Expected type 'Sequence', got '__generator of str' instead">gen(11)</warning>),
|
||||
f_8(<warning descr="Expected type 'Container', got '__generator of str' instead">gen(11)</warning>),
|
||||
f_1(<warning descr="Expected type 'list[int]', got '__generator[str]' instead">gen(11)</warning>),
|
||||
f_2(<warning descr="Expected type 'Sequence[int]', got '__generator[str]' instead">gen(11)</warning>),
|
||||
f_3(<warning descr="Expected type 'Container[int]', got '__generator[str]' instead">gen(11)</warning>),
|
||||
f_4(<warning descr="Expected type 'Iterator[int]', got '__generator[str]' instead">gen(11)</warning>),
|
||||
f_5(<warning descr="Expected type 'Iterable[int]', got '__generator[str]' instead">gen(11)</warning>),
|
||||
f_6(<warning descr="Expected type 'list', got '__generator[str]' instead">gen(11)</warning>),
|
||||
f_7(<warning descr="Expected type 'Sequence', got '__generator[str]' instead">gen(11)</warning>),
|
||||
f_8(<warning descr="Expected type 'Container', got '__generator[str]' instead">gen(11)</warning>),
|
||||
f_9(gen(11)),
|
||||
f_10(gen(11)),
|
||||
f_11(<warning descr="Expected type 'list of one of (str, unicode)', got '__generator of str' instead">gen(11)</warning>),
|
||||
f_12(<warning descr="Expected type 'Sequence of one of (str, unicode)', got '__generator of str' instead">gen(11)</warning>),
|
||||
f_13(<warning descr="Expected type 'Container of one of (str, unicode)', got '__generator of str' instead">gen(11)</warning>),
|
||||
f_11(<warning descr="Expected type 'list[str | unicode]', got '__generator[str]' instead">gen(11)</warning>),
|
||||
f_12(<warning descr="Expected type 'Sequence[str | unicode]', got '__generator[str]' instead">gen(11)</warning>),
|
||||
f_13(<warning descr="Expected type 'Container[str | unicode]', got '__generator[str]' instead">gen(11)</warning>),
|
||||
f_14(gen(11)),
|
||||
f_15(gen(11)),
|
||||
f_15('foo'.split('o')),
|
||||
|
||||
@@ -20,7 +20,7 @@ def test_generic_user_class():
|
||||
self.x = value
|
||||
|
||||
c = User1(10)
|
||||
print(c.get() + <warning descr="Expected type 'one of (int, long, float, complex)', got 'str' instead">'foo'</warning>)
|
||||
print(c.get() + <warning descr="Expected type 'int | long | float | complex', got 'str' instead">'foo'</warning>)
|
||||
c.put(14)
|
||||
c.put(<weak_warning descr="Expected type 'int' (matched generic type 'T'), got 'str' instead">'foo'</weak_warning>)
|
||||
|
||||
|
||||
@@ -38,9 +38,9 @@ def test():
|
||||
|
||||
result = f1([1, 2, 3])
|
||||
print(result)
|
||||
print(result + <warning descr="Expected type 'one of (int, long, float, complex)', got 'str' instead">'foo'</warning>)
|
||||
print(result + <warning descr="Expected type 'int | long | float | complex', got 'str' instead">'foo'</warning>)
|
||||
|
||||
f2(1, <weak_warning descr="Expected type 'list of int' (matched generic type 'list of T'), got 'list of str' instead">['foo']</weak_warning>, 'bar')
|
||||
f2(1, <weak_warning descr="Expected type 'list[int]' (matched generic type 'list[T]'), got 'list[str]' instead">['foo']</weak_warning>, 'bar')
|
||||
|
||||
result = f3(1, 'foo', True)
|
||||
f4(<warning descr="Expected type '(bool,int,str)', got '(int,str,bool)' instead">result</warning>)
|
||||
f4(<warning descr="Expected type '(bool, int, str)', got '(int, str, bool)' instead">result</warning>)
|
||||
|
||||
@@ -7,5 +7,5 @@ def f(spam, eggs):
|
||||
|
||||
|
||||
def test():
|
||||
f(<warning descr="Expected type 'list of one of (str, unicode)', got 'list of int' instead">[1, 2, 3]</warning>,
|
||||
(<warning descr="Expected type '(bool,int,unicode)', got '(bool,int,str)' instead">False, 2, ''</warning>))
|
||||
f(<warning descr="Expected type 'list[str | unicode]', got 'list[int]' instead">[1, 2, 3]</warning>,
|
||||
(<warning descr="Expected type '(bool, int, unicode)', got '(bool, int, str)' instead">False, 2, ''</warning>))
|
||||
|
||||
@@ -5,4 +5,4 @@ def test():
|
||||
c = C()
|
||||
x = c.f()
|
||||
y = x
|
||||
return y + <warning descr="Expected type 'one of (int, long, float, complex)', got 'str' instead">'foo'</warning>
|
||||
return y + <warning descr="Expected type 'int | long | float | complex', got 'str' instead">'foo'</warning>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
def test():
|
||||
xs = map(lambda x: x + 1, [1, 2, 3])
|
||||
print('foo' + <warning descr="Expected type 'one of (str, unicode)', got 'int' instead">xs[0]</warning>)
|
||||
print('foo' + <warning descr="Expected type 'str | unicode', got 'int' instead">xs[0]</warning>)
|
||||
ys = map(str, iter([1, 2, 3]))
|
||||
print(1 + <warning descr="Expected type 'one of (int, long, float, complex)', got 'str' instead">ys[0]</warning>, 'bar' + ys[1])
|
||||
print(1 + <warning descr="Expected type 'int | long | float | complex', got 'str' instead">ys[0]</warning>, 'bar' + ys[1])
|
||||
|
||||
@@ -7,4 +7,4 @@ def f():
|
||||
return C()
|
||||
|
||||
def test():
|
||||
f().foo + <warning descr="Expected type 'one of (str, unicode)', got 'int' instead">1</warning>
|
||||
f().foo + <warning descr="Expected type 'str | unicode', got 'int' instead">1</warning>
|
||||
|
||||
@@ -5,5 +5,5 @@ class C(object):
|
||||
def test_right_operators():
|
||||
o = C()
|
||||
xs = [
|
||||
<warning descr="Expected type 'one of (int, long)', got 'C' instead">o</warning> * [],
|
||||
<warning descr="Expected type 'int | long', got 'C' instead">o</warning> * [],
|
||||
]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
def test():
|
||||
print('foo' + 'bar')
|
||||
print(2 + 3)
|
||||
print('foo' + <warning descr="Expected type 'one of (str, unicode)', got 'int' instead">3</warning>)
|
||||
print(3 + <warning descr="Expected type 'one of (int, long, float, complex)', got 'str' instead">'foo'</warning>)
|
||||
print('foo' + <warning descr="Expected type 'str | unicode', got 'int' instead">3</warning>)
|
||||
print(3 + <warning descr="Expected type 'int | long | float | complex', got 'str' instead">'foo'</warning>)
|
||||
print('foo' + 'bar' * 3)
|
||||
print('foo' + 3 * 'bar')
|
||||
print('foo' + <warning descr="Expected type 'one of (str, unicode)', got 'int' instead">2 * 3</warning>)
|
||||
print('foo' + <warning descr="Expected type 'str | unicode', got 'int' instead">2 * 3</warning>)
|
||||
|
||||
@@ -17,7 +17,7 @@ def test():
|
||||
"""
|
||||
x1 = f1(42)
|
||||
f2(x1) # Weaker union types
|
||||
f3(<warning descr="Expected type 'int', got 'one of (list, str, None)' instead">x1</warning>)
|
||||
f3(<warning descr="Expected type 'int', got 'list | str | None' instead">x1</warning>)
|
||||
|
||||
f2(<warning descr="Expected type 'str', got 'int' instead">x1.count('')</warning>)
|
||||
f3(x1.count(''))
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
variable "x"
|
||||
Inferred type: one of (str, int)
|
||||
Inferred type: str | int
|
||||
|
||||
@@ -1 +1 @@
|
||||
<html><body><small>Assigned to <code>y</code><br></small><code><br>Inferred type: one of (<a href="psi_element://#typename#int">int</a>, <a href="psi_element://#typename#str">str</a>)</code></body></html>
|
||||
<html><body><small>Assigned to <code>y</code><br></small><code><br>Inferred type: <a href="psi_element://#typename#int">int</a> | <a href="psi_element://#typename#str">str</a></code></body></html>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.jetbrains.python;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.jetbrains.python.fixtures.PyTestCase;
|
||||
import com.jetbrains.python.psi.types.*;
|
||||
|
||||
@@ -236,11 +237,11 @@ public class PyTypeParserTest extends PyTestCase {
|
||||
assertNotNull(callableType);
|
||||
final PyType returnType = callableType.getCallType(getTypeEvalContext(), null);
|
||||
assertInstanceOf(returnType, PyGenericType.class);
|
||||
final List<PyType> parameterTypes = callableType.getParameterTypes(getTypeEvalContext());
|
||||
final List<Pair<String, PyType>> parameterTypes = callableType.getParameters(getTypeEvalContext());
|
||||
assertNotNull(parameterTypes);
|
||||
assertEquals(2, parameterTypes.size());
|
||||
assertEquals("int", parameterTypes.get(0).getName());
|
||||
assertEquals("T", parameterTypes.get(1).getName());
|
||||
assertEquals("int", parameterTypes.get(0).getSecond().getName());
|
||||
assertEquals("T", parameterTypes.get(1).getSecond().getName());
|
||||
}
|
||||
|
||||
public void testCallableWithoutArgs() {
|
||||
@@ -252,7 +253,7 @@ public class PyTypeParserTest extends PyTestCase {
|
||||
final PyType returnType = callableType.getCallType(getTypeEvalContext(), null);
|
||||
assertNotNull(returnType);
|
||||
assertEquals("int", returnType.getName());
|
||||
final List<PyType> parameterTypes = callableType.getParameterTypes(getTypeEvalContext());
|
||||
final List<Pair<String, PyType>> parameterTypes = callableType.getParameters(getTypeEvalContext());
|
||||
assertNotNull(parameterTypes);
|
||||
assertEquals(0, parameterTypes.size());
|
||||
}
|
||||
|
||||
@@ -25,18 +25,18 @@ public class PyTypeTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void testBinaryExprType() {
|
||||
doTest("int or long or float or complex",
|
||||
doTest("int",
|
||||
"expr = 1 + 2");
|
||||
doTest("str or unicode",
|
||||
doTest("str | unicode",
|
||||
"expr = '1' + '2'");
|
||||
doTest("str or unicode",
|
||||
doTest("str",
|
||||
"expr = '%s' % ('a')");
|
||||
doTest("list",
|
||||
doTest("list[int]",
|
||||
"expr = [1] + [2]");
|
||||
}
|
||||
|
||||
public void testAssignmentChainBinaryExprType() {
|
||||
doTest("int or long or float or complex",
|
||||
doTest("int",
|
||||
"class C(object):\n" +
|
||||
" def __add__(self, other):\n" +
|
||||
" return -1\n" +
|
||||
@@ -56,7 +56,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void testUnionOfTuples() {
|
||||
doTest("(int or str, str or int)",
|
||||
doTest("(int | str, str | int)",
|
||||
"def x():\n" +
|
||||
" if True:\n" +
|
||||
" return (1, 'a')\n" +
|
||||
@@ -80,7 +80,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void testSet() {
|
||||
doTest("set of int",
|
||||
doTest("set[int]",
|
||||
"expr = {1, 2, 3}");
|
||||
}
|
||||
|
||||
@@ -112,10 +112,18 @@ public class PyTypeTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void testPropertyType() {
|
||||
doTest("unknown",
|
||||
doTest("property",
|
||||
"class C:\n" +
|
||||
" x = property(lambda self: object(), None, None)\n" +
|
||||
"expr = C.x");
|
||||
" x = property(lambda self: 'foo', None, None)\n" +
|
||||
"expr = C.x\n");
|
||||
}
|
||||
|
||||
public void testPropertyInstanceType() {
|
||||
doTest("str",
|
||||
"class C:\n" +
|
||||
" x = property(lambda self: 'foo', None, None)\n" +
|
||||
"c = C()\n" +
|
||||
"expr = c.x\n");
|
||||
}
|
||||
|
||||
public void testIterationType() {
|
||||
@@ -129,7 +137,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void testSliceType() {
|
||||
doTest("list of int",
|
||||
doTest("list[int]",
|
||||
"l = [1, 2, 3]; expr = l[0:1]");
|
||||
}
|
||||
|
||||
@@ -215,15 +223,12 @@ public class PyTypeTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void testUnknownTypeInUnion() {
|
||||
final String text = "def f(c, x):\n" +
|
||||
" if c:\n" +
|
||||
" return 1\n" +
|
||||
" return x\n" +
|
||||
"expr = f(1, g())\n";
|
||||
PyExpression expr = parseExpr(text);
|
||||
PyType t = getTypeEvalContext(expr).getType(expr);
|
||||
assertTrue(PyTypeChecker.isUnknown(t));
|
||||
doTest("int", text);
|
||||
doTest("int | unknown",
|
||||
"def f(c, x):\n" +
|
||||
" if c:\n" +
|
||||
" return 1\n" +
|
||||
" return x\n" +
|
||||
"expr = f(1, g())\n");
|
||||
}
|
||||
|
||||
public void testIsInstance() {
|
||||
@@ -341,7 +346,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
public void testYieldFromType() {
|
||||
PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON33);
|
||||
try {
|
||||
doTest("str or int or float",
|
||||
doTest("str | int | float",
|
||||
"def subgen():\n" +
|
||||
" for i in [1, 2, 3]:\n" +
|
||||
" yield i\n" +
|
||||
@@ -429,7 +434,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
|
||||
// PY-7215
|
||||
public void testFunctionWithNestedGenerator() {
|
||||
doTest("list of int",
|
||||
doTest("list[int]",
|
||||
"def f():\n" +
|
||||
" def g():\n" +
|
||||
" yield 10\n" +
|
||||
@@ -468,7 +473,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
|
||||
// EA-40207
|
||||
public void testRecursion() {
|
||||
doTest("list of list",
|
||||
doTest("list[list]",
|
||||
"def f():\n" +
|
||||
" return [f()]\n" +
|
||||
"expr = f()\n");
|
||||
@@ -533,7 +538,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void testLogicalAndExpression() {
|
||||
doTest("str or int",
|
||||
doTest("str | int",
|
||||
"expr = 'foo' and 2");
|
||||
}
|
||||
|
||||
@@ -552,16 +557,17 @@ public class PyTypeTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void testParameterFromUsages() {
|
||||
doTest("int",
|
||||
doTest("int | str | unknown",
|
||||
"def foo(bar):\n" +
|
||||
" expr = bar\n" +
|
||||
"def use_foo(x):\n" +
|
||||
" foo(x)\n" +
|
||||
" foo(3)\n");
|
||||
" foo(3)\n" +
|
||||
" foo('bar')\n");
|
||||
}
|
||||
|
||||
public void testUpperBoundGeneric() {
|
||||
doTest("int or str",
|
||||
doTest("int | str",
|
||||
"def foo(x):\n" +
|
||||
" '''\n" +
|
||||
" :type x: T <= int or str\n" +
|
||||
@@ -649,20 +655,11 @@ public class PyTypeTest extends PyTestCase {
|
||||
return myFixture.findElementByText("expr", PyExpression.class);
|
||||
}
|
||||
|
||||
private static String msg(PyType expected, PyType actual, TypeEvalContext context) {
|
||||
return String.format("Expected: %s, actual: %s",
|
||||
PythonDocumentationProvider.getTypeName(expected, context),
|
||||
PythonDocumentationProvider.getTypeName(actual, context));
|
||||
}
|
||||
|
||||
private void doTest(final String expectedType, final String text) {
|
||||
PyExpression expr = parseExpr(text);
|
||||
TypeEvalContext context = getTypeEvalContext(expr);
|
||||
PyType actual = context.getType(expr);
|
||||
PyType expected = PyTypeParser.getTypeByName(expr, expectedType);
|
||||
if (expected != null) {
|
||||
assertNotNull(context.printTrace(), actual);
|
||||
assertTrue(msg(expected, actual, context), PyTypeChecker.match(expected, actual, context));
|
||||
}
|
||||
final String actualType = PythonDocumentationProvider.getTypeName(actual, context);
|
||||
assertEquals(expectedType, actualType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,4 +198,9 @@ public class PyTypeCheckerInspectionTest extends PyTestCase {
|
||||
public void testMapReturnElementType() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-10413
|
||||
public void testFunctionParameterReturnType() {
|
||||
doTest();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user