From 1f721bbb791d2bfe38f702e94b2b5a26f39573f2 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 3 Mar 2014 12:34:02 +0400 Subject: [PATCH 01/13] Added PyCallableType.getReturnType() for forthcoming return types caching --- .../jetbrains/python/psi/impl/PyJavaClassType.java | 8 +++++++- .../jetbrains/python/psi/impl/PyJavaMethodType.java | 8 +++++++- .../jetbrains/python/psi/types/PyCallableType.java | 12 ++++++++---- .../python/psi/types/PyCallableTypeImpl.java | 7 +++++++ .../jetbrains/python/psi/types/PyClassTypeImpl.java | 8 +++++++- .../jetbrains/python/psi/types/PyFunctionType.java | 7 +++++++ 6 files changed, 43 insertions(+), 7 deletions(-) diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java index 02176e32c287..3c778d28540a 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java @@ -104,13 +104,19 @@ public class PyJavaClassType implements PyClassLikeType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getReturnType(@NotNull TypeEvalContext context) { if (myDefinition) { return new PyJavaClassType(myClass, false); } return null; } + @Nullable + @Override + public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + return getReturnType(context); + } + @Nullable @Override public List getParameters(@NotNull TypeEvalContext context) { diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java index dbcc7e2fc8c9..5b496c14a07a 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java @@ -52,10 +52,16 @@ public class PyJavaMethodType implements PyCallableType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getReturnType(@NotNull TypeEvalContext context) { return PyJavaTypeProvider.asPyType(myMethod.getReturnType()); } + @Nullable + @Override + public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + return getReturnType(context); + } + @Nullable @Override public List getParameters(@NotNull TypeEvalContext context) { diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java index 43261ddba84e..7292391ad4f8 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java @@ -34,11 +34,15 @@ public interface PyCallableType extends PyType { boolean isCallable(); /** - * Returns the type which is the result of calling an instance of this type. + * Returns the return type of a function independent of a call site. * - * @return the call result type or null if invalid. - * @param context - * @param callSite + * For example, it may return a generic type. + */ + @Nullable + PyType getReturnType(@NotNull TypeEvalContext context); + + /** + * Returns the type which is the result of calling an instance of this type. */ @Nullable PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite); diff --git a/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java index f417f5aa4c93..9c1d2a649263 100644 --- a/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java @@ -47,6 +47,13 @@ public class PyCallableTypeImpl implements PyCallableType { return true; } + @Nullable + @Override + public PyType getReturnType(@NotNull TypeEvalContext context) { + // TODO: Check that this return type doesn't depend on the call site for all PyCallableTypeImpl objects + return myReturnType; + } + @Nullable @Override public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index a63fd46bf3a7..fd1097918dcf 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -307,13 +307,19 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getReturnType(@NotNull TypeEvalContext context) { if (isDefinition()) { return new PyClassTypeImpl(getPyClass(), false); } return null; } + @Nullable + @Override + public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + return getReturnType(context); + } + @Nullable @Override public List getParameters(@NotNull TypeEvalContext context) { diff --git a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java index 5e0c35699067..c1e9f3046bc6 100644 --- a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java @@ -44,6 +44,13 @@ public class PyFunctionType implements PyCallableType { return true; } + @Nullable + @Override + public PyType getReturnType(@NotNull TypeEvalContext context) { + // TODO: Make Callable.getReturnType() call site independent, extract getCallType() + return myCallable.getReturnType(context, null); + } + @Nullable @Override public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { From ed026c0705c1bec35351420c59d0a3befe139f2a Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 3 Mar 2014 12:45:46 +0400 Subject: [PATCH 02/13] Renamed Callable.getReturnType() to getCallType() --- python/psi-api/src/com/jetbrains/python/psi/Callable.java | 4 ++-- .../codeInsight/override/PyOverrideImplementUtil.java | 2 +- .../userSkeletons/PyUserSkeletonsTypeProvider.java | 2 +- .../python/inspections/PyPropertyDefinitionInspection.java | 2 +- .../python/inspections/PyStringFormatInspection.java | 2 +- .../jetbrains/python/psi/impl/PyBinaryExpressionImpl.java | 2 +- .../jetbrains/python/psi/impl/PyCallExpressionHelper.java | 6 +++--- python/src/com/jetbrains/python/psi/impl/PyClassImpl.java | 2 +- .../src/com/jetbrains/python/psi/impl/PyFunctionImpl.java | 2 +- .../jetbrains/python/psi/impl/PyLambdaExpressionImpl.java | 2 +- .../com/jetbrains/python/psi/impl/PyNamedParameterImpl.java | 2 +- .../jetbrains/python/psi/impl/PyPrefixExpressionImpl.java | 2 +- .../python/psi/impl/PySubscriptionExpressionImpl.java | 2 +- .../jetbrains/python/psi/impl/PyTargetExpressionImpl.java | 2 +- .../src/com/jetbrains/python/psi/types/PyFunctionType.java | 4 ++-- .../src/com/jetbrains/python/psi/types/PyTypeChecker.java | 3 +-- 16 files changed, 20 insertions(+), 21 deletions(-) diff --git a/python/psi-api/src/com/jetbrains/python/psi/Callable.java b/python/psi-api/src/com/jetbrains/python/psi/Callable.java index 23a5ef7870b7..bade73381eae 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/Callable.java +++ b/python/psi-api/src/com/jetbrains/python/psi/Callable.java @@ -34,10 +34,10 @@ public interface Callable extends PyTypedElement, PyQualifiedNameOwner { PyParameterList getParameterList(); /** - * @return the type of returned value. + * Returns the type of the call to the callable. */ @Nullable - PyType getReturnType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite); + PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite); /** * @return a methods returns itself, non-method callables return null. diff --git a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java index 8783a7a16b58..a7fc0dc08d25 100644 --- a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java @@ -225,7 +225,7 @@ public class PyOverrideImplementUtil { statementBody.append(PyNames.PASS); } else { - if (!PyNames.INIT.equals(baseFunction.getName()) && baseFunction.getReturnType(context, null) != PyNoneType.INSTANCE) { + if (!PyNames.INIT.equals(baseFunction.getName()) && baseFunction.getCallType(context, null) != PyNoneType.INSTANCE) { statementBody.append("return "); } if (baseClass.isNewStyleClass()) { diff --git a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java index b900e28f93c0..c836e0919dde 100644 --- a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java @@ -46,7 +46,7 @@ public class PyUserSkeletonsTypeProvider extends PyTypeProviderBase { public PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { final PyFunction functionSkeleton = PyUserSkeletonsUtil.getUserSkeleton(function); if (functionSkeleton != null) { - return functionSkeleton.getReturnType(context, callSite); + return functionSkeleton.getCallType(context, callSite); } return null; } diff --git a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java index 967e6a47c26d..33d9b0bf20a1 100644 --- a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java @@ -301,7 +301,7 @@ public class PyPropertyDefinitionInspection extends PyInspection { } else { PyReferenceExpression callSite = being_checked instanceof PyReferenceExpression ? (PyReferenceExpression) being_checked : null; - hasReturns = !(callable.getReturnType(myTypeEvalContext, callSite) instanceof PyNoneType); + hasReturns = !(callable.getCallType(myTypeEvalContext, callSite) instanceof PyNoneType); } if (allowed ^ hasReturns) { if (allowed && callable instanceof PyFunction) { diff --git a/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java b/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java index 180fd1bfc3b0..280822ba7175 100644 --- a/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java @@ -149,7 +149,7 @@ public class PyStringFormatInspection extends PyInspection { } else if (rightExpression instanceof PyCallExpression) { final Callable callable = ((PyCallExpression)rightExpression).resolveCalleeFunction(resolveContext); - // TODO: Switch to Callable.getReturnType() + // TODO: Switch to Callable.getCallType() if (callable instanceof PyFunction && myTypeEvalContext.maySwitchToAST((PyFunction) callable)) { PyStatementList statementList = ((PyFunction)callable).getStatementList(); if (statementList == null) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java index bee876ac948d..61513d1e4c4f 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java @@ -137,7 +137,7 @@ public class PyBinaryExpressionImpl extends PyElementImpl implements PyBinaryExp } final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCall(this, context); if (results != null) { - final PyType type = results.getCallable().getReturnType(context, this); + final PyType type = results.getCallable().getCallType(context, this); if (!PyTypeChecker.isUnknown(type) && !(type instanceof PyNoneType)) { return type; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java index c32ec1ba1566..874190b84104 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java @@ -198,7 +198,7 @@ public class PyCallExpressionHelper { final PyFunction function = (PyFunction)resolved; final Property property = function.getProperty(); if (property != null && isQualifiedByInstance(function, qualifiers, context)) { - final PyType type = function.getReturnType(context, null); + final PyType type = function.getCallType(context, null); if (type instanceof PyFunctionType) { resolved = ((PyFunctionType)type).getCallable(); } @@ -424,7 +424,7 @@ public class PyCallExpressionHelper { } } if (init != null) { - final PyType t = init.getReturnType(context, (PyReferenceExpression)callee); + final PyType t = init.getCallType(context, (PyReferenceExpression)callee); if (cls != null) { if (init.getContainingClass() != cls) { if (t instanceof PyCollectionType) { @@ -453,7 +453,7 @@ public class PyCallExpressionHelper { } if (target instanceof Callable) { final Callable callable = (Callable)target; - return callable.getReturnType(context, (PyReferenceExpression)callee); + return callable.getCallType(context, (PyReferenceExpression)callee); } } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 516cb4704a95..b25ba2dbfa86 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -750,7 +750,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement if (!(callable instanceof StubBasedPsiElement) && !context.maySwitchToAST(callable)) { return null; } - return callable.getReturnType(context, null); + return callable.getCallType(context, null); } return null; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java index 2ffc8e6cba03..eeeb0b3c2228 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java @@ -176,7 +176,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp @Nullable @Override - public PyType getReturnType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { PyType type = getGenericReturnType(context, callSite); if (callSite == null) { return type; diff --git a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java index 56249f1fdfa4..3b318d4962a0 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java @@ -61,7 +61,7 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp @Nullable @Override - public PyType getReturnType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { final PyExpression body = getBody(); if (body != null) return context.getType(body); else return null; diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java index 6ad33d60569e..eeb3f9a0e3af 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java @@ -208,7 +208,7 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl Date: Mon, 3 Mar 2014 12:56:37 +0400 Subject: [PATCH 03/13] Renamed PyTypeProvider.getReturnType() to getCallType() --- .../src/com/jetbrains/python/psi/impl/PyTypeProvider.java | 2 +- .../src/com/jetbrains/python/psi/types/PyTypeProviderBase.java | 2 +- .../jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java | 2 +- python/src/com/jetbrains/pyqt/PyQtTypeProvider.java | 2 +- .../python/codeInsight/stdlib/PyStdlibTypeProvider.java | 2 +- .../codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java | 2 +- python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java b/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java index ff188f56c262..af0b38b6c519 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java +++ b/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java @@ -39,7 +39,7 @@ public interface PyTypeProvider { PyType getParameterType(@NotNull PyNamedParameter param, @NotNull PyFunction func, @NotNull TypeEvalContext context); @Nullable - PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context); + PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context); @Nullable PyType getContextManagerVariableType(PyClass contextManager, PyExpression withExpression, TypeEvalContext context); diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java index 6330c4a76a17..7f9a7cf44319 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java @@ -95,7 +95,7 @@ public class PyTypeProviderBase implements PyTypeProvider { } @Override - public PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { + public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { ReturnTypeDescriptor descriptor; synchronized (myMethodToReturnTypeMap) { descriptor = myMethodToReturnTypeMap.get(function.getName()); diff --git a/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java b/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java index 1048e53b5682..27207ab31136 100644 --- a/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java +++ b/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java @@ -67,7 +67,7 @@ public class NumpyDocStringTypeProvider extends PyTypeProviderBase { @Nullable @Override - public PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { + public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { if (isInsideNumPy(function)) { final NumPyDocString docString = NumPyDocString.forFunction(function, callSite); if (docString != null) { diff --git a/python/src/com/jetbrains/pyqt/PyQtTypeProvider.java b/python/src/com/jetbrains/pyqt/PyQtTypeProvider.java index d9d030c352cd..5e8ed0373d15 100644 --- a/python/src/com/jetbrains/pyqt/PyQtTypeProvider.java +++ b/python/src/com/jetbrains/pyqt/PyQtTypeProvider.java @@ -37,7 +37,7 @@ public class PyQtTypeProvider extends PyTypeProviderBase { private static final String ourQt4Signal = "pyqtSignal"; @Override - public PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { + public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { if (PyNames.INIT.equals(function.getName())) { final PyClass containingClass = function.getContainingClass(); if (containingClass != null && ourQt4Signal.equals(containingClass.getName())) { diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java index 9cdf4c30994a..d7678c2cd871 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java @@ -120,7 +120,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { @Nullable @Override - public PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { + public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { final String qname = getQualifiedName(function, callSite); if (qname != null) { if (OPEN_FUNCTIONS.contains(qname) && callSite != null) { diff --git a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java index c836e0919dde..4184bdf52800 100644 --- a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java @@ -43,7 +43,7 @@ public class PyUserSkeletonsTypeProvider extends PyTypeProviderBase { } @Override - public PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { + public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { final PyFunction functionSkeleton = PyUserSkeletonsUtil.getUserSkeleton(function); if (functionSkeleton != null) { return functionSkeleton.getCallType(context, callSite); diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java index eeeb0b3c2228..85aedba9dbd6 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java @@ -261,7 +261,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp } } for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { - final PyType returnType = typeProvider.getReturnType(this, callSite, typeEvalContext); + final PyType returnType = typeProvider.getCallType(this, callSite, typeEvalContext); if (returnType != null) { returnType.assertValid(typeProvider.toString()); return returnType; From f90ee78702b56ac95de57f4ca8cf130eafe2d49a Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 3 Mar 2014 13:39:21 +0400 Subject: [PATCH 04/13] Added Callable.getReturnType() and PyTypeProvider.getReturnType() As a side effect, switched to type-based class generics unification in constructors. --- .../com/jetbrains/python/psi/Callable.java | 6 ++ .../python/psi/impl/PyTypeProvider.java | 3 + .../python/psi/types/PyTypeProviderBase.java | 6 ++ .../com/jetbrains/pyqt/PyQtTypeProvider.java | 8 +-- .../PyUserSkeletonsTypeProvider.java | 9 +-- .../inspections/PyTypeCheckerInspection.java | 2 +- .../python/psi/impl/PyFunctionImpl.java | 65 +++++++++++-------- .../psi/impl/PyLambdaExpressionImpl.java | 11 +++- .../python/psi/types/PyTypeChecker.java | 32 +++++---- 9 files changed, 91 insertions(+), 51 deletions(-) diff --git a/python/psi-api/src/com/jetbrains/python/psi/Callable.java b/python/psi-api/src/com/jetbrains/python/psi/Callable.java index bade73381eae..b979b0deb79a 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/Callable.java +++ b/python/psi-api/src/com/jetbrains/python/psi/Callable.java @@ -33,6 +33,12 @@ public interface Callable extends PyTypedElement, PyQualifiedNameOwner { @NotNull PyParameterList getParameterList(); + /** + * Returns the return type of the callable independent of a call site. + */ + @Nullable + PyType getReturnType(@NotNull TypeEvalContext context); + /** * Returns the type of the call to the callable. */ diff --git a/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java b/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java index af0b38b6c519..5707005026cb 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java +++ b/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java @@ -38,6 +38,9 @@ public interface PyTypeProvider { @Nullable PyType getParameterType(@NotNull PyNamedParameter param, @NotNull PyFunction func, @NotNull TypeEvalContext context); + @Nullable + PyType getReturnType(@NotNull Callable callable, @NotNull TypeEvalContext context); + @Nullable PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context); diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java index 7f9a7cf44319..c27dc4bc04ed 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java @@ -94,6 +94,12 @@ public class PyTypeProviderBase implements PyTypeProvider { return null; } + @Nullable + @Override + public PyType getReturnType(@NotNull Callable callable, @NotNull TypeEvalContext context) { + return null; + } + @Override public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { ReturnTypeDescriptor descriptor; diff --git a/python/src/com/jetbrains/pyqt/PyQtTypeProvider.java b/python/src/com/jetbrains/pyqt/PyQtTypeProvider.java index 5e8ed0373d15..a57a4a528e0c 100644 --- a/python/src/com/jetbrains/pyqt/PyQtTypeProvider.java +++ b/python/src/com/jetbrains/pyqt/PyQtTypeProvider.java @@ -15,12 +15,11 @@ */ package com.jetbrains.pyqt; +import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.Callable; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFunction; -import com.jetbrains.python.psi.PyQualifiedExpression; -import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.psi.stubs.PyClassNameIndex; import com.jetbrains.python.psi.types.PyClassTypeImpl; import com.jetbrains.python.psi.types.PyType; @@ -37,8 +36,9 @@ public class PyQtTypeProvider extends PyTypeProviderBase { private static final String ourQt4Signal = "pyqtSignal"; @Override - public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { - if (PyNames.INIT.equals(function.getName())) { + public PyType getReturnType(@NotNull Callable callable, @NotNull TypeEvalContext context) { + if (PyNames.INIT.equals(callable.getName()) && callable instanceof PyFunction) { + final PyFunction function = (PyFunction)callable; final PyClass containingClass = function.getContainingClass(); if (containingClass != null && ourQt4Signal.equals(containingClass.getName())) { final String classQName = containingClass.getQualifiedName(); diff --git a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java index 4184bdf52800..6dbb63ad56da 100644 --- a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java @@ -42,11 +42,12 @@ public class PyUserSkeletonsTypeProvider extends PyTypeProviderBase { return null; } + @Nullable @Override - public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { - final PyFunction functionSkeleton = PyUserSkeletonsUtil.getUserSkeleton(function); - if (functionSkeleton != null) { - return functionSkeleton.getCallType(context, callSite); + public PyType getReturnType(@NotNull Callable callable, @NotNull TypeEvalContext context) { + final Callable callableSkeleton = PyUserSkeletonsUtil.getUserSkeleton(callable); + if (callableSkeleton != null) { + return callableSkeleton.getReturnType(context); } return null; } diff --git a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java index 45df382d3f83..d31d19ef4da9 100644 --- a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java @@ -102,7 +102,7 @@ public class PyTypeCheckerInspection extends PyInspection { } final PyType argType = myTypeEvalContext.getType(entry.getKey()); if (!genericsCollected) { - substitutions.putAll(PyTypeChecker.collectCallGenerics(results.getCallable(), results.getReceiver(), myTypeEvalContext)); + substitutions.putAll(PyTypeChecker.unifyReceiver(results.getReceiver(), myTypeEvalContext)); genericsCollected = true; } checkTypes(paramType, argType, entry.getKey(), myTypeEvalContext, substitutions); diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java index 85aedba9dbd6..26cb36fd9f8f 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java @@ -174,6 +174,40 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp return getStubOrPsiChild(PyElementTypes.DECORATOR_LIST); // PsiTreeUtil.getChildOfType(this, PyDecoratorList.class); } + @Nullable + @Override + public PyType getReturnType(@NotNull TypeEvalContext context) { + for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { + final PyType returnType = typeProvider.getReturnType(this, context); + if (returnType != null) { + returnType.assertValid(typeProvider.toString()); + return returnType; + } + } + if (context.maySwitchToAST(this) && LanguageLevel.forElement(this).isAtLeast(LanguageLevel.PYTHON30)) { + PyAnnotation anno = getAnnotation(); + if (anno != null) { + PyClass pyClass = anno.resolveToClass(); + if (pyClass != null) { + return new PyClassTypeImpl(pyClass, false); + } + } + } + final PyType docStringType = getReturnTypeFromDocString(); + if (docStringType != null) { + docStringType.assertValid("from docstring"); + return docStringType; + } + if (context.allowReturnTypes(this)) { + final Ref yieldTypeRef = getYieldStatementType(context); + if (yieldTypeRef != null) { + return yieldTypeRef.get(); + } + return getReturnStatementType(context); + } + return null; + } + @Nullable @Override public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { @@ -184,7 +218,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCallSite(callSite, context); if (PyTypeChecker.hasGenerics(type, context)) { if (results != null) { - final Map substitutions = PyTypeChecker.unifyGenericCall(this, results.getReceiver(), results.getArguments(), + final Map substitutions = PyTypeChecker.unifyGenericCall(results.getReceiver(), results.getArguments(), context); type = substitutions != null ? PyTypeChecker.substitute(type, substitutions, context) : null; } @@ -209,7 +243,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp @Nullable PyExpression receiver) { PyType type = getGenericReturnType(context, null); if (PyTypeChecker.hasGenerics(type, context)) { - final Map substitutions = PyTypeChecker.unifyGenericCall(this, receiver, + final Map substitutions = PyTypeChecker.unifyGenericCall(receiver, Maps.newHashMap(), context); if (substitutions != null) { @@ -250,36 +284,15 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp } @Nullable - private PyType getGenericReturnType(@NotNull TypeEvalContext typeEvalContext, @Nullable PyQualifiedExpression callSite) { - if (typeEvalContext.maySwitchToAST(this) && LanguageLevel.forElement(this).isAtLeast(LanguageLevel.PYTHON30)) { - PyAnnotation anno = getAnnotation(); - if (anno != null) { - PyClass pyClass = anno.resolveToClass(); - if (pyClass != null) { - return new PyClassTypeImpl(pyClass, false); - } - } - } + private PyType getGenericReturnType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { - final PyType returnType = typeProvider.getCallType(this, callSite, typeEvalContext); + final PyType returnType = typeProvider.getCallType(this, callSite, context); if (returnType != null) { returnType.assertValid(typeProvider.toString()); return returnType; } } - final PyType docStringType = getReturnTypeFromDocString(); - if (docStringType != null) { - docStringType.assertValid("from docstring"); - return docStringType; - } - if (typeEvalContext.allowReturnTypes(this)) { - final Ref yieldTypeRef = getYieldStatementType(typeEvalContext); - if (yieldTypeRef != null) { - return yieldTypeRef.get(); - } - return getReturnStatementType(typeEvalContext); - } - return null; + return getReturnType(context); } @Nullable diff --git a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java index 3b318d4962a0..99c50c86123b 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java @@ -61,10 +61,15 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getReturnType(@NotNull TypeEvalContext context) { final PyExpression body = getBody(); - if (body != null) return context.getType(body); - else return null; + return body != null ? context.getType(body) : null; + } + + @Nullable + @Override + public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + return getReturnType(context); } @Nullable diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index 9525c0de3ca4..9e6fef3f173d 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -316,11 +316,10 @@ public class PyTypeChecker { } @Nullable - public static Map unifyGenericCall(@NotNull PyFunction function, - @Nullable PyExpression receiver, + public static Map unifyGenericCall(@Nullable PyExpression receiver, @NotNull Map arguments, @NotNull TypeEvalContext context) { - final Map substitutions = collectCallGenerics(function, receiver, context); + final Map substitutions = unifyReceiver(receiver, context); for (Map.Entry entry : arguments.entrySet()) { final PyNamedParameter p = entry.getValue(); if (p.isPositionalContainer() || p.isKeywordContainer()) { @@ -336,8 +335,7 @@ public class PyTypeChecker { } @NotNull - public static Map collectCallGenerics(@NotNull Callable callable, @Nullable PyExpression receiver, - @NotNull TypeEvalContext context) { + public static Map unifyReceiver(@Nullable PyExpression receiver, @NotNull TypeEvalContext context) { final Map substitutions = new LinkedHashMap(); // Collect generic params of object type final Set generics = new LinkedHashSet(); @@ -346,14 +344,22 @@ public class PyTypeChecker { for (PyGenericType t : generics) { substitutions.put(t, t); } - final PyClass cls = (callable instanceof PyFunction) ? ((PyFunction)callable).getContainingClass() : null; - if (cls != null) { - final PyFunction init = cls.findInitOrNew(true); - // Unify generics in constructor - if (init != null) { - final PyType initType = init.getCallType(context, null); - if (initType != null) { - match(initType, qualifierType, context, substitutions); + // Unify generics in constructor + if (qualifierType != null) { + final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); + // TODO: Resolve to __new__ as well + final List results = qualifierType.resolveMember(PyNames.INIT, null, AccessDirection.READ, + resolveContext); + if (results != null && !results.isEmpty()) { + final PsiElement init = results.get(0).getElement(); + if (init instanceof PyTypedElement) { + final PyType initType = context.getType((PyTypedElement)init); + if (initType instanceof PyCallableType) { + final PyType initReturnType = ((PyCallableType)initType).getReturnType(context); + if (initReturnType != null) { + match(initReturnType, qualifierType, context, substitutions); + } + } } } } From 9e9e8e5a6a50aa5703deaa7bfe3a0311b702dc44 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 3 Mar 2014 14:22:00 +0400 Subject: [PATCH 05/13] Cache call site independent return types of callables in TypeEvalContext --- .../jetbrains/python/psi/impl/PyJavaClassType.java | 4 ++-- .../jetbrains/python/psi/impl/PyJavaMethodType.java | 4 ++-- .../jetbrains/python/psi/types/PyCallableType.java | 2 +- .../jetbrains/python/psi/impl/PyFunctionImpl.java | 13 +++++++++++-- .../python/psi/impl/PyLambdaExpressionImpl.java | 12 +++++++++++- .../python/psi/types/PyCallableTypeImpl.java | 3 +-- .../jetbrains/python/psi/types/PyClassTypeImpl.java | 4 ++-- .../jetbrains/python/psi/types/PyFunctionType.java | 9 +++++---- .../jetbrains/python/psi/types/PyTypeChecker.java | 2 +- python/testData/quickdoc/Method.html | 2 +- 10 files changed, 37 insertions(+), 18 deletions(-) diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java index 3c778d28540a..87cbdaf9ab10 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java @@ -104,7 +104,7 @@ public class PyJavaClassType implements PyClassLikeType { @Nullable @Override - public PyType getReturnType(@NotNull TypeEvalContext context) { + public PyType getReturnType() { if (myDefinition) { return new PyJavaClassType(myClass, false); } @@ -114,7 +114,7 @@ public class PyJavaClassType implements PyClassLikeType { @Nullable @Override public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { - return getReturnType(context); + return getReturnType(); } @Nullable diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java index 5b496c14a07a..247e5e9ad9b2 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java @@ -52,14 +52,14 @@ public class PyJavaMethodType implements PyCallableType { @Nullable @Override - public PyType getReturnType(@NotNull TypeEvalContext context) { + public PyType getReturnType() { return PyJavaTypeProvider.asPyType(myMethod.getReturnType()); } @Nullable @Override public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { - return getReturnType(context); + return getReturnType(); } @Nullable diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java index 7292391ad4f8..109a20e6c60d 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java @@ -39,7 +39,7 @@ public interface PyCallableType extends PyType { * For example, it may return a generic type. */ @Nullable - PyType getReturnType(@NotNull TypeEvalContext context); + PyType getReturnType(); /** * Returns the type which is the result of calling an instance of this type. diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java index 26cb36fd9f8f..1f789ba673a8 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java @@ -177,6 +177,15 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp @Nullable @Override public PyType getReturnType(@NotNull TypeEvalContext context) { + final PyType type = context.getType(this); + if (type instanceof PyCallableType) { + return ((PyCallableType)type).getReturnType(); + } + return null; + } + + @Nullable + private PyType calculateReturnType(@NotNull TypeEvalContext context) { for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { final PyType returnType = typeProvider.getReturnType(this, context); if (returnType != null) { @@ -399,8 +408,8 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp return type; } } - final PyFunctionType type = new PyFunctionType(this); - if (getDecoratorList() != null) { + final PyFunctionType type = new PyFunctionType(this, calculateReturnType(context)); + if (PyUtil.hasCustomDecorators(this) && !PyUtil.isDecoratedAsAbstract(this) && getProperty() == null) { return PyUnionType.createWeakType(type); } return type; diff --git a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java index 99c50c86123b..f39a88947adb 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java @@ -21,6 +21,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache; import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.types.PyCallableType; import com.jetbrains.python.psi.types.PyFunctionType; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; @@ -46,7 +47,7 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp return type; } } - return new PyFunctionType(this); + return new PyFunctionType(this, calculateReturnType(context)); } @NotNull @@ -62,6 +63,15 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp @Nullable @Override public PyType getReturnType(@NotNull TypeEvalContext context) { + final PyType type = context.getType(this); + if (type instanceof PyCallableType) { + return ((PyCallableType)type).getReturnType(); + } + return null; + } + + @Nullable + private PyType calculateReturnType(@NotNull TypeEvalContext context) { final PyExpression body = getBody(); return body != null ? context.getType(body) : null; } diff --git a/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java index 9c1d2a649263..2c37790558c1 100644 --- a/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java @@ -49,8 +49,7 @@ public class PyCallableTypeImpl implements PyCallableType { @Nullable @Override - public PyType getReturnType(@NotNull TypeEvalContext context) { - // TODO: Check that this return type doesn't depend on the call site for all PyCallableTypeImpl objects + public PyType getReturnType() { return myReturnType; } diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index fd1097918dcf..c557c63c9603 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -307,7 +307,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { @Nullable @Override - public PyType getReturnType(@NotNull TypeEvalContext context) { + public PyType getReturnType() { if (isDefinition()) { return new PyClassTypeImpl(getPyClass(), false); } @@ -317,7 +317,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { @Nullable @Override public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { - return getReturnType(context); + return getReturnType(); } @Nullable diff --git a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java index 6d577721063c..804f19b63b89 100644 --- a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java @@ -34,9 +34,11 @@ import java.util.List; */ public class PyFunctionType implements PyCallableType { @NotNull private final Callable myCallable; + @Nullable private final PyType myReturnType; - public PyFunctionType(@NotNull Callable callable) { + public PyFunctionType(@NotNull Callable callable, @Nullable PyType returnType) { myCallable = callable; + myReturnType = returnType; } @Override @@ -46,9 +48,8 @@ public class PyFunctionType implements PyCallableType { @Nullable @Override - public PyType getReturnType(@NotNull TypeEvalContext context) { - // TODO: Make Callable.getReturnType() call site independent, extract getCallType() - return myCallable.getCallType(context, null); + public PyType getReturnType() { + return myReturnType; } @Nullable diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index 9e6fef3f173d..b698869ea379 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -355,7 +355,7 @@ public class PyTypeChecker { if (init instanceof PyTypedElement) { final PyType initType = context.getType((PyTypedElement)init); if (initType instanceof PyCallableType) { - final PyType initReturnType = ((PyCallableType)initType).getReturnType(context); + final PyType initReturnType = ((PyCallableType)initType).getReturnType(); if (initReturnType != null) { match(initReturnType, qualifierType, context, substitutions); } diff --git a/python/testData/quickdoc/Method.html b/python/testData/quickdoc/Method.html index c99d4b3cbd1b..db6787aadafe 100644 --- a/python/testData/quickdoc/Method.html +++ b/python/testData/quickdoc/Method.html @@ -1 +1 @@ -class Foo

@deco
def meth(self)
Inferred type: (self: Foo) -> None


Doc of meth.
\ No newline at end of file +class Foo

@deco
def meth(self)
Inferred type: (self: Foo) -> unknown


Doc of meth.
\ No newline at end of file From 032ad71073e496fa96c2298251b1a870de735851 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 3 Mar 2014 14:32:58 +0400 Subject: [PATCH 06/13] Inlined getGenericReturnType() --- .../python/psi/impl/PyFunctionImpl.java | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java index 1f789ba673a8..5a5c074c225e 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java @@ -220,7 +220,17 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp @Nullable @Override public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { - PyType type = getGenericReturnType(context, callSite); + PyType type = null; + for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { + type = typeProvider.getCallType(this, callSite, context); + if (type != null) { + type.assertValid(typeProvider.toString()); + break; + } + } + if (type == null) { + type = getReturnType(context); + } if (callSite == null) { return type; } @@ -250,7 +260,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp */ public PyType getReturnTypeWithoutCallSite(@NotNull TypeEvalContext context, @Nullable PyExpression receiver) { - PyType type = getGenericReturnType(context, null); + PyType type = getReturnType(context); if (PyTypeChecker.hasGenerics(type, context)) { final Map substitutions = PyTypeChecker.unifyGenericCall(receiver, Maps.newHashMap(), @@ -292,18 +302,6 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp return false; } - @Nullable - private PyType getGenericReturnType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { - for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { - final PyType returnType = typeProvider.getCallType(this, callSite, context); - if (returnType != null) { - returnType.assertValid(typeProvider.toString()); - return returnType; - } - } - return getReturnType(context); - } - @Nullable private Ref getYieldStatementType(@NotNull final TypeEvalContext context) { Ref elementType = null; From dd898e2d02b714c3f5f933c5c60d0c8524c1bf7e Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 3 Mar 2014 14:56:50 +0400 Subject: [PATCH 07/13] Introduced Callable.getCallType() instead of PyFunctionImpl.getReturnTypeWithoutCallSite() --- .../com/jetbrains/python/psi/Callable.java | 10 +++++ .../python/psi/impl/PyFunctionImpl.java | 44 ++++++++----------- .../psi/impl/PyLambdaExpressionImpl.java | 10 +++++ .../psi/impl/PyTargetExpressionImpl.java | 10 ++--- 4 files changed, 43 insertions(+), 31 deletions(-) diff --git a/python/psi-api/src/com/jetbrains/python/psi/Callable.java b/python/psi-api/src/com/jetbrains/python/psi/Callable.java index b979b0deb79a..7eb9727ebbb4 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/Callable.java +++ b/python/psi-api/src/com/jetbrains/python/psi/Callable.java @@ -20,6 +20,8 @@ import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Map; + /** * Something that can be called, passed parameters to, and return something back. @@ -45,6 +47,14 @@ public interface Callable extends PyTypedElement, PyQualifiedNameOwner { @Nullable PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite); + /** + * Returns the type of the call to the callable where the call site is specified by the optional receiver and the arguments to parameters + * mapping. + */ + @Nullable + PyType getCallType(@Nullable PyExpression receiver, @NotNull Map parameters, + @NotNull TypeEvalContext context); + /** * @return a methods returns itself, non-method callables return null. */ diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java index 5a5c074c225e..62776f013af1 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java @@ -15,7 +15,6 @@ */ package com.jetbrains.python.psi.impl; -import com.google.common.collect.Maps; import com.intellij.lang.ASTNode; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.Pair; @@ -235,36 +234,25 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp return type; } final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCallSite(callSite, context); - if (PyTypeChecker.hasGenerics(type, context)) { - if (results != null) { - final Map substitutions = PyTypeChecker.unifyGenericCall(results.getReceiver(), results.getArguments(), - context); - type = substitutions != null ? PyTypeChecker.substitute(type, substitutions, context) : null; - } - else { - type = null; - } - } if (results != null) { - type = replaceSelf(type, results.getReceiver(), context); - } - if (results != null && isDynamicallyEvaluated(results.getArguments().values(), context)) { - return PyUnionType.createWeakType(type); + return analyzeCallType(type, results.getReceiver(), results.getArguments(), context); } return type; } @Nullable - /** - * Suits when there is no call site(e.g. implicit __iter__ call in statement for) - */ - public PyType getReturnTypeWithoutCallSite(@NotNull TypeEvalContext context, - @Nullable PyExpression receiver) { - PyType type = getReturnType(context); + @Override + public PyType getCallType(@Nullable PyExpression receiver, + @NotNull Map parameters, + @NotNull TypeEvalContext context) { + return analyzeCallType(getReturnType(context), receiver, parameters, context); + } + + @Nullable + private PyType analyzeCallType(@Nullable PyType type, @Nullable PyExpression receiver, + @NotNull Map parameters, @NotNull TypeEvalContext context) { if (PyTypeChecker.hasGenerics(type, context)) { - final Map substitutions = PyTypeChecker.unifyGenericCall(receiver, - Maps.newHashMap(), - context); + final Map substitutions = PyTypeChecker.unifyGenericCall(receiver, parameters, context); if (substitutions != null) { type = PyTypeChecker.substitute(type, substitutions, context); } @@ -272,7 +260,13 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp type = null; } } - return replaceSelf(type, receiver, context); + if (receiver != null) { + type = replaceSelf(type, receiver, context); + } + if (type != null && isDynamicallyEvaluated(parameters.values(), context)) { + type = PyUnionType.createWeakType(type); + } + return type; } @Nullable diff --git a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java index f39a88947adb..97f1303cb24e 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java @@ -28,6 +28,8 @@ import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Map; + /** * @author yole */ @@ -82,6 +84,14 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp return getReturnType(context); } + @Nullable + @Override + public PyType getCallType(@Nullable PyExpression receiver, + @NotNull Map parameters, + @NotNull TypeEvalContext context) { + return getReturnType(context); + } + @Nullable public PyExpression getBody() { return PsiTreeUtil.getChildOfType(this, PyExpression.class); diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java index 3ce0c51e7183..060c39ccdee0 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java @@ -54,6 +54,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; /** @@ -243,8 +244,8 @@ public class PyTargetExpressionImpl extends PyPresentableElementImplemptyMap(), context); if (enterType != null) { return enterType; } @@ -438,10 +439,7 @@ public class PyTargetExpressionImpl extends PyPresentableElementImplemptyMap(), context); } @Nullable From eb0b14f04f34339062edccdb0c28847222358ef4 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 3 Mar 2014 15:00:48 +0400 Subject: [PATCH 08/13] Changed Callable.getCallType() with explicit 'null' call site to Callable.getReturnType() --- .../python/codeInsight/override/PyOverrideImplementUtil.java | 2 +- .../com/jetbrains/python/psi/impl/PyCallExpressionHelper.java | 2 +- python/src/com/jetbrains/python/psi/impl/PyClassImpl.java | 2 +- .../src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java index a7fc0dc08d25..cce526ad60ec 100644 --- a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java @@ -225,7 +225,7 @@ public class PyOverrideImplementUtil { statementBody.append(PyNames.PASS); } else { - if (!PyNames.INIT.equals(baseFunction.getName()) && baseFunction.getCallType(context, null) != PyNoneType.INSTANCE) { + if (!PyNames.INIT.equals(baseFunction.getName()) && baseFunction.getReturnType(context) != PyNoneType.INSTANCE) { statementBody.append("return "); } if (baseClass.isNewStyleClass()) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java index 874190b84104..4928bc6305e6 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java @@ -198,7 +198,7 @@ public class PyCallExpressionHelper { final PyFunction function = (PyFunction)resolved; final Property property = function.getProperty(); if (property != null && isQualifiedByInstance(function, qualifiers, context)) { - final PyType type = function.getCallType(context, null); + final PyType type = function.getReturnType(context); if (type instanceof PyFunctionType) { resolved = ((PyFunctionType)type).getCallable(); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index b25ba2dbfa86..cc112040964d 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -750,7 +750,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement if (!(callable instanceof StubBasedPsiElement) && !context.maySwitchToAST(callable)) { return null; } - return callable.getCallType(context, null); + return callable.getReturnType(context); } return null; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java index eeb3f9a0e3af..04771779a780 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java @@ -208,7 +208,7 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl Date: Mon, 3 Mar 2014 15:39:47 +0400 Subject: [PATCH 09/13] Switched to @NotNull call site in Callable.getCallType() and PyCallableType.getCallType() Changed some usages of getCallType() to getReturnType() and fixed handling of functions with custom decorators. --- .../python/psi/impl/PyJavaClassType.java | 2 +- .../python/psi/impl/PyJavaMethodType.java | 2 +- .../com/jetbrains/python/psi/Callable.java | 2 +- .../python/psi/types/PyCallableType.java | 2 +- .../codeInsight/stdlib/PyNamedTupleType.java | 2 +- .../documentation/PyTypeModelBuilder.java | 2 +- .../PyPropertyDefinitionInspection.java | 4 +++- .../psi/impl/PyCallExpressionHelper.java | 8 ++++++- .../python/psi/impl/PyFunctionImpl.java | 23 +++++++++++-------- .../psi/impl/PyLambdaExpressionImpl.java | 2 +- .../python/psi/types/PyCallableTypeImpl.java | 2 +- .../python/psi/types/PyClassTypeImpl.java | 2 +- .../python/psi/types/PyFunctionType.java | 2 +- .../python/psi/types/PyTypeChecker.java | 7 +++--- python/testData/quickdoc/Method.html | 2 +- .../jetbrains/python/PyTypeParserTest.java | 4 ++-- 16 files changed, 40 insertions(+), 28 deletions(-) diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java index 87cbdaf9ab10..b1df4c6f4dff 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java @@ -113,7 +113,7 @@ public class PyJavaClassType implements PyClassLikeType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { return getReturnType(); } diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java index 247e5e9ad9b2..b12fa1cb06ba 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java @@ -58,7 +58,7 @@ public class PyJavaMethodType implements PyCallableType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { return getReturnType(); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/Callable.java b/python/psi-api/src/com/jetbrains/python/psi/Callable.java index 7eb9727ebbb4..2dbded6faae7 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/Callable.java +++ b/python/psi-api/src/com/jetbrains/python/psi/Callable.java @@ -45,7 +45,7 @@ public interface Callable extends PyTypedElement, PyQualifiedNameOwner { * Returns the type of the call to the callable. */ @Nullable - PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite); + PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite); /** * Returns the type of the call to the callable where the call site is specified by the optional receiver and the arguments to parameters diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java index 109a20e6c60d..6797ca69e4a5 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java @@ -45,7 +45,7 @@ public interface PyCallableType extends PyType { * Returns the type which is the result of calling an instance of this type. */ @Nullable - PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite); + PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite); /** * Returns the list of parameter types. diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java index 9ffb86d2b090..f70a18b9aa39 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java @@ -95,7 +95,7 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { if (myDefinitionLevel > 0) { return new PyNamedTupleType(myClass, myDeclaration, myName, myFields, myDefinitionLevel-1); } diff --git a/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java b/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java index ad1fa2d7f5a2..519e6a4afb2c 100644 --- a/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java @@ -226,7 +226,7 @@ public class PyTypeModelBuilder { parameterModels.add(new ParamType(parameter.getName(), build(parameter.getType(myContext), true))); } } - final PyType ret = type.getCallType(myContext, null); + final PyType ret = type.getReturnType(); final TypeModel returnType = build(ret, true); return new FunctionType(returnType, parameterModels); } diff --git a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java index 33d9b0bf20a1..945929e866d6 100644 --- a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java @@ -301,7 +301,9 @@ public class PyPropertyDefinitionInspection extends PyInspection { } else { PyReferenceExpression callSite = being_checked instanceof PyReferenceExpression ? (PyReferenceExpression) being_checked : null; - hasReturns = !(callable.getCallType(myTypeEvalContext, callSite) instanceof PyNoneType); + final PyType type = callSite != null ? callable.getCallType(myTypeEvalContext, callSite) + : callable.getReturnType(myTypeEvalContext); + hasReturns = !(type instanceof PyNoneType); } if (allowed ^ hasReturns) { if (allowed && callable instanceof PyFunction) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java index 4928bc6305e6..7eae40ba90c9 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java @@ -463,8 +463,14 @@ public class PyCallExpressionHelper { else { final PyType type = context.getType(callee); if (type instanceof PyCallableType) { + final PyCallableType callableType = (PyCallableType)type; final PyQualifiedExpression callSite = callee instanceof PyQualifiedExpression ? (PyQualifiedExpression)callee : null; - return ((PyCallableType) type).getCallType(context, callSite); + if (callSite != null) { + return callableType.getCallType(context, callSite); + } + else { + return callableType.getReturnType(); + } } return null; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java index 62776f013af1..1c29810d6f1a 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java @@ -176,7 +176,11 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp @Nullable @Override public PyType getReturnType(@NotNull TypeEvalContext context) { - final PyType type = context.getType(this); + PyType type = context.getType(this); + if (type instanceof PyUnionType) { + final PyUnionType unionType = (PyUnionType)type; + type = unionType.excludeNull(); + } if (type instanceof PyCallableType) { return ((PyCallableType)type).getReturnType(); } @@ -218,7 +222,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { PyType type = null; for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { type = typeProvider.getCallType(this, callSite, context); @@ -230,9 +234,6 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp if (type == null) { type = getReturnType(context); } - if (callSite == null) { - return type; - } final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCallSite(callSite, context); if (results != null) { return analyzeCallType(type, results.getReceiver(), results.getArguments(), context); @@ -249,8 +250,10 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp } @Nullable - private PyType analyzeCallType(@Nullable PyType type, @Nullable PyExpression receiver, - @NotNull Map parameters, @NotNull TypeEvalContext context) { + private PyType analyzeCallType(@Nullable PyType type, + @Nullable PyExpression receiver, + @NotNull Map parameters, + @NotNull TypeEvalContext context) { if (PyTypeChecker.hasGenerics(type, context)) { final Map substitutions = PyTypeChecker.unifyGenericCall(receiver, parameters, context); if (substitutions != null) { @@ -400,8 +403,10 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp return type; } } - final PyFunctionType type = new PyFunctionType(this, calculateReturnType(context)); - if (PyUtil.hasCustomDecorators(this) && !PyUtil.isDecoratedAsAbstract(this) && getProperty() == null) { + final boolean hasCustomDecorators = PyUtil.hasCustomDecorators(this) && !PyUtil.isDecoratedAsAbstract(this) && getProperty() == null; + final PyType returnType = calculateReturnType(context); + final PyFunctionType type = new PyFunctionType(this, hasCustomDecorators ? PyUnionType.createWeakType(returnType) : returnType); + if (hasCustomDecorators) { return PyUnionType.createWeakType(type); } return type; diff --git a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java index 97f1303cb24e..87d081050f12 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java @@ -80,7 +80,7 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { return getReturnType(context); } diff --git a/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java index 2c37790558c1..2a488c3a53ea 100644 --- a/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java @@ -55,7 +55,7 @@ public class PyCallableTypeImpl implements PyCallableType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { return myReturnType; } diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index c557c63c9603..592ee9a1881b 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -316,7 +316,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { return getReturnType(); } diff --git a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java index 804f19b63b89..acd18cf7018b 100644 --- a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java @@ -54,7 +54,7 @@ public class PyFunctionType implements PyCallableType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { return myCallable.getCallType(context, callSite); } diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index b698869ea379..6050bb58e643 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -171,8 +171,7 @@ public class PyTypeChecker { } } } - if (!match(expectedCallable.getCallType(context, null), actualCallable.getCallType(context, null), context, substitutions, - recursive)) { + if (!match(expectedCallable.getReturnType(), actualCallable.getReturnType(), context, substitutions, recursive)) { return false; } return true; @@ -258,7 +257,7 @@ public class PyTypeChecker { } } } - collectGenerics(callable.getCallType(context, null), context, collected, visited); + collectGenerics(callable.getReturnType(), context, collected, visited); } } @@ -308,7 +307,7 @@ public class PyTypeChecker { substParams.add(subst); } } - final PyType substResult = substitute(callable.getCallType(context, null), substitutions, context); + final PyType substResult = substitute(callable.getReturnType(), substitutions, context); return new PyCallableTypeImpl(substParams, substResult); } } diff --git a/python/testData/quickdoc/Method.html b/python/testData/quickdoc/Method.html index db6787aadafe..c99d4b3cbd1b 100644 --- a/python/testData/quickdoc/Method.html +++ b/python/testData/quickdoc/Method.html @@ -1 +1 @@ -class Foo

@deco
def meth(self)
Inferred type: (self: Foo) -> unknown


Doc of meth.
\ No newline at end of file +class Foo

@deco
def meth(self)
Inferred type: (self: Foo) -> None


Doc of meth.
\ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyTypeParserTest.java b/python/testSrc/com/jetbrains/python/PyTypeParserTest.java index 30dc43404a3c..8a34c5e31ae6 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeParserTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeParserTest.java @@ -252,7 +252,7 @@ public class PyTypeParserTest extends PyTestCase { final PyCallableType callableType = (PyCallableType)type; assertNotNull(callableType); final TypeEvalContext context = getTypeEvalContext(); - final PyType returnType = callableType.getCallType(context, null); + final PyType returnType = callableType.getReturnType(); assertInstanceOf(returnType, PyGenericType.class); final List parameterTypes = callableType.getParameters(context); assertNotNull(parameterTypes); @@ -271,7 +271,7 @@ public class PyTypeParserTest extends PyTestCase { assertInstanceOf(type, PyCallableType.class); final PyCallableType callableType = (PyCallableType)type; assertNotNull(callableType); - final PyType returnType = callableType.getCallType(getTypeEvalContext(), null); + final PyType returnType = callableType.getReturnType(); assertNotNull(returnType); assertEquals("int", returnType.getName()); final List parameterTypes = callableType.getParameters(getTypeEvalContext()); From 287c82f797d030f26970507012cfc03b12f44393 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 3 Mar 2014 17:06:52 +0400 Subject: [PATCH 10/13] Removed TypeEvalContext parameter from PyType.isBuiltin() --- .../com/jetbrains/python/psi/impl/PyJavaClassType.java | 2 +- .../com/jetbrains/python/psi/impl/PyJavaMethodType.java | 2 +- .../com/jetbrains/python/psi/impl/PyJavaPackageType.java | 3 +-- .../psi-api/src/com/jetbrains/python/psi/types/PyType.java | 3 +-- .../completion/PyDictKeyNamesCompletionContributor.java | 2 +- .../intentions/PyDictConstructorToLiteralFormIntention.java | 2 +- .../python/codeInsight/stdlib/PyNamedTupleType.java | 2 +- .../python/inspections/PyBroadExceptionInspection.java | 2 +- .../python/inspections/PyStatementEffectInspection.java | 4 ++-- .../jetbrains/python/psi/impl/CallArgumentsMappingImpl.java | 2 +- .../com/jetbrains/python/psi/types/PyCallableTypeImpl.java | 2 +- .../src/com/jetbrains/python/psi/types/PyClassTypeImpl.java | 4 ++-- .../src/com/jetbrains/python/psi/types/PyFunctionType.java | 2 +- python/src/com/jetbrains/python/psi/types/PyGenericType.java | 2 +- .../com/jetbrains/python/psi/types/PyImportedModuleType.java | 2 +- python/src/com/jetbrains/python/psi/types/PyModuleType.java | 2 +- python/src/com/jetbrains/python/psi/types/PyNoneType.java | 2 +- python/src/com/jetbrains/python/psi/types/PyTupleType.java | 2 +- python/src/com/jetbrains/python/psi/types/PyUnionType.java | 5 ++--- .../python/refactoring/introduce/IntroduceHandler.java | 2 +- 20 files changed, 23 insertions(+), 26 deletions(-) diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java index b1df4c6f4dff..c2e5938776e7 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java @@ -89,7 +89,7 @@ public class PyJavaClassType implements PyClassLikeType { } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return false; // TODO: JDK's types could be considered built-in. } diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java index b12fa1cb06ba..8287b0b4c6cd 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java @@ -90,7 +90,7 @@ public class PyJavaMethodType implements PyCallableType { } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return false; } diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java index 2948f2108abb..6f891c02c1c4 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java @@ -31,7 +31,6 @@ import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; import com.jetbrains.python.psi.types.PyType; -import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -96,7 +95,7 @@ public class PyJavaPackageType implements PyType { } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return false; } diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java index 098761020989..67ba765bbf81 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java @@ -73,9 +73,8 @@ public interface PyType { /** * @return true if the type is a known built-in type. - * @param context */ - boolean isBuiltin(TypeEvalContext context); + boolean isBuiltin(); void assertValid(String message); } diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java index cc7817fdf3d2..d7b1598f39a6 100644 --- a/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java +++ b/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java @@ -131,7 +131,7 @@ public class PyDictKeyNamesCompletionContributor extends CompletionContributor { if ("dict".equals(name)) { final TypeEvalContext context = TypeEvalContext.userInitiated(callee.getContainingFile()); final PyType type = context.getType(dictConstructor); - if (type != null && type.isBuiltin(context)) { + if (type != null && type.isBuiltin()) { final PyArgumentList list = dictConstructor.getArgumentList(); if (list == null) return; final PyExpression[] argumentList = list.getArguments(); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java index 322a31b6419c..8a72aa233dc5 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java @@ -58,7 +58,7 @@ public class PyDictConstructorToLiteralFormIntention extends BaseIntentionAction if (expression != null && expression.isCalleeText("dict")) { final TypeEvalContext context = TypeEvalContext.codeAnalysis(file); PyType type = context.getType(expression); - if (type != null && type.isBuiltin(context)) { + if (type != null && type.isBuiltin()) { PyExpression[] argumentList = expression.getArguments(); for (PyExpression argument : argumentList) { if (!(argument instanceof PyKeywordArgument)) return false; diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java index f70a18b9aa39..ad1d6a24bdc1 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java @@ -89,7 +89,7 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return false; } diff --git a/python/src/com/jetbrains/python/inspections/PyBroadExceptionInspection.java b/python/src/com/jetbrains/python/inspections/PyBroadExceptionInspection.java index 2731f8d8fb11..4b0945d6742b 100644 --- a/python/src/com/jetbrains/python/inspections/PyBroadExceptionInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyBroadExceptionInspection.java @@ -54,7 +54,7 @@ public class PyBroadExceptionInspection extends PyInspection { public static boolean equalsException(@NotNull PyClass cls, @NotNull TypeEvalContext context) { final PyType type = context.getType(cls); - return ("Exception".equals(cls.getName()) || "BaseException".equals(cls.getName())) && type != null && type.isBuiltin(context); + return ("Exception".equals(cls.getName()) || "BaseException".equals(cls.getName())) && type != null && type.isBuiltin(); } private static class Visitor extends PyInspectionVisitor { diff --git a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java index 28ccafd5aa12..a72ec9ef8504 100644 --- a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java @@ -111,7 +111,7 @@ public class PyStatementEffectInspection extends PyInspection { // maybe the op is overridden and may produce side effects, like cout << "hello" PyType type = myTypeEvalContext.getType(leftExpression); if (type != null && - !type.isBuiltin(myTypeEvalContext) && + !type.isBuiltin() && type.resolveMember(method, null, AccessDirection.READ, resolveWithoutImplicits()) != null) { return true; } @@ -119,7 +119,7 @@ public class PyStatementEffectInspection extends PyInspection { type = myTypeEvalContext.getType(rightExpression); if (type != null) { String rmethod = "__r" + method.substring(2); // __add__ -> __radd__ - if (!type.isBuiltin(myTypeEvalContext) && type.resolveMember(rmethod, null, AccessDirection.READ, resolveWithoutImplicits()) != null) { + if (!type.isBuiltin() && type.resolveMember(rmethod, null, AccessDirection.READ, resolveWithoutImplicits()) != null) { return true; } } diff --git a/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java b/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java index 692ff0052b10..20e8c5dbe1dc 100644 --- a/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java @@ -134,7 +134,7 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { } else { PyType arg_type = context.getType(arg); - if (arg_type != null && arg_type.isBuiltin(context) && "list".equals(arg_type.getName())) { + if (arg_type != null && arg_type.isBuiltin() && "list".equals(arg_type.getName())) { mapped_args.add(arg); // we can't really analyze arbitrary lists statically yet // but ListLiteralExpressions are handled by visitor } diff --git a/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java index 2a488c3a53ea..d5152bedca94 100644 --- a/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java @@ -111,7 +111,7 @@ public class PyCallableTypeImpl implements PyCallableType { } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return false; } diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index 592ee9a1881b..7a0fc0b44236 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -163,7 +163,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } } - if ("super".equals(getClassQName()) && isBuiltin(context) && location instanceof PyCallExpression) { + if ("super".equals(getClassQName()) && isBuiltin() && location instanceof PyCallExpression) { // methods of super() call are not of class super! PyExpression first_arg = ((PyCallExpression)location).getArgument(0, PyExpression.class); if (first_arg != null) { // the usual case: first arg is the derived class that super() is proxying for @@ -536,7 +536,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return PyBuiltinCache.getInstance(myClass).isBuiltin(myClass); } diff --git a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java index acd18cf7018b..540bcb300f5f 100644 --- a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java @@ -87,7 +87,7 @@ public class PyFunctionType implements PyCallableType { } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return false; } diff --git a/python/src/com/jetbrains/python/psi/types/PyGenericType.java b/python/src/com/jetbrains/python/psi/types/PyGenericType.java index af7aaae80c44..68256ae6c3f3 100644 --- a/python/src/com/jetbrains/python/psi/types/PyGenericType.java +++ b/python/src/com/jetbrains/python/psi/types/PyGenericType.java @@ -59,7 +59,7 @@ public class PyGenericType implements PyType { } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return false; } diff --git a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java index 3b56b6320289..5f66c818388d 100644 --- a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java @@ -90,7 +90,7 @@ public class PyImportedModuleType implements PyType { } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return false; // no module can be imported from builtins } diff --git a/python/src/com/jetbrains/python/psi/types/PyModuleType.java b/python/src/com/jetbrains/python/psi/types/PyModuleType.java index 5e495cdd4a88..f58f8f879c3b 100644 --- a/python/src/com/jetbrains/python/psi/types/PyModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyModuleType.java @@ -407,7 +407,7 @@ public class PyModuleType implements PyType { // Modules don't descend from obje } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return true; } diff --git a/python/src/com/jetbrains/python/psi/types/PyNoneType.java b/python/src/com/jetbrains/python/psi/types/PyNoneType.java index 05a793182e57..417f0ce1a2f1 100644 --- a/python/src/com/jetbrains/python/psi/types/PyNoneType.java +++ b/python/src/com/jetbrains/python/psi/types/PyNoneType.java @@ -53,7 +53,7 @@ public class PyNoneType implements PyType { // TODO must extend ClassType. It's } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return true; } diff --git a/python/src/com/jetbrains/python/psi/types/PyTupleType.java b/python/src/com/jetbrains/python/psi/types/PyTupleType.java index 8ede14ea8c99..ae6ca00b3dbd 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTupleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyTupleType.java @@ -63,7 +63,7 @@ public class PyTupleType extends PyClassTypeImpl implements PySubscriptableType } @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { return true; } diff --git a/python/src/com/jetbrains/python/psi/types/PyUnionType.java b/python/src/com/jetbrains/python/psi/types/PyUnionType.java index abdc5ad34428..8572b72c1771 100644 --- a/python/src/com/jetbrains/python/psi/types/PyUnionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyUnionType.java @@ -77,13 +77,12 @@ public class PyUnionType implements PyType { } /** - * @param context * @return true if all types in the union are built-in. */ @Override - public boolean isBuiltin(TypeEvalContext context) { + public boolean isBuiltin() { for (PyType one : myMembers) { - if (one == null || !one.isBuiltin(context)) return false; + if (one == null || !one.isBuiltin()) return false; } return true; } diff --git a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java index 7f774010aa8f..f479d104765e 100644 --- a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java +++ b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java @@ -207,7 +207,7 @@ abstract public class IntroduceHandler implements RefactoringActionHandler { if (type != null && type != PyNoneType.INSTANCE) { String typeName = type.getName(); if (typeName != null) { - if (type.isBuiltin(context)) { + if (type.isBuiltin()) { typeName = typeName.substring(0, 1); } candidates.addAll(NameSuggesterUtil.generateNamesByType(typeName)); From 6b8002e34ad150ca0f82539eef5c61e39b000a47 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 3 Mar 2014 19:29:39 +0400 Subject: [PATCH 11/13] Cache return types of callables using TypeEvalContext.getReturnType() --- .../python/psi/impl/PyJavaClassType.java | 4 +- .../python/psi/impl/PyJavaMethodType.java | 4 +- .../com/jetbrains/python/psi/Callable.java | 2 +- .../python/psi/types/PyCallableType.java | 3 +- .../python/psi/types/TypeEvalContext.java | 79 ++++++++++++++----- .../override/PyOverrideImplementUtil.java | 2 +- .../PyUserSkeletonsTypeProvider.java | 2 +- .../documentation/PyTypeModelBuilder.java | 2 +- .../PyPropertyDefinitionInspection.java | 2 +- .../psi/impl/PyCallExpressionHelper.java | 4 +- .../python/psi/impl/PyClassImpl.java | 2 +- .../python/psi/impl/PyFunctionImpl.java | 22 +----- .../psi/impl/PyLambdaExpressionImpl.java | 18 +---- .../python/psi/impl/PyNamedParameterImpl.java | 2 +- .../python/psi/types/PyCallableTypeImpl.java | 2 +- .../python/psi/types/PyClassTypeImpl.java | 4 +- .../python/psi/types/PyFunctionType.java | 8 +- .../python/psi/types/PyTypeChecker.java | 8 +- .../jetbrains/python/PyTypeParserTest.java | 4 +- 19 files changed, 93 insertions(+), 81 deletions(-) diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java index c2e5938776e7..a667bb69f849 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java @@ -104,7 +104,7 @@ public class PyJavaClassType implements PyClassLikeType { @Nullable @Override - public PyType getReturnType() { + public PyType getReturnType(@NotNull TypeEvalContext context) { if (myDefinition) { return new PyJavaClassType(myClass, false); } @@ -114,7 +114,7 @@ public class PyJavaClassType implements PyClassLikeType { @Nullable @Override public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { - return getReturnType(); + return getReturnType(context); } @Nullable diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java index 8287b0b4c6cd..6f0fd48e8742 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java @@ -52,14 +52,14 @@ public class PyJavaMethodType implements PyCallableType { @Nullable @Override - public PyType getReturnType() { + public PyType getReturnType(@NotNull TypeEvalContext context) { return PyJavaTypeProvider.asPyType(myMethod.getReturnType()); } @Nullable @Override public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { - return getReturnType(); + return getReturnType(context); } @Nullable diff --git a/python/psi-api/src/com/jetbrains/python/psi/Callable.java b/python/psi-api/src/com/jetbrains/python/psi/Callable.java index 2dbded6faae7..a31197ec60c1 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/Callable.java +++ b/python/psi-api/src/com/jetbrains/python/psi/Callable.java @@ -39,7 +39,7 @@ public interface Callable extends PyTypedElement, PyQualifiedNameOwner { * Returns the return type of the callable independent of a call site. */ @Nullable - PyType getReturnType(@NotNull TypeEvalContext context); + PyType getReturnType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key); /** * Returns the type of the call to the callable. diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java index 6797ca69e4a5..66fb827babe4 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java @@ -37,9 +37,10 @@ public interface PyCallableType extends PyType { * Returns the return type of a function independent of a call site. * * For example, it may return a generic type. + * @param context */ @Nullable - PyType getReturnType(); + PyType getReturnType(@NotNull TypeEvalContext context); /** * Returns the type which is the result of calling an instance of this type. diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java index bc53ffdeceaf..f3c688bc88ae 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java @@ -18,6 +18,7 @@ package com.jetbrains.python.psi.types; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.jetbrains.python.psi.Callable; import com.jetbrains.python.psi.PyTypedElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,12 +42,19 @@ public class TypeEvalContext { @Nullable private final PsiFile myOrigin; private final Map myEvaluated = new HashMap(); + private final Map myEvaluatedReturn = new HashMap(); private final ThreadLocal> myEvaluating = new ThreadLocal>() { @Override protected Set initialValue() { return new HashSet(); } }; + private final ThreadLocal> myEvaluatingReturn = new ThreadLocal>() { + @Override + protected Set initialValue() { + return new HashSet(); + } + }; private TypeEvalContext(boolean allowDataFlow, boolean allowStubToAST, @Nullable PsiFile origin) { myAllowDataFlow = allowDataFlow; @@ -114,64 +122,93 @@ public class TypeEvalContext { } return this; } - + public void trace(String message, Object... args) { if (myTrace != null) { myTrace.add(myTraceIndent + String.format(message, args)); } } - + public void traceIndent() { if (myTrace != null) { myTraceIndent += " "; } } - + public void traceUnindent() { if (myTrace != null && myTraceIndent.length() >= 2) { myTraceIndent = myTraceIndent.substring(0, myTraceIndent.length()-2); } } - + public String printTrace() { return StringUtil.join(myTrace, "\n"); } - + public boolean tracing() { return myTrace != null; } @Nullable - public PyType getType(@NotNull PyTypedElement element) { - synchronized (myEvaluated) { - if (myEvaluated.containsKey(element)) { - final PyType pyType = myEvaluated.get(element); - if (pyType != null) { - pyType.assertValid(element.toString()); - } - return pyType; - } - } + public PyType getType(@NotNull final PyTypedElement element) { final Set evaluating = myEvaluating.get(); if (evaluating.contains(element)) { return null; } evaluating.add(element); try { - PyType result = element.getType(this, Key.INSTANCE); - if (result != null) { - result.assertValid(element.toString()); - } synchronized (myEvaluated) { - myEvaluated.put(element, result); + if (myEvaluated.containsKey(element)) { + final PyType type = myEvaluated.get(element); + assertValid(type, element); + return type; + } } - return result; + final PyType type = element.getType(this, Key.INSTANCE); + assertValid(type, element); + synchronized (myEvaluated) { + myEvaluated.put(element, type); + } + return type; } finally { evaluating.remove(element); } } + @Nullable + public PyType getReturnType(@NotNull final Callable callable) { + final Set evaluating = myEvaluatingReturn.get(); + if (evaluating.contains(callable)) { + return null; + } + evaluating.add(callable); + try { + synchronized (myEvaluatedReturn) { + if (myEvaluatedReturn.containsKey(callable)) { + final PyType type = myEvaluatedReturn.get(callable); + assertValid(type, callable); + return type; + } + } + final PyType type = callable.getReturnType(this, Key.INSTANCE); + assertValid(type, callable); + synchronized (myEvaluatedReturn) { + myEvaluatedReturn.put(callable, type); + } + return type; + } + finally { + evaluating.remove(callable); + } + } + + private static void assertValid(@Nullable PyType result, @NotNull PyTypedElement element) { + if (result != null) { + result.assertValid(element.toString()); + } + } + public boolean maySwitchToAST(@NotNull PsiElement element) { return myAllowStubToAST || myOrigin == element.getContainingFile(); } diff --git a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java index cce526ad60ec..39222b0fef9b 100644 --- a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java @@ -225,7 +225,7 @@ public class PyOverrideImplementUtil { statementBody.append(PyNames.PASS); } else { - if (!PyNames.INIT.equals(baseFunction.getName()) && baseFunction.getReturnType(context) != PyNoneType.INSTANCE) { + if (!PyNames.INIT.equals(baseFunction.getName()) && context.getReturnType(baseFunction) != PyNoneType.INSTANCE) { statementBody.append("return "); } if (baseClass.isNewStyleClass()) { diff --git a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java index 6dbb63ad56da..6fa6529f3dfc 100644 --- a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java @@ -47,7 +47,7 @@ public class PyUserSkeletonsTypeProvider extends PyTypeProviderBase { public PyType getReturnType(@NotNull Callable callable, @NotNull TypeEvalContext context) { final Callable callableSkeleton = PyUserSkeletonsUtil.getUserSkeleton(callable); if (callableSkeleton != null) { - return callableSkeleton.getReturnType(context); + return context.getReturnType(callableSkeleton); } return null; } diff --git a/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java b/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java index 519e6a4afb2c..6934a37d723f 100644 --- a/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java @@ -226,7 +226,7 @@ public class PyTypeModelBuilder { parameterModels.add(new ParamType(parameter.getName(), build(parameter.getType(myContext), true))); } } - final PyType ret = type.getReturnType(); + final PyType ret = type.getReturnType(myContext); final TypeModel returnType = build(ret, true); return new FunctionType(returnType, parameterModels); } diff --git a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java index 945929e866d6..27fff5602374 100644 --- a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java @@ -302,7 +302,7 @@ public class PyPropertyDefinitionInspection extends PyInspection { else { PyReferenceExpression callSite = being_checked instanceof PyReferenceExpression ? (PyReferenceExpression) being_checked : null; final PyType type = callSite != null ? callable.getCallType(myTypeEvalContext, callSite) - : callable.getReturnType(myTypeEvalContext); + : myTypeEvalContext.getReturnType(callable); hasReturns = !(type instanceof PyNoneType); } if (allowed ^ hasReturns) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java index 7eae40ba90c9..45f094764533 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java @@ -198,7 +198,7 @@ public class PyCallExpressionHelper { final PyFunction function = (PyFunction)resolved; final Property property = function.getProperty(); if (property != null && isQualifiedByInstance(function, qualifiers, context)) { - final PyType type = function.getReturnType(context); + final PyType type = context.getReturnType(function); if (type instanceof PyFunctionType) { resolved = ((PyFunctionType)type).getCallable(); } @@ -469,7 +469,7 @@ public class PyCallExpressionHelper { return callableType.getCallType(context, callSite); } else { - return callableType.getReturnType(); + return callableType.getReturnType(context); } } return null; diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index cc112040964d..b0f63eca8612 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -750,7 +750,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement if (!(callable instanceof StubBasedPsiElement) && !context.maySwitchToAST(callable)) { return null; } - return callable.getReturnType(context); + return context.getReturnType(callable); } return null; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java index 1c29810d6f1a..acc225b67f22 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java @@ -175,20 +175,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp @Nullable @Override - public PyType getReturnType(@NotNull TypeEvalContext context) { - PyType type = context.getType(this); - if (type instanceof PyUnionType) { - final PyUnionType unionType = (PyUnionType)type; - type = unionType.excludeNull(); - } - if (type instanceof PyCallableType) { - return ((PyCallableType)type).getReturnType(); - } - return null; - } - - @Nullable - private PyType calculateReturnType(@NotNull TypeEvalContext context) { + public PyType getReturnType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { final PyType returnType = typeProvider.getReturnType(this, context); if (returnType != null) { @@ -232,7 +219,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp } } if (type == null) { - type = getReturnType(context); + type = context.getReturnType(this); } final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCallSite(callSite, context); if (results != null) { @@ -246,7 +233,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp public PyType getCallType(@Nullable PyExpression receiver, @NotNull Map parameters, @NotNull TypeEvalContext context) { - return analyzeCallType(getReturnType(context), receiver, parameters, context); + return analyzeCallType(context.getReturnType(this), receiver, parameters, context); } @Nullable @@ -404,8 +391,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp } } final boolean hasCustomDecorators = PyUtil.hasCustomDecorators(this) && !PyUtil.isDecoratedAsAbstract(this) && getProperty() == null; - final PyType returnType = calculateReturnType(context); - final PyFunctionType type = new PyFunctionType(this, hasCustomDecorators ? PyUnionType.createWeakType(returnType) : returnType); + final PyFunctionType type = new PyFunctionType(this); if (hasCustomDecorators) { return PyUnionType.createWeakType(type); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java index 87d081050f12..0dd75915de12 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java @@ -21,7 +21,6 @@ import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.types.PyCallableType; import com.jetbrains.python.psi.types.PyFunctionType; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; @@ -49,7 +48,7 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp return type; } } - return new PyFunctionType(this, calculateReturnType(context)); + return new PyFunctionType(this); } @NotNull @@ -64,16 +63,7 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp @Nullable @Override - public PyType getReturnType(@NotNull TypeEvalContext context) { - final PyType type = context.getType(this); - if (type instanceof PyCallableType) { - return ((PyCallableType)type).getReturnType(); - } - return null; - } - - @Nullable - private PyType calculateReturnType(@NotNull TypeEvalContext context) { + public PyType getReturnType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { final PyExpression body = getBody(); return body != null ? context.getType(body) : null; } @@ -81,7 +71,7 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp @Nullable @Override public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { - return getReturnType(context); + return context.getReturnType(this); } @Nullable @@ -89,7 +79,7 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp public PyType getCallType(@Nullable PyExpression receiver, @NotNull Map parameters, @NotNull TypeEvalContext context) { - return getReturnType(context); + return context.getReturnType(this); } @Nullable diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java index 04771779a780..f38937daa87f 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java @@ -208,7 +208,7 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl parameterTypes = callableType.getParameters(context); assertNotNull(parameterTypes); @@ -271,7 +271,7 @@ public class PyTypeParserTest extends PyTestCase { assertInstanceOf(type, PyCallableType.class); final PyCallableType callableType = (PyCallableType)type; assertNotNull(callableType); - final PyType returnType = callableType.getReturnType(); + final PyType returnType = callableType.getReturnType(getTypeEvalContext()); assertNotNull(returnType); assertEquals("int", returnType.getName()); final List parameterTypes = callableType.getParameters(getTypeEvalContext()); From 00dbd95514641cd430aaba9fb2c9a7f5178a09a2 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 4 Mar 2014 15:43:05 +0400 Subject: [PATCH 12/13] Reuse resolve context with type eval context from the current inspection session for performance reasons --- .../python/inspections/PyProtectedMemberInspection.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java b/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java index fe9ac7f9159e..52775764074e 100644 --- a/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java @@ -70,7 +70,10 @@ public class PyProtectedMemberInspection extends PyInspection { if (name != null && name.startsWith("_") && !name.startsWith("__") && !name.endsWith("__")) { final PyClass parentClass = getClassOwner(node); if (parentClass != null) { - final PsiReference reference = node.getReference(); + final PsiReference reference = node.getReference(resolveWithoutImplicits()); + if (reference == null) { + return; + } final PsiElement resolvedExpression = reference.resolve(); final PyClass resolvedClass = getClassOwner(resolvedExpression); if (parentClass.isSubclass(resolvedClass)) From fe93f3fa22c878986a59e6289543322735ebae7a Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 4 Mar 2014 16:19:42 +0400 Subject: [PATCH 13/13] Query only the first result of super and overring method searches for performance resaons --- .../inspections/PyMethodMayBeStaticInspection.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/python/src/com/jetbrains/python/inspections/PyMethodMayBeStaticInspection.java b/python/src/com/jetbrains/python/inspections/PyMethodMayBeStaticInspection.java index 71f2772dae08..acf33c542e24 100644 --- a/python/src/com/jetbrains/python/inspections/PyMethodMayBeStaticInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyMethodMayBeStaticInspection.java @@ -32,8 +32,6 @@ import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collection; - /** * User: ktisha * @@ -66,10 +64,10 @@ public class PyMethodMayBeStaticInspection extends PyInspection { final PyClass containingClass = node.getContainingClass(); if (containingClass == null) return; if (PythonUnitTestUtil.isUnitTestCaseClass(containingClass)) return; - final Collection supers = PySuperMethodsSearch.search(node).findAll(); - if (!supers.isEmpty()) return; - final Collection overrides = PyOverridingMethodsSearch.search(node, true).findAll(); - if (!overrides.isEmpty()) return; + final PsiElement firstSuper = PySuperMethodsSearch.search(node).findFirst(); + if (firstSuper != null) return; + final PyFunction firstOverride = PyOverridingMethodsSearch.search(node, true).findFirst(); + if (firstOverride != null) return; final PyDecoratorList decoratorList = node.getDecoratorList(); if (decoratorList != null) return; if (node.getModifier() != null) return;