Match protocol usage against definition to get correct substitutions (PY-13750)

This commit is contained in:
Semyon Proshev
2018-04-23 19:40:17 +03:00
parent d329187a84
commit 5aa26dd020
4 changed files with 35 additions and 1 deletions
@@ -296,6 +296,16 @@ public class PyTypeChecker {
}
}
final PyType originalProtocolGenericType = StreamEx
.of(Extensions.getExtensions(PyTypeProvider.EP_NAME))
.map(provider -> provider.getGenericType(superClass, context.context))
.findFirst(Objects::nonNull)
.orElse(null);
// actual was matched against protocol definition above
// and here protocol usage is matched against its definition to update substitutions
match(expected, originalProtocolGenericType, context);
return Optional.of(true);
}
@@ -13,4 +13,4 @@ def test_numerics():
divmod(False, False)
divmod(<warning descr="Expected type '_N', got 'bytes' instead">b'foo'</warning>, <warning descr="Expected type '_N', got 'str' instead">'bar'</warning>)
pow(False, True)
round<warning descr="Unexpected type(s):(bool, str)Possible types:(SupportsRound, int)(float, int)">(False, 'foo')</warning>
round<warning descr="Unexpected type(s):(bool, str)Possible types:(SupportsRound[int], int)(float, int)">(False, 'foo')</warning>
@@ -974,6 +974,18 @@ public class Py3TypeTest extends PyTestCase {
);
}
// PY-13750
public void testBuiltinRound() {
doTest("int", "expr = round(1)");
doTest("Union[float, int]", "expr = round(1, 1)");
doTest("int", "expr = round(1.1)");
doTest("Union[float, int]", "expr = round(1.1, 1)");
doTest("int", "expr = round(True)");
doTest("Union[float, int]", "expr = round(True, 1)");
}
private void doTest(final String expectedType, final String text) {
myFixture.configureByText(PythonFileType.INSTANCE, text);
final PyExpression expr = myFixture.findElementByText("expr", PyExpression.class);
@@ -3218,6 +3218,18 @@ public class PyTypeTest extends PyTestCase {
);
}
// PY-13750
public void testBuiltinRound() {
doTest("float", "expr = round(1)");
doTest("float", "expr = round(1, 1)");
doTest("float", "expr = round(1.1)");
doTest("float", "expr = round(1.1, 1)");
doTest("float", "expr = round(True)");
doTest("float", "expr = round(True, 1)");
}
private static List<TypeEvalContext> getTypeEvalContexts(@NotNull PyExpression element) {
return ImmutableList.of(TypeEvalContext.codeAnalysis(element.getProject(), element.getContainingFile()).withTracing(),
TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile()).withTracing());