Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ekaterina Tuzova
2013-08-01 17:12:28 +04:00
42 changed files with 341 additions and 154 deletions
+1 -1
View File
@@ -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
View File
@@ -1 +1 @@
<html><body><small>Assigned to <code>y</code><br></small><code><br>Inferred&nbsp;type:&nbsp;one&nbsp;of&nbsp;(<a href="psi_element://#typename#int">int</a>,&nbsp;<a href="psi_element://#typename#str">str</a>)</code></body></html>
<html><body><small>Assigned to <code>y</code><br></small><code><br>Inferred&nbsp;type:&nbsp;<a href="psi_element://#typename#int">int</a>&nbsp;|&nbsp;<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();
}
}