mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'function-types'
This commit is contained in:
@@ -10,14 +10,6 @@ __builtin__.open = \
|
||||
:type errors: string or None \n\
|
||||
:rtype: file \n\
|
||||
|
||||
__builtin__.open.1 = \
|
||||
:type mode: unicode \n\
|
||||
:rtype: io.TextIOWrapper of unicode \n\
|
||||
|
||||
__builtin__.open.2 = \
|
||||
:type mode: bytes \n\
|
||||
:rtype: io.FileIO of bytes \n\
|
||||
|
||||
|
||||
## 5.4. Numeric types
|
||||
|
||||
@@ -1291,8 +1283,8 @@ struct.Struct.unpack_from = \
|
||||
## 7.5. StringIO
|
||||
|
||||
StringIO.StringIO.__init__ = \
|
||||
:type buf: T \n\
|
||||
:rtype: StringIO of T (bytes or unicode) \n\
|
||||
:type buf: T <= bytes or unicode \n\
|
||||
:rtype: StringIO of T \n\
|
||||
|
||||
StringIO.StringIO.getvalue = \
|
||||
:rtype: T \n\
|
||||
@@ -1334,19 +1326,11 @@ StringIO.StringIO.__iter__ = \
|
||||
## 7.6. cStringIO
|
||||
|
||||
cStringIO.StringIO = \
|
||||
:type s: string \n\
|
||||
:rtype: cStringIO.OutputType of string \n\
|
||||
|
||||
cStringIO.StringIO.1 = \
|
||||
:type s: bytes \n\
|
||||
:rtype: cStringIO.OutputType of bytes \n\
|
||||
|
||||
cStringIO.StringIO.2 = \
|
||||
:type s: unicode \n\
|
||||
:rtype: cStringIO.OutputType of unicode \n\
|
||||
:type s: T <= bytes or unicode \n\
|
||||
:rtype: cStringIO.OutputType of T \n\
|
||||
|
||||
cStringIO.OutputType.__init__ = \
|
||||
:rtype: cStringIO.OutputType of T \n\
|
||||
:rtype: cStringIO.OutputType of T <= bytes or unicode \n\
|
||||
|
||||
cStringIO.OutputType.getvalue = \
|
||||
:rtype: T \n\
|
||||
@@ -1435,16 +1419,6 @@ datetime.date.__sub__ = \
|
||||
:type other: datetime.date or datetime.timedelta \n\
|
||||
:rtype: datetime.date or datetime.timedelta \n\
|
||||
|
||||
datetime.date.__sub__.1 = \
|
||||
:type y: datetime.date \n\
|
||||
:type other: datetime.date \n\
|
||||
:rtype: datetime.timedelta \n\
|
||||
|
||||
datetime.date.__sub__.2 = \
|
||||
:type y: datetime.timedelta \n\
|
||||
:type other: datetime.timedelta \n\
|
||||
:rtype: datetime.date \n\
|
||||
|
||||
datetime.date.__rsub__ = \
|
||||
:type y: datetime.date \n\
|
||||
:type other: datetime.date \n\
|
||||
@@ -1467,24 +1441,9 @@ datetime.ime.tzname = \
|
||||
:rtype: string \n\
|
||||
|
||||
datetime.timedelta.__add__ = \
|
||||
:type y: datetime.timedelta or datetime.date or datetime.datetime \n\
|
||||
:type other: datetime.timedelta or datetime.date or datetime.datetime \n\
|
||||
:rtype: datetime.timedelta or datetime.date or datetime.datetime \n\
|
||||
|
||||
datetime.timedelta.__add__.1 = \
|
||||
:type y: datetime.timedelta \n\
|
||||
:type other: datetime.timedelta \n\
|
||||
:rtype: datetime.timedelta \n\
|
||||
|
||||
datetime.timedelta.__add__.2 = \
|
||||
:type y: datetime.datetime \n\
|
||||
:type other: datetime.datetime \n\
|
||||
:rtype: datetime.datetime \n\
|
||||
|
||||
datetime.timedelta.__add__.3 = \
|
||||
:type y: datetime.date \n\
|
||||
:type other: datetime.date \n\
|
||||
:rtype: datetime.date \n\
|
||||
:type y: T <= datetime.timedelta or datetime.date or datetime.datetime \n\
|
||||
:type other: T <= datetime.timedelta or datetime.date or datetime.datetime \n\
|
||||
:rtype: T \n\
|
||||
|
||||
datetime.timedelta.__radd__ = \
|
||||
:type y: datetime.timedelta or datetime.date or datetime.datetime \n\
|
||||
@@ -1616,21 +1575,6 @@ datetime.datetime.__sub__ = \
|
||||
:type other: datetime.datetime or datetime.timedelta \n\
|
||||
:rtype: datetime.datetime or datetime.timedelta \n\
|
||||
|
||||
datetime.datetime.__sub__.1 = \
|
||||
:type y: datetime.datetime \n\
|
||||
:type other: datetime.datetime \n\
|
||||
:rtype: datetime.timedelta \n\
|
||||
|
||||
datetime.datetime.__sub__.2 = \
|
||||
:type y: datetime.timedelta \n\
|
||||
:type other: datetime.timedelta \n\
|
||||
:rtype: datetime.datetime \n\
|
||||
|
||||
datetime.datetime.__rsub__ = \
|
||||
:type y: datetime.datetime \n\
|
||||
:type other: datetime.datetime \n\
|
||||
:rtype: datetime.timedelta \n\
|
||||
|
||||
|
||||
## 8.3. collections
|
||||
|
||||
@@ -1892,52 +1836,20 @@ decimal.Decimal.__neg__ = \
|
||||
# 10.1. os.path
|
||||
|
||||
os.path.abspath = \
|
||||
:type path: bytes or unicode \n\
|
||||
:rtype: bytes or unicode \n\
|
||||
|
||||
os.path.abspath.1 = \
|
||||
:type path: bytes \n\
|
||||
:rtype: bytes \n\
|
||||
|
||||
os.path.abspath.2 = \
|
||||
:type path: unicode \n\
|
||||
:rtype: unicode \n\
|
||||
:type path: T <= bytes or unicode \n\
|
||||
:rtype: T \n\
|
||||
|
||||
os.path.basename = \
|
||||
:type p: bytes or unicode \n\
|
||||
:rtype: bytes or unicode \n\
|
||||
|
||||
os.path.basename.1 = \
|
||||
:type p: bytes \n\
|
||||
:rtype: bytes \n\
|
||||
|
||||
os.path.basename.2 = \
|
||||
:type p: unicode \n\
|
||||
:rtype: unicode \n\
|
||||
:type p: T <= bytes or unicode \n\
|
||||
:rtype: T \n\
|
||||
|
||||
os.path.commonprefix = \
|
||||
:type m: collections.Iterable of (bytes or unicode) \n\
|
||||
:rtype: bytes or unicode \n\
|
||||
|
||||
os.path.commonprefix.1 = \
|
||||
:type m: collections.Iterable of bytes \n\
|
||||
:rtype: bytes \n\
|
||||
|
||||
os.path.commonprefix.2 = \
|
||||
:type m: collections.Iterable of unicode \n\
|
||||
:rtype: unicode \n\
|
||||
:type m: collections.Iterable of T <= bytes or unicode \n\
|
||||
:rtype: T \n\
|
||||
|
||||
os.path.dirname = \
|
||||
:type p: bytes or unicode \n\
|
||||
:rtype: bytes or unicode \n\
|
||||
|
||||
os.path.dirname.1 = \
|
||||
:type p: bytes \n\
|
||||
:rtype: bytes \n\
|
||||
|
||||
os.path.dirname.2 = \
|
||||
:type p: unicode \n\
|
||||
:rtype: unicode \n\
|
||||
:type p: T <= bytes or unicode \n\
|
||||
:rtype: T \n\
|
||||
|
||||
os.path.exists = \
|
||||
:type path: bytes or unicode \n\
|
||||
@@ -1948,28 +1860,12 @@ os.path.lexists = \
|
||||
:rtype: bool \n\
|
||||
|
||||
os.path.expanduser = \
|
||||
:type path: bytes or unicode \n\
|
||||
:rtype: bytes or unicode \n\
|
||||
|
||||
os.path.expanduser.1 = \
|
||||
:type path: bytes \n\
|
||||
:rtype: bytes \n\
|
||||
|
||||
os.path.expanduser.2 = \
|
||||
:type path: unicode \n\
|
||||
:rtype: unicode \n\
|
||||
:type path: T <= bytes or unicode \n\
|
||||
:rtype: T \n\
|
||||
|
||||
os.path.expandvars = \
|
||||
:type path: bytes or unicode \n\
|
||||
:rtype: bytes or unicode \n\
|
||||
|
||||
os.path.expandvars.1 = \
|
||||
:type path: bytes \n\
|
||||
:rtype: bytes \n\
|
||||
|
||||
os.path.expandvars.2 = \
|
||||
:type path: unicode \n\
|
||||
:rtype: unicode \n\
|
||||
:type path: T <= bytes or unicode \n\
|
||||
:rtype: T \n\
|
||||
|
||||
os.path.getatime = \
|
||||
:type filename: bytes or unicode \n\
|
||||
@@ -2008,65 +1904,25 @@ os.path.ismount = \
|
||||
:rtype: bool \n\
|
||||
|
||||
os.path.join = \
|
||||
:type a: bytes or unicode \n\
|
||||
:rtype: bytes or unicode \n\
|
||||
|
||||
os.path.join.1 = \
|
||||
:type a: bytes \n\
|
||||
:rtype: bytes \n\
|
||||
|
||||
os.path.join.2 = \
|
||||
:type a: unicode \n\
|
||||
:rtype: unicode \n\
|
||||
:type a: T <= bytes or unicode \n\
|
||||
:rtype: T \n\
|
||||
|
||||
os.path.normcase = \
|
||||
:type s: bytes or unicode \n\
|
||||
:rtype: bytes or unicode \n\
|
||||
|
||||
os.path.normcase.1 = \
|
||||
:type s: bytes \n\
|
||||
:rtype: bytes \n\
|
||||
|
||||
os.path.normcase.2 = \
|
||||
:type s: unicode \n\
|
||||
:rtype: unicode \n\
|
||||
:type s: T <= bytes or unicode \n\
|
||||
:rtype: T \n\
|
||||
|
||||
os.path.normpath = \
|
||||
:type path: bytes or unicode \n\
|
||||
:rtype: bytes or unicode \n\
|
||||
|
||||
os.path.normpath.1 = \
|
||||
:type path: bytes \n\
|
||||
:rtype: bytes \n\
|
||||
|
||||
os.path.normpath.2 = \
|
||||
:type path: unicode \n\
|
||||
:rtype: unicode \n\
|
||||
:type path: T <= bytes or unicode \n\
|
||||
:rtype: T \n\
|
||||
|
||||
os.path.realpath = \
|
||||
:type filename: bytes or unicode \n\
|
||||
:type filename: T <= bytes or unicode \n\
|
||||
:rtype: bytes or unicode \n\
|
||||
|
||||
os.path.realpath.1 = \
|
||||
:type filename: bytes \n\
|
||||
:rtype: bytes \n\
|
||||
|
||||
os.path.realpath.2 = \
|
||||
:type filename: unicode \n\
|
||||
:rtype: unicode \n\
|
||||
|
||||
os.path.relpath = \
|
||||
:type path: bytes or unicode \n\
|
||||
:type path: T <= bytes or unicode \n\
|
||||
:type start: bytes or unicode \n\
|
||||
:rtype: bytes or unicode \n\
|
||||
|
||||
os.path.relpath.1 = \
|
||||
:type path: bytes \n\
|
||||
:rtype: bytes \n\
|
||||
|
||||
os.path.relpath.2 = \
|
||||
:type path: unicode \n\
|
||||
:rtype: unicode \n\
|
||||
:rtype: T \n\
|
||||
|
||||
os.path.samefile = \
|
||||
:type f1: bytes or unicode \n\
|
||||
@@ -2084,52 +1940,20 @@ os.path.samestat = \
|
||||
:rtype: bool \n\
|
||||
|
||||
os.path.split = \
|
||||
:type p: bytes or unicode \n\
|
||||
:rtype: (bytes or unicode, bytes or unicode) \n\
|
||||
|
||||
os.path.split.1 = \
|
||||
:type p: bytes \n\
|
||||
:rtype: (bytes, bytes) \n\
|
||||
|
||||
os.path.split.2 = \
|
||||
:type p: unicode \n\
|
||||
:rtype: (unicode, unicode) \n\
|
||||
:type p: T <= bytes or unicode \n\
|
||||
:rtype: (T, T) \n\
|
||||
|
||||
os.path.splitdrive = \
|
||||
:type p: bytes or unicode \n\
|
||||
:rtype: (bytes or unicode, bytes or unicode) \n\
|
||||
|
||||
os.path.splitdrive.1 = \
|
||||
:type p: bytes \n\
|
||||
:rtype: (bytes, bytes) \n\
|
||||
|
||||
os.path.splitdrive.2 = \
|
||||
:type p: unicode \n\
|
||||
:rtype: (unicode, unicode) \n\
|
||||
:type p: T <= bytes or unicode \n\
|
||||
:rtype: (T, T) \n\
|
||||
|
||||
os.path.splitext = \
|
||||
:type p: bytes or unicode \n\
|
||||
:rtype: (bytes or unicode, bytes or unicode) \n\
|
||||
|
||||
os.path.splitext.1 = \
|
||||
:type p: bytes \n\
|
||||
:rtype: (bytes, bytes) \n\
|
||||
|
||||
os.path.splitext.2 = \
|
||||
:type p: unicode \n\
|
||||
:rtype: (unicode, unicode) \n\
|
||||
:type p: T <= bytes or unicode \n\
|
||||
:rtype: (T, T) \n\
|
||||
|
||||
os.path.splitunc = \
|
||||
:type p: bytes or unicode \n\
|
||||
:rtype: (bytes or unicode, bytes or unicode) \n\
|
||||
|
||||
os.path.splitunc.1 = \
|
||||
:type p: bytes \n\
|
||||
:rtype: (bytes, bytes) \n\
|
||||
|
||||
os.path.splitunc.2 = \
|
||||
:type p: unicode \n\
|
||||
:rtype: (unicode, unicode) \n\
|
||||
:type p: T <= bytes or unicode \n\
|
||||
:rtype: (T, T) \n\
|
||||
|
||||
os.path.walk = \
|
||||
:type top: bytes or unicode \n\
|
||||
@@ -2345,14 +2169,6 @@ os.fdopen = \
|
||||
:type bufsize: int \n\
|
||||
:rtype: file \n\
|
||||
|
||||
os.fdopen.1 = \
|
||||
:type mode: unicode \n\
|
||||
:rtype: io.TextIOWrapper of unicode \n\
|
||||
|
||||
os.fdopen.2 = \
|
||||
:type mode: bytes \n\
|
||||
:rtype: io.FileIO of bytes \n\
|
||||
|
||||
os.popen = \
|
||||
:type command: string \n\
|
||||
:type mode: string \n\
|
||||
@@ -2525,12 +2341,8 @@ os.link = \
|
||||
:rtype: None \n\
|
||||
|
||||
os.listdir = \
|
||||
:type path: bytes or unicode \n\
|
||||
:rtype: list of string \n\
|
||||
|
||||
os.listdir.1 = \
|
||||
:type path: unicode \n\
|
||||
:rtype: list of unicode \n\
|
||||
:type path: T <= bytes or unicode \n\
|
||||
:rtype: list of T \n\
|
||||
|
||||
os.lstat = \
|
||||
:type path: bytes or unicode \n\
|
||||
@@ -2575,12 +2387,8 @@ os.pathconf = \
|
||||
:type name: int or string \n\
|
||||
|
||||
os.readlink = \
|
||||
:type path: bytes or unicode \n\
|
||||
:rtype: string \n\
|
||||
|
||||
os.readlink.1 = \
|
||||
:type path: unicode \n\
|
||||
:rtype: unicode \n\
|
||||
:type path: T <= bytes or unicode \n\
|
||||
:rtype: T \n\
|
||||
|
||||
os.remove = \
|
||||
:type path: bytes or unicode \n\
|
||||
@@ -2640,22 +2448,10 @@ os.utime = \
|
||||
:rtype: None \n\
|
||||
|
||||
os.walk = \
|
||||
:type top: bytes or unicode \n\
|
||||
:type top: T <= bytes or unicode \n\
|
||||
:type topdown: bool \n\
|
||||
:type followlinks: bool \n\
|
||||
:rtype: collections.Iterable of (string, list of string, list of string) \n\
|
||||
|
||||
os.walk.1 = \
|
||||
:type top: bytes \n\
|
||||
:type topdown: bool \n\
|
||||
:type followlinks: bool \n\
|
||||
:rtype: collections.Iterable of (bytes, list of bytes, list of bytes) \n\
|
||||
|
||||
os.walk.2 = \
|
||||
:type top: unicode \n\
|
||||
:type topdown: bool \n\
|
||||
:type followlinks: bool \n\
|
||||
:rtype: collections.Iterable of (unicode, list of unicode, list of unicode) \n\
|
||||
:rtype: collections.Iterable of (T, list of T, list of T) \n\
|
||||
|
||||
os.execl = \
|
||||
:type file: bytes or unicode \n\
|
||||
@@ -2836,14 +2632,6 @@ io.open = \
|
||||
:type errors: string or None \n\
|
||||
:rtype: file \n\
|
||||
|
||||
io.open.1 = \
|
||||
:type mode: unicode \n\
|
||||
:rtype: io.TextIOWrapper of unicode \n\
|
||||
|
||||
io.open.2 = \
|
||||
:type mode: bytes \n\
|
||||
:rtype: io.FileIO of bytes \n\
|
||||
|
||||
io.TextIOWrapper.__init__ = \
|
||||
:rtype: io.TextIOWrapper of T \n\
|
||||
|
||||
|
||||
@@ -96,6 +96,12 @@ public class PyJavaClassType implements PyClassLikeType {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<PyType> getParameterTypes(@NotNull TypeEvalContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefinition() {
|
||||
return myDefinition;
|
||||
|
||||
@@ -39,6 +39,12 @@ public class PyJavaMethodType implements PyCallableType {
|
||||
return PyJavaTypeProvider.asPyType(myMethod.getReturnType());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<PyType> getParameterTypes(@NotNull TypeEvalContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<? extends RatedResolveResult> resolveMember(@NotNull String name,
|
||||
|
||||
@@ -4,6 +4,8 @@ import com.jetbrains.python.psi.PyQualifiedExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A type instances of which can possibly be called. For example, a class definition can be called, and the result of a call is a class
|
||||
* instance.
|
||||
@@ -25,4 +27,12 @@ public interface PyCallableType extends PyType {
|
||||
*/
|
||||
@Nullable
|
||||
PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite);
|
||||
|
||||
/**
|
||||
* Returns the list of parameter types.
|
||||
*
|
||||
* @return list of positional parameters or null if not applicable.
|
||||
*/
|
||||
@Nullable
|
||||
List<PyType> getParameterTypes(@NotNull TypeEvalContext context);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
|
||||
@NotNull private Properties myStdlibTypes = new Properties();
|
||||
|
||||
private static final Set<String> OPEN_FUNCTIONS = ImmutableSet.of("__builtin__.open", "io.open", "os.fdopen");
|
||||
private static final String BINARY_FILE_TYPE = "io.FileIO[bytes]";
|
||||
private static final String TEXT_FILE_TYPE = "io.TextIOWrapper[unicode]";
|
||||
|
||||
@Nullable
|
||||
public static PyStdlibTypeProvider getInstance() {
|
||||
@@ -78,12 +80,12 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
|
||||
public PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) {
|
||||
final String qname = getQualifiedName(function, callSite);
|
||||
if (qname != null) {
|
||||
if (callSite != null) {
|
||||
PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCallSite(callSite, context);
|
||||
if (OPEN_FUNCTIONS.contains(qname) && callSite != null) {
|
||||
final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCallSite(callSite, context);
|
||||
if (results != null) {
|
||||
final PyType overloaded = getOverloadedReturnTypeByQName(results.getArguments(), qname, function, context);
|
||||
if (overloaded != null) {
|
||||
return overloaded;
|
||||
final PyType type = getOpenFunctionType(qname, results.getArguments(), callSite);
|
||||
if (type != null) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,56 +169,9 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PyType getOverloadedReturnTypeByQName(@NotNull Map<PyExpression, PyNamedParameter> arguments,
|
||||
@NotNull String qname,
|
||||
@NotNull PsiElement anchor,
|
||||
@NotNull TypeEvalContext context) {
|
||||
int i = 1;
|
||||
PyType rtype;
|
||||
do {
|
||||
final String overloadedQName = String.format("%s.%d", qname, i);
|
||||
rtype = getReturnTypeByQName(overloadedQName, anchor, context);
|
||||
if (rtype != null) {
|
||||
boolean matched = true;
|
||||
boolean notNullParameterMatch = false;
|
||||
// Special case for the 'mode' argument of the '*open()' functions
|
||||
if (OPEN_FUNCTIONS.contains(qname)) {
|
||||
matched = matchOpenFunctionType(qname, overloadedQName, arguments, anchor, context);
|
||||
notNullParameterMatch = true;
|
||||
}
|
||||
else {
|
||||
for (Map.Entry<PyExpression, PyNamedParameter> entry : arguments.entrySet()) {
|
||||
final PyNamedParameter p = entry.getValue();
|
||||
final String name = p.getName();
|
||||
if (p.isPositionalContainer() || p.isKeywordContainer() || name == null) {
|
||||
continue;
|
||||
}
|
||||
final PyType argType = context.getType(entry.getKey());
|
||||
final PyType paramType = getParameterTypeByQName(overloadedQName, name, anchor, context);
|
||||
if (PyTypeChecker.match(paramType, argType, context)) {
|
||||
if (paramType != null && !PyTypeChecker.isUnknown(argType)) {
|
||||
notNullParameterMatch = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
matched = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matched && notNullParameterMatch) {
|
||||
return rtype;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
} while (rtype != null);
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean matchOpenFunctionType(@NotNull String callQName,
|
||||
@NotNull String overloadedQName,
|
||||
@NotNull Map<PyExpression, PyNamedParameter> arguments,
|
||||
@NotNull PsiElement anchor, @NotNull TypeEvalContext context) {
|
||||
private static PyType getOpenFunctionType(@NotNull String callQName,
|
||||
@NotNull Map<PyExpression, PyNamedParameter> arguments,
|
||||
@NotNull PsiElement anchor) {
|
||||
String mode = "r";
|
||||
for (Map.Entry<PyExpression, PyNamedParameter> entry : arguments.entrySet()) {
|
||||
final PyNamedParameter parameter = entry.getValue();
|
||||
@@ -228,24 +183,20 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
}
|
||||
}
|
||||
final PyBuiltinCache cache = PyBuiltinCache.getInstance(anchor);
|
||||
final LanguageLevel level = LanguageLevel.forElement(anchor);
|
||||
final PyType paramType = getParameterTypeByQName(overloadedQName, "mode", anchor, context);
|
||||
final PyType argType;
|
||||
// Binary mode
|
||||
if (mode.contains("b")) {
|
||||
argType = cache.getBytesType(level);
|
||||
return PyTypeParser.getTypeByName(anchor, BINARY_FILE_TYPE);
|
||||
}
|
||||
// Text mode
|
||||
else {
|
||||
if (level.isPy3K() || "io.open".equals(callQName)) {
|
||||
argType = cache.getUnicodeType(level);
|
||||
return PyTypeParser.getTypeByName(anchor, TEXT_FILE_TYPE);
|
||||
}
|
||||
else {
|
||||
argType = cache.getBytesType(level);
|
||||
return PyTypeParser.getTypeByName(anchor, BINARY_FILE_TYPE);
|
||||
}
|
||||
}
|
||||
return PyTypeChecker.match(paramType, argType, context);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -220,6 +220,10 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl<PyNamedParame
|
||||
return PyTypeParser.getTypeByName(this, typeName);
|
||||
}
|
||||
}
|
||||
for(PyTypeProvider provider: Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
|
||||
PyType result = provider.getParameterType(this, func, context);
|
||||
if (result != null) return result;
|
||||
}
|
||||
if (context.maySwitchToAST(this)) {
|
||||
final PyExpression defaultValue = getDefaultValue();
|
||||
if (defaultValue != null) {
|
||||
@@ -229,10 +233,6 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl<PyNamedParame
|
||||
}
|
||||
}
|
||||
}
|
||||
for(PyTypeProvider provider: Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
|
||||
PyType result = provider.getParameterType(this, func, context);
|
||||
if (result != null) return result;
|
||||
}
|
||||
// Guess the type from file-local usages
|
||||
if (context.allowLocalUsages(this)) {
|
||||
final Ref<PyType> ref = Ref.create(null);
|
||||
|
||||
@@ -40,6 +40,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -314,58 +316,8 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp
|
||||
}
|
||||
}
|
||||
if (source != null && target != null) {
|
||||
PyType type = null;
|
||||
final PyType sourceType = context.getType(source);
|
||||
if (sourceType instanceof PyCollectionType) {
|
||||
type = ((PyCollectionType)sourceType).getElementType(context);
|
||||
if (sourceType instanceof PyClassType) {
|
||||
final PyClass cls = ((PyClassType)sourceType).getPyClass();
|
||||
if (cls != null && type instanceof PyTupleType && PyABCUtil.isSubclass(cls, PyNames.MAPPING)) {
|
||||
final PyTupleType mappingType = (PyTupleType)type;
|
||||
if (mappingType.getElementCount() == 2) {
|
||||
return mappingType.getElementType(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sourceType instanceof PyClassType) {
|
||||
final PyClass pyClass = ((PyClassType)sourceType).getPyClass();
|
||||
if (pyClass != null) {
|
||||
for (PyTypeProvider provider: Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
|
||||
final PyType iterType = provider.getIterationType(pyClass);
|
||||
if (iterType != null) {
|
||||
type = iterType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (PyABCUtil.isSubclass(pyClass, PyNames.ITERATOR)) {
|
||||
final PyFunction iter = pyClass.findMethodByName(PyNames.ITER, true);
|
||||
PyType iterMethodType = null;
|
||||
if (iter != null) {
|
||||
iterMethodType = getContextSensitiveType(iter, context, source);
|
||||
}
|
||||
if (iterMethodType instanceof PyCollectionType) {
|
||||
final PyCollectionType collectionType = (PyCollectionType)iterMethodType;
|
||||
type = collectionType.getElementType(context);
|
||||
}
|
||||
if (type == null) {
|
||||
PyFunction next = pyClass.findMethodByName(PyNames.NEXT, true);
|
||||
if (next == null) {
|
||||
next = pyClass.findMethodByName(PyNames.DUNDER_NEXT, true);
|
||||
}
|
||||
if (next != null) {
|
||||
type = getContextSensitiveType(next, context, source);
|
||||
}
|
||||
}
|
||||
if (type == null) {
|
||||
final PyFunction getItem = pyClass.findMethodByName(PyNames.GETITEM, true);
|
||||
if (getItem != null) {
|
||||
type = getContextSensitiveType(getItem, context, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final PyType type = getIterationType(sourceType, source, context);
|
||||
final PsiElement parent = getParent();
|
||||
if (type instanceof PyTupleType && parent instanceof PyTupleExpression) {
|
||||
return getTypeFromTupleAssignment((PyTupleExpression)parent, (PyTupleType)type);
|
||||
@@ -377,9 +329,71 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PyType getIterationType(@Nullable PyType iterableType, @Nullable PyExpression source, @NotNull TypeEvalContext context) {
|
||||
PyType result = null;
|
||||
if (iterableType instanceof PyCollectionType) {
|
||||
result = ((PyCollectionType)iterableType).getElementType(context);
|
||||
if (iterableType instanceof PyClassType) {
|
||||
final PyClass cls = ((PyClassType)iterableType).getPyClass();
|
||||
if (result instanceof PyTupleType && PyABCUtil.isSubclass(cls, PyNames.MAPPING)) {
|
||||
final PyTupleType mappingType = (PyTupleType)result;
|
||||
if (mappingType.getElementCount() == 2) {
|
||||
result = mappingType.getElementType(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (iterableType instanceof PyUnionType) {
|
||||
final Collection<PyType> members = ((PyUnionType)iterableType).getMembers();
|
||||
final List<PyType> iterationTypes = new ArrayList<PyType>();
|
||||
for (PyType member : members) {
|
||||
iterationTypes.add(getIterationType(member, source, context));
|
||||
}
|
||||
return PyUnionType.union(iterationTypes);
|
||||
}
|
||||
else if (iterableType instanceof PyClassType) {
|
||||
final PyClass pyClass = ((PyClassType)iterableType).getPyClass();
|
||||
for (PyTypeProvider provider: Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
|
||||
final PyType iterationType = provider.getIterationType(pyClass);
|
||||
if (iterationType != null) {
|
||||
result = iterationType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (PyABCUtil.isSubclass(pyClass, PyNames.ITERATOR)) {
|
||||
final PyFunction iterateMethod = pyClass.findMethodByName(PyNames.ITER, true);
|
||||
PyType iterateMethodType = null;
|
||||
if (iterateMethod != null) {
|
||||
iterateMethodType = getContextSensitiveType(iterateMethod, context, source);
|
||||
}
|
||||
if (iterateMethodType instanceof PyCollectionType) {
|
||||
final PyCollectionType collectionType = (PyCollectionType)iterateMethodType;
|
||||
result = collectionType.getElementType(context);
|
||||
}
|
||||
if (result == null) {
|
||||
PyFunction next = pyClass.findMethodByName(PyNames.NEXT, true);
|
||||
if (next == null) {
|
||||
next = pyClass.findMethodByName(PyNames.DUNDER_NEXT, true);
|
||||
}
|
||||
if (next != null) {
|
||||
result = getContextSensitiveType(next, context, source);
|
||||
}
|
||||
}
|
||||
if (result == null) {
|
||||
final PyFunction getItem = pyClass.findMethodByName(PyNames.GETITEM, true);
|
||||
if (getItem != null) {
|
||||
result = getContextSensitiveType(getItem, context, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PyType getContextSensitiveType(@NotNull PyFunction function, @NotNull TypeEvalContext context,
|
||||
@NotNull PyExpression source) {
|
||||
@Nullable PyExpression source) {
|
||||
if (function instanceof PyFunctionImpl) {
|
||||
return ((PyFunctionImpl)function).getReturnTypeWithoutCallSite(context, source);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.jetbrains.python.psi.types;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.jetbrains.python.psi.AccessDirection;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.PyQualifiedExpression;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import com.jetbrains.python.psi.resolve.RatedResolveResult;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author vlan
|
||||
*/
|
||||
public class PyCallableTypeImpl implements PyCallableType {
|
||||
@NotNull private final List<PyType> myParameterTypes;
|
||||
@Nullable private final PyType myReturnType;
|
||||
|
||||
public PyCallableTypeImpl(@NotNull List<PyType> parameterTypes, @Nullable PyType returnType) {
|
||||
myParameterTypes = parameterTypes;
|
||||
myReturnType = returnType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCallable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) {
|
||||
return myReturnType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<PyType> getParameterTypes(@NotNull TypeEvalContext context) {
|
||||
return myParameterTypes;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<? extends RatedResolveResult> resolveMember(@NotNull String name,
|
||||
@Nullable PyExpression location,
|
||||
@NotNull AccessDirection direction,
|
||||
@NotNull PyResolveContext resolveContext) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getCompletionVariants(String completionPrefix, PyExpression location, ProcessingContext context) {
|
||||
return new Object[0];
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getName() {
|
||||
return String.format("(%s) -> %s",
|
||||
StringUtil.join(myParameterTypes,
|
||||
new Function<PyType, String>() {
|
||||
@Override
|
||||
public String fun(PyType type) {
|
||||
return type != null ? type.getName() : "unknown";
|
||||
}
|
||||
},
|
||||
", "),
|
||||
myReturnType != null ? myReturnType.getName() : "unknown");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltin(TypeEvalContext context) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertValid(String message) {
|
||||
}
|
||||
}
|
||||
@@ -277,6 +277,12 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<PyType> getParameterTypes(@NotNull TypeEvalContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiElement resolveClassMember(@NotNull PyClass cls,
|
||||
boolean isDefinition,
|
||||
|
||||
@@ -33,6 +33,12 @@ public class PyFunctionType implements PyCallableType {
|
||||
return myCallable.getReturnType(context, callSite);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<PyType> getParameterTypes(@NotNull TypeEvalContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends RatedResolveResult> resolveMember(@NotNull String name,
|
||||
@Nullable PyExpression location,
|
||||
|
||||
@@ -26,6 +26,6 @@ import static com.jetbrains.python.psi.types.PyTypeTokenTypes.*;
|
||||
[\r\n]+ { return NL; }
|
||||
[\ \t] { return SPACE; }
|
||||
(":py"?":class:`"[~!]?)|("`")|([A-Z]"{")|("}") { return MARKUP; }
|
||||
("or")|("of")|("from")|("to")|[,\(\)\.\[\]|] { return OP; }
|
||||
("or")|("of")|("from")|("to")|("<=")|("->")|[,\(\)\.\[\]|] { return OP; }
|
||||
[T-Z] { return PARAMETER; }
|
||||
[A-Za-z_][A-Za-z_0-9]* { return IDENTIFIER; }
|
||||
|
||||
@@ -140,6 +140,27 @@ public class PyTypeChecker {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (actual instanceof PyCallableType && expected instanceof PyCallableType) {
|
||||
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);
|
||||
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)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!match(expectedCallable.getCallType(context, null), actualCallable.getCallType(context, null), context, substitutions,
|
||||
recursive)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
final String superName = expected.getName();
|
||||
final String subName = actual.getName();
|
||||
// TODO: No inheritance check for builtin numerics at this moment
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* The following code was generated by JFlex 1.4.3 on 7/19/13 2:41 PM */
|
||||
/* The following code was generated by JFlex 1.4.3 on 7/23/13 5:34 PM */
|
||||
|
||||
package com.jetbrains.python.psi.types;
|
||||
|
||||
@@ -11,7 +11,7 @@ import static com.jetbrains.python.psi.types.PyTypeTokenTypes.*;
|
||||
/**
|
||||
* This class is a scanner generated by
|
||||
* <a href="http://www.jflex.de/">JFlex</a> 1.4.3
|
||||
* on 7/19/13 2:41 PM from the specification file
|
||||
* on 7/23/13 5:34 PM from the specification file
|
||||
* <tt>/home/user/src/idea/tools/lexer/../../python/src/com/jetbrains/python/psi/types/PyType.flex</tt>
|
||||
*/
|
||||
public class PyTypeLexer implements FlexLexer {
|
||||
@@ -35,11 +35,12 @@ public class PyTypeLexer implements FlexLexer {
|
||||
* Translates characters to character classes
|
||||
*/
|
||||
private static final String ZZ_CMAP_PACKED =
|
||||
"\11\0\1\2\1\1\2\0\1\1\22\0\1\2\1\13\6\0\2\24"+
|
||||
"\2\0\1\24\1\0\1\24\1\0\12\27\1\3\6\0\23\14\7\25"+
|
||||
"\1\24\1\0\1\24\1\0\1\26\1\12\1\10\1\26\1\6\2\26"+
|
||||
"\1\21\5\26\1\7\1\22\1\26\1\17\1\4\1\26\1\20\1\11"+
|
||||
"\1\23\4\26\1\5\1\26\1\15\1\24\1\16\1\13\uff81\0";
|
||||
"\11\0\1\2\1\1\2\0\1\1\22\0\1\2\1\13\6\0\2\30"+
|
||||
"\2\0\1\30\1\26\1\30\1\0\12\33\1\3\1\0\1\24\1\25"+
|
||||
"\1\27\2\0\23\14\7\31\1\30\1\0\1\30\1\0\1\32\1\12"+
|
||||
"\1\10\1\32\1\6\2\32\1\21\5\32\1\7\1\22\1\32\1\17"+
|
||||
"\1\4\1\32\1\20\1\11\1\23\4\32\1\5\1\32\1\15\1\30"+
|
||||
"\1\16\1\13\uff81\0";
|
||||
|
||||
/**
|
||||
* Translates characters to character classes
|
||||
@@ -52,11 +53,12 @@ public class PyTypeLexer implements FlexLexer {
|
||||
private static final int [] ZZ_ACTION = zzUnpackAction();
|
||||
|
||||
private static final String ZZ_ACTION_PACKED_0 =
|
||||
"\1\0\1\1\1\2\1\0\1\3\1\4\4\3\1\5"+
|
||||
"\1\6\2\0\1\5\1\3\2\0\1\3\5\0\1\4";
|
||||
"\1\0\1\1\1\2\1\0\1\3\1\4\4\3\2\0"+
|
||||
"\1\5\1\6\2\0\1\5\1\3\2\0\1\3\5\0"+
|
||||
"\1\4";
|
||||
|
||||
private static int [] zzUnpackAction() {
|
||||
int [] result = new int[25];
|
||||
int [] result = new int[27];
|
||||
int offset = 0;
|
||||
offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
|
||||
return result;
|
||||
@@ -81,13 +83,13 @@ public class PyTypeLexer implements FlexLexer {
|
||||
private static final int [] ZZ_ROWMAP = zzUnpackRowMap();
|
||||
|
||||
private static final String ZZ_ROWMAP_PACKED_0 =
|
||||
"\0\0\0\30\0\60\0\110\0\140\0\60\0\170\0\220"+
|
||||
"\0\250\0\300\0\60\0\170\0\330\0\360\0\140\0\u0108"+
|
||||
"\0\u0120\0\u0138\0\u0150\0\u0168\0\u0180\0\u0198\0\u01b0\0\u01c8"+
|
||||
"\0\u01e0";
|
||||
"\0\0\0\34\0\70\0\124\0\160\0\70\0\214\0\250"+
|
||||
"\0\304\0\340\0\374\0\u0118\0\70\0\214\0\u0134\0\u0150"+
|
||||
"\0\160\0\u016c\0\u0188\0\u01a4\0\u01c0\0\u01dc\0\u01f8\0\u0214"+
|
||||
"\0\u0230\0\u024c\0\u0268";
|
||||
|
||||
private static int [] zzUnpackRowMap() {
|
||||
int [] result = new int[25];
|
||||
int [] result = new int[27];
|
||||
int offset = 0;
|
||||
offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
|
||||
return result;
|
||||
@@ -112,21 +114,22 @@ public class PyTypeLexer implements FlexLexer {
|
||||
private static final String ZZ_TRANS_PACKED_0 =
|
||||
"\1\0\1\2\1\3\1\4\6\5\1\6\1\0\1\7"+
|
||||
"\1\0\1\6\1\10\1\5\1\11\1\5\1\12\1\13"+
|
||||
"\1\14\1\5\2\0\1\2\62\0\1\15\1\0\1\16"+
|
||||
"\25\0\6\5\2\0\1\5\2\0\5\5\1\0\3\5"+
|
||||
"\4\0\6\5\2\0\1\5\1\6\1\0\5\5\1\0"+
|
||||
"\3\5\4\0\6\5\2\0\1\5\2\0\1\5\2\17"+
|
||||
"\2\5\1\0\3\5\4\0\6\5\2\0\1\5\2\0"+
|
||||
"\1\5\1\20\3\5\1\0\3\5\4\0\6\5\2\0"+
|
||||
"\1\5\2\0\1\17\4\5\1\0\3\5\5\0\1\21"+
|
||||
"\31\0\1\22\24\0\6\5\2\0\1\5\2\0\1\23"+
|
||||
"\4\5\1\0\3\5\3\0\1\24\34\0\1\25\23\0"+
|
||||
"\6\5\2\0\1\5\2\0\3\5\1\17\1\5\1\0"+
|
||||
"\3\5\6\0\1\16\32\0\1\26\27\0\1\27\21\0"+
|
||||
"\1\30\36\0\1\31\30\0\1\6\14\0";
|
||||
"\1\0\1\14\1\0\1\15\1\16\1\5\2\0\1\2"+
|
||||
"\72\0\1\17\1\0\1\20\31\0\6\5\2\0\1\5"+
|
||||
"\2\0\5\5\5\0\3\5\4\0\6\5\2\0\1\5"+
|
||||
"\1\6\1\0\5\5\5\0\3\5\4\0\6\5\2\0"+
|
||||
"\1\5\2\0\1\5\2\21\2\5\5\0\3\5\4\0"+
|
||||
"\6\5\2\0\1\5\2\0\1\5\1\22\3\5\5\0"+
|
||||
"\3\5\4\0\6\5\2\0\1\5\2\0\1\21\4\5"+
|
||||
"\5\0\3\5\25\0\1\15\35\0\1\15\11\0\1\23"+
|
||||
"\35\0\1\24\30\0\6\5\2\0\1\5\2\0\1\25"+
|
||||
"\4\5\5\0\3\5\3\0\1\26\40\0\1\27\27\0"+
|
||||
"\6\5\2\0\1\5\2\0\3\5\1\21\1\5\5\0"+
|
||||
"\3\5\6\0\1\20\36\0\1\30\33\0\1\31\25\0"+
|
||||
"\1\32\42\0\1\33\34\0\1\6\20\0";
|
||||
|
||||
private static int [] zzUnpackTrans() {
|
||||
int [] result = new int[504];
|
||||
int [] result = new int[644];
|
||||
int offset = 0;
|
||||
offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result);
|
||||
return result;
|
||||
@@ -167,11 +170,11 @@ public class PyTypeLexer implements FlexLexer {
|
||||
private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute();
|
||||
|
||||
private static final String ZZ_ATTRIBUTE_PACKED_0 =
|
||||
"\1\0\1\1\1\11\1\0\1\1\1\11\4\1\1\11"+
|
||||
"\1\1\2\0\2\1\2\0\1\1\5\0\1\1";
|
||||
"\1\0\1\1\1\11\1\0\1\1\1\11\4\1\2\0"+
|
||||
"\1\11\1\1\2\0\2\1\2\0\1\1\5\0\1\1";
|
||||
|
||||
private static int [] zzUnpackAttribute() {
|
||||
int [] result = new int[25];
|
||||
int [] result = new int[27];
|
||||
int offset = 0;
|
||||
offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
|
||||
return result;
|
||||
@@ -254,7 +257,7 @@ public class PyTypeLexer implements FlexLexer {
|
||||
char [] map = new char[0x10000];
|
||||
int i = 0; /* index in packed string */
|
||||
int j = 0; /* index in unpacked array */
|
||||
while (i < 98) {
|
||||
while (i < 106) {
|
||||
int count = packed.charAt(i++);
|
||||
char value = packed.charAt(i++);
|
||||
do map[j++] = value; while (--count > 0);
|
||||
|
||||
@@ -108,10 +108,11 @@ public class PyTypeParser {
|
||||
|
||||
final ForwardDeclaration<ParseResult, PyElementType> typeExpr = ForwardDeclaration.create();
|
||||
|
||||
final FunctionalParser<ParseResult, PyElementType> simpleType =
|
||||
final FunctionalParser<ParseResult, PyElementType> classType =
|
||||
token(IDENTIFIER).then(many(op(".").skipThen(token(IDENTIFIER))))
|
||||
.map(new MakeSimpleType(anchor))
|
||||
.named("simple-type");
|
||||
.cached()
|
||||
.named("class-type");
|
||||
|
||||
final FunctionalParser<ParseResult, PyElementType> tupleType =
|
||||
op("(").skipThen(typeExpr).then(many(op(",").skipThen(typeExpr))).thenSkip(op(")"))
|
||||
@@ -135,7 +136,7 @@ public class PyTypeParser {
|
||||
.named("tuple-type");
|
||||
|
||||
final FunctionalParser<ParseResult, PyElementType> typeParameter =
|
||||
token(PARAMETER).then(maybe(op("(").skipThen(typeExpr).thenSkip(op(")"))))
|
||||
token(PARAMETER).then(maybe(op("<=").skipThen(typeExpr)))
|
||||
.map(new Function<Pair<Token<PyElementType>, ParseResult>, ParseResult>() {
|
||||
@Override
|
||||
public ParseResult fun(Pair<Token<PyElementType>, ParseResult> value) {
|
||||
@@ -154,14 +155,13 @@ public class PyTypeParser {
|
||||
.named("type-parameter");
|
||||
|
||||
final FunctionalParser<ParseResult, PyElementType> simpleExpr =
|
||||
simpleType
|
||||
classType
|
||||
.or(tupleType)
|
||||
.or(typeParameter)
|
||||
.cached()
|
||||
.named("simple-expr");
|
||||
|
||||
final FunctionalParser<ParseResult, PyElementType> paramExpr =
|
||||
simpleExpr.thenSkip(op("[")).then(typeExpr).then(many(op(",").skipThen(typeExpr))).thenSkip(op("]"))
|
||||
classType.thenSkip(op("[")).then(typeExpr).then(many(op(",").skipThen(typeExpr))).thenSkip(op("]"))
|
||||
.map(new Function<Pair<Pair<ParseResult, ParseResult>, List<ParseResult>>, ParseResult>() {
|
||||
@Override
|
||||
public ParseResult fun(Pair<Pair<ParseResult, ParseResult>, List<ParseResult>> value) {
|
||||
@@ -187,7 +187,7 @@ public class PyTypeParser {
|
||||
return EMPTY_RESULT;
|
||||
}
|
||||
})
|
||||
.or(simpleExpr.thenSkip(op("of")).then(simpleExpr)
|
||||
.or(classType.thenSkip(op("of")).then(simpleExpr)
|
||||
.map(new Function<Pair<ParseResult, ParseResult>, ParseResult>() {
|
||||
@Override
|
||||
public ParseResult fun(Pair<ParseResult, ParseResult> value) {
|
||||
@@ -205,7 +205,7 @@ public class PyTypeParser {
|
||||
return EMPTY_RESULT;
|
||||
}
|
||||
}))
|
||||
.or(simpleExpr.thenSkip(op("from")).then(simpleExpr).thenSkip(op("to")).then(simpleExpr)
|
||||
.or(classType.thenSkip(op("from")).then(simpleExpr).thenSkip(op("to")).then(simpleExpr)
|
||||
.map(new Function<Pair<Pair<ParseResult, ParseResult>, ParseResult>, ParseResult>() {
|
||||
@Override
|
||||
public ParseResult fun(Pair<Pair<ParseResult, ParseResult>, ParseResult> value) {
|
||||
@@ -222,11 +222,45 @@ public class PyTypeParser {
|
||||
return EMPTY_RESULT;
|
||||
}
|
||||
}))
|
||||
.or(simpleExpr)
|
||||
.named("param-expr");
|
||||
|
||||
final FunctionalParser<ParseResult, PyElementType> callableExpr =
|
||||
op("(").skipThen(maybe(typeExpr.then(many(op(",").skipThen(typeExpr))))).thenSkip(op(")")).thenSkip(op("->")).then(typeExpr)
|
||||
.map(
|
||||
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 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;
|
||||
parameterTypes.add(first.getType());
|
||||
for (ParseResult r : second) {
|
||||
result = result.merge(r);
|
||||
parameterTypes.add(r.getType());
|
||||
}
|
||||
result = result.merge(returnResult);
|
||||
}
|
||||
else {
|
||||
result = returnResult;
|
||||
}
|
||||
return result.withType(new PyCallableTypeImpl(parameterTypes, returnResult.getType()));
|
||||
}
|
||||
})
|
||||
.named("callable-expr");
|
||||
|
||||
final FunctionalParser<ParseResult, PyElementType> singleExpr =
|
||||
paramExpr
|
||||
.or(callableExpr)
|
||||
.or(simpleExpr)
|
||||
.named("single-expr");
|
||||
|
||||
final FunctionalParser<ParseResult, PyElementType> unionExpr =
|
||||
paramExpr.then(many(op("or").or(op("|")).skipThen(paramExpr)))
|
||||
singleExpr.then(many(op("or").or(op("|")).skipThen(singleExpr)))
|
||||
.map(new Function<Pair<ParseResult, List<ParseResult>>, ParseResult>() {
|
||||
@Override
|
||||
public ParseResult fun(Pair<ParseResult, List<ParseResult>> value) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
def test():
|
||||
def f(x):
|
||||
"""
|
||||
:type x: T (int or str)
|
||||
:type x: T <= int or str
|
||||
:rtype: T
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -0,0 +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>)
|
||||
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])
|
||||
@@ -177,7 +177,7 @@ public class PyTypeParserTest extends PyTestCase {
|
||||
|
||||
public void testBoundedGeneric() {
|
||||
myFixture.configureByFile("typeParser/typeParser.py");
|
||||
final PyType type = PyTypeParser.getTypeByName(myFixture.getFile(), "T (str or unicode)");
|
||||
final PyType type = PyTypeParser.getTypeByName(myFixture.getFile(), "T <= str or unicode");
|
||||
assertNotNull(type);
|
||||
assertInstanceOf(type, PyGenericType.class);
|
||||
final PyGenericType genericType = (PyGenericType)type;
|
||||
@@ -227,4 +227,33 @@ public class PyTypeParserTest extends PyTestCase {
|
||||
assertClassType(list.get(1), "str");
|
||||
assertClassType(list.get(2), "unicode");
|
||||
}
|
||||
|
||||
public void testCallableType() {
|
||||
myFixture.configureByFile("typeParser/typeParser.py");
|
||||
final PyType type = PyTypeParser.getTypeByName(myFixture.getFile(), "(int, T) -> T");
|
||||
assertInstanceOf(type, PyCallableType.class);
|
||||
final PyCallableType callableType = (PyCallableType)type;
|
||||
assertNotNull(callableType);
|
||||
final PyType returnType = callableType.getCallType(getTypeEvalContext(), null);
|
||||
assertInstanceOf(returnType, PyGenericType.class);
|
||||
final List<PyType> parameterTypes = callableType.getParameterTypes(getTypeEvalContext());
|
||||
assertNotNull(parameterTypes);
|
||||
assertEquals(2, parameterTypes.size());
|
||||
assertEquals("int", parameterTypes.get(0).getName());
|
||||
assertEquals("T", parameterTypes.get(1).getName());
|
||||
}
|
||||
|
||||
public void testCallableWithoutArgs() {
|
||||
myFixture.configureByFile("typeParser/typeParser.py");
|
||||
final PyType type = PyTypeParser.getTypeByName(myFixture.getFile(), "() -> int");
|
||||
assertInstanceOf(type, PyCallableType.class);
|
||||
final PyCallableType callableType = (PyCallableType)type;
|
||||
assertNotNull(callableType);
|
||||
final PyType returnType = callableType.getCallType(getTypeEvalContext(), null);
|
||||
assertNotNull(returnType);
|
||||
assertEquals("int", returnType.getName());
|
||||
final List<PyType> parameterTypes = callableType.getParameterTypes(getTypeEvalContext());
|
||||
assertNotNull(parameterTypes);
|
||||
assertEquals(0, parameterTypes.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -564,7 +564,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
doTest("int or str",
|
||||
"def foo(x):\n" +
|
||||
" '''\n" +
|
||||
" :type x: T (int or str)\n" +
|
||||
" :type x: T <= int or str\n" +
|
||||
" :rtype: T\n" +
|
||||
" '''\n" +
|
||||
"def bar(x):\n" +
|
||||
@@ -582,6 +582,53 @@ public class PyTypeTest extends PyTestCase {
|
||||
" pass\n");
|
||||
}
|
||||
|
||||
public void testFunctionTypeAsUnificationArgument() {
|
||||
doTest("int",
|
||||
"def map2(f, xs):\n" +
|
||||
" '''\n" +
|
||||
" :type f: (T) -> V | None\n" +
|
||||
" :type xs: collections.Iterable[T] | bytes | unicode\n" +
|
||||
" :rtype: list[V] | bytes | unicode\n" +
|
||||
" '''\n" +
|
||||
" pass\n" +
|
||||
"\n" +
|
||||
"expr = map2(lambda x: 10, ['1', '2', '3'])[0]\n");
|
||||
}
|
||||
|
||||
public void testFunctionTypeAsUnificationResult() {
|
||||
doTest("int",
|
||||
"def f(x):\n" +
|
||||
" '''\n" +
|
||||
" :type x: T\n" +
|
||||
" :rtype: () -> T\n" +
|
||||
" '''\n" +
|
||||
" pass\n" +
|
||||
"\n" +
|
||||
"g = f(10)\n" +
|
||||
"expr = g()\n");
|
||||
}
|
||||
|
||||
public void testUnionIteration() {
|
||||
final String text = "def f(c):\n" +
|
||||
" if c < 0:\n" +
|
||||
" return [1, 2, 3]\n" +
|
||||
" elif c == 0:\n" +
|
||||
" return 0.0\n" +
|
||||
" else:\n" +
|
||||
" return 'foo'\n" +
|
||||
"\n" +
|
||||
"def g(c):\n" +
|
||||
" for expr in f(c):\n" +
|
||||
" pass\n";
|
||||
final PyExpression expr = parseExpr(text);
|
||||
final TypeEvalContext context = getTypeEvalContext(expr);
|
||||
final PyType type = context.getType(expr);
|
||||
assertInstanceOf(type, PyUnionType.class);
|
||||
assertTrue(PyTypeChecker.match(PyTypeParser.getTypeByName(expr, "int"), type, context));
|
||||
assertTrue(PyTypeChecker.match(PyTypeParser.getTypeByName(expr, "str"), type, context));
|
||||
assertTrue(PyTypeChecker.isUnknown(type));
|
||||
}
|
||||
|
||||
private static TypeEvalContext getTypeEvalContext(@NotNull PyExpression element) {
|
||||
return TypeEvalContext.userInitiated(element.getContainingFile()).withTracing();
|
||||
}
|
||||
|
||||
@@ -193,4 +193,9 @@ public class PyTypeCheckerInspectionTest extends PyTestCase {
|
||||
public void testForLoopIteration() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-4285
|
||||
public void testMapReturnElementType() {
|
||||
doTest();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user