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.
This commit is contained in:
Andrey Vlasovskikh
2017-04-13 21:57:59 +03:00
parent ec6ed69d29
commit 1f598fe985
7 changed files with 56 additions and 11 deletions
@@ -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<PyGenericType, PyType> 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));
@@ -0,0 +1,8 @@
def f(i):
xs = []
xs[i].items()
def g(index):
x = [][index]
x['foo']
@@ -0,0 +1,6 @@
from typing import Any
from m1 import C
def f(x: Any):
c = C()
<caret>expr = c.foo(x)
@@ -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]: ...
@@ -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());
@@ -768,6 +768,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase {
doTest();
}
// PY-22741, PY-22808
public void testListIndexedByUnknownType() {
doTest();
}
@NotNull
@Override
protected Class<? extends PyInspection> getInspectionClass() {
@@ -113,4 +113,9 @@ public class PyiTypeTest extends PyTestCase {
public void testOverloadedReturnType() {
doTest("str");
}
// PY-22808
public void testOverloadedNotMatchedType() {
doTest("Union[list, Any]");
}
}