diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index 5ac746146a46..e181ce5cb582 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -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); } diff --git a/python/testData/inspections/PyTypeCheckerInspection/BuiltinsPy3.py b/python/testData/inspections/PyTypeCheckerInspection/BuiltinsPy3.py index 61a4a848f026..bb96bf914289 100644 --- a/python/testData/inspections/PyTypeCheckerInspection/BuiltinsPy3.py +++ b/python/testData/inspections/PyTypeCheckerInspection/BuiltinsPy3.py @@ -13,4 +13,4 @@ def test_numerics(): divmod(False, False) divmod(b'foo', 'bar') pow(False, True) - round(False, 'foo') + round(False, 'foo') diff --git a/python/testSrc/com/jetbrains/python/Py3TypeTest.java b/python/testSrc/com/jetbrains/python/Py3TypeTest.java index 67361ae53ea8..e36f164224bb 100644 --- a/python/testSrc/com/jetbrains/python/Py3TypeTest.java +++ b/python/testSrc/com/jetbrains/python/Py3TypeTest.java @@ -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); diff --git a/python/testSrc/com/jetbrains/python/PyTypeTest.java b/python/testSrc/com/jetbrains/python/PyTypeTest.java index 13c0670b6f72..36775cc5492b 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeTest.java @@ -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 getTypeEvalContexts(@NotNull PyExpression element) { return ImmutableList.of(TypeEvalContext.codeAnalysis(element.getProject(), element.getContainingFile()).withTracing(), TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile()).withTracing());