From 1f598fe985132d794262c2069da83710321b660f Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Thu, 13 Apr 2017 21:53:18 +0300 Subject: [PATCH] Don't use types of not matched overloads in resulting call type (PY-22808, PY-22741) We used to exclude all the Any types from matched overloads even though the match was successful. Now we stop analyzing an overload immediately when the actual arguments don't match against its parameters. --- .../jetbrains/python/pyi/PyiTypeProvider.java | 17 ++++++----------- .../listIndexedByUnknownType.py | 8 ++++++++ .../OverloadedNotMatchedType.py | 6 ++++++ .../pyi/type/overloadedNotMatchedType/m1.pyi | 9 +++++++++ .../com/jetbrains/python/PyTypingTest.java | 17 +++++++++++++++++ .../PyUnresolvedReferencesInspectionTest.java | 5 +++++ .../com/jetbrains/python/pyi/PyiTypeTest.java | 5 +++++ 7 files changed, 56 insertions(+), 11 deletions(-) create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/listIndexedByUnknownType.py create mode 100644 python/testData/pyi/type/overloadedNotMatchedType/OverloadedNotMatchedType.py create mode 100644 python/testData/pyi/type/overloadedNotMatchedType/m1.pyi diff --git a/python/src/com/jetbrains/python/pyi/PyiTypeProvider.java b/python/src/com/jetbrains/python/pyi/PyiTypeProvider.java index 03207e585b5e..f6c2df5f8923 100644 --- a/python/src/com/jetbrains/python/pyi/PyiTypeProvider.java +++ b/python/src/com/jetbrains/python/pyi/PyiTypeProvider.java @@ -27,10 +27,7 @@ import com.jetbrains.python.psi.types.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; +import java.util.*; import static com.jetbrains.python.psi.PyUtil.as; @@ -119,9 +116,7 @@ public class PyiTypeProvider extends PyTypeProviderBase { for (PyFunction overload : overloads) { final PyType returnType = context.getReturnType(overload); - if (!PyTypeChecker.hasGenerics(returnType, context)) { - allReturnTypes.add(returnType); - } + allReturnTypes.add(PyTypeChecker.substitute(returnType, new HashMap<>(), context)); final PyExpression receiver = PyTypeChecker.getReceiver(callSite, overload); final PyCallExpressionHelper.ArgumentMappingResults mapping = mapArguments(callSite, overload, context); @@ -129,11 +124,11 @@ public class PyiTypeProvider extends PyTypeProviderBase { continue; } final Map substitutions = PyTypeChecker.unifyGenericCall(receiver, mapping.getMappedParameters(), context); - - final PyType unifiedType = substitutions != null ? PyTypeChecker.substitute(returnType, substitutions, context) : null; - if (unifiedType != null) { - matchedReturnTypes.add(unifiedType); + if (substitutions == null) { + continue; } + final PyType unifiedType = PyTypeChecker.substitute(returnType, substitutions, context); + matchedReturnTypes.add(unifiedType); } return Ref.create(PyUnionType.union(matchedReturnTypes.isEmpty() ? allReturnTypes : matchedReturnTypes)); diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/listIndexedByUnknownType.py b/python/testData/inspections/PyUnresolvedReferencesInspection/listIndexedByUnknownType.py new file mode 100644 index 000000000000..d736117e174f --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/listIndexedByUnknownType.py @@ -0,0 +1,8 @@ +def f(i): + xs = [] + xs[i].items() + + +def g(index): + x = [][index] + x['foo'] diff --git a/python/testData/pyi/type/overloadedNotMatchedType/OverloadedNotMatchedType.py b/python/testData/pyi/type/overloadedNotMatchedType/OverloadedNotMatchedType.py new file mode 100644 index 000000000000..974ecfa18e0a --- /dev/null +++ b/python/testData/pyi/type/overloadedNotMatchedType/OverloadedNotMatchedType.py @@ -0,0 +1,6 @@ +from typing import Any +from m1 import C + +def f(x: Any): + c = C() + expr = c.foo(x) diff --git a/python/testData/pyi/type/overloadedNotMatchedType/m1.pyi b/python/testData/pyi/type/overloadedNotMatchedType/m1.pyi new file mode 100644 index 000000000000..24f62bb4c2d8 --- /dev/null +++ b/python/testData/pyi/type/overloadedNotMatchedType/m1.pyi @@ -0,0 +1,9 @@ +from typing import TypeVar, Generic, overload, List + +_T = TypeVar('_T') + +class C(Generic[_T]): + @overload + def foo(self, i: int) -> _T: ... + @overload + def foo(self, s: slice) -> List[_T]: ... diff --git a/python/testSrc/com/jetbrains/python/PyTypingTest.java b/python/testSrc/com/jetbrains/python/PyTypingTest.java index 12420ba99c6e..d869af1d0ee4 100644 --- a/python/testSrc/com/jetbrains/python/PyTypingTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypingTest.java @@ -892,6 +892,23 @@ public class PyTypingTest extends PyTestCase { "expr = xs.pop()"); } + public void testGenericUserFunctionWithManyParamsAndNestedCall() { + doTest("Tuple[bool, int, str]", + "from typing import TypeVar\n" + + "\n" + + "T = TypeVar('T')\n" + + "U = TypeVar('U')\n" + + "V = TypeVar('V')\n" + + "\n" + + "def myid(x: T) -> T:\n" + + " pass\n" + + "\n" + + "def f(x: T, y: U, z: V):\n" + + " return myid(x), myid(y), myid(z)\n" + + "\n" + + "expr = f(True, 1, 'foo')\n"); + } + private void doTestNoInjectedText(@NotNull String text) { myFixture.configureByText(PythonFileType.INSTANCE, text); final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myFixture.getProject()); diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index e26d550b25ed..7a19faa97ffe 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -768,6 +768,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase { doTest(); } + // PY-22741, PY-22808 + public void testListIndexedByUnknownType() { + doTest(); + } + @NotNull @Override protected Class getInspectionClass() { diff --git a/python/testSrc/com/jetbrains/python/pyi/PyiTypeTest.java b/python/testSrc/com/jetbrains/python/pyi/PyiTypeTest.java index 0349ee5cee7f..33d3dfdbffcb 100644 --- a/python/testSrc/com/jetbrains/python/pyi/PyiTypeTest.java +++ b/python/testSrc/com/jetbrains/python/pyi/PyiTypeTest.java @@ -113,4 +113,9 @@ public class PyiTypeTest extends PyTestCase { public void testOverloadedReturnType() { doTest("str"); } + + // PY-22808 + public void testOverloadedNotMatchedType() { + doTest("Union[list, Any]"); + } }