diff --git a/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java b/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java index b243d1423ff8..b24646262593 100644 --- a/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java @@ -266,7 +266,7 @@ public class PyTypeModelBuilder { } else if (type instanceof PyUnionType && allowUnions) { final PyUnionType unionType = (PyUnionType)type; - if (type instanceof PyDynamicallyEvaluatedType || PyTypeChecker.isUnknown(type)) { + if (type instanceof PyDynamicallyEvaluatedType || PyTypeChecker.isUnknown(type, false)) { result = new UnknownType(build(unionType.excludeNull(myContext), true)); } else { diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index abe39749ae37..3b0819fbfa12 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -346,13 +346,17 @@ public class PyTypeChecker { } public static boolean isUnknown(@Nullable PyType type) { - if (type == null || type instanceof PyGenericType) { + return isUnknown(type, true); + } + + public static boolean isUnknown(@Nullable PyType type, boolean genericsAreUnknown) { + if (type == null || (genericsAreUnknown && type instanceof PyGenericType)) { return true; } if (type instanceof PyUnionType) { final PyUnionType union = (PyUnionType)type; for (PyType t : union.getMembers()) { - if (isUnknown(t)) { + if (isUnknown(t, genericsAreUnknown)) { return true; } } diff --git a/python/testData/quickdoc/OptionalAndUnionTypesContainingTypeVars.html b/python/testData/quickdoc/OptionalAndUnionTypesContainingTypeVars.html new file mode 100644 index 000000000000..38ed0a947505 --- /dev/null +++ b/python/testData/quickdoc/OptionalAndUnionTypesContainingTypeVars.html @@ -0,0 +1 @@ +def f(x1: Optional[T], x2: Union[T, Tuple[Any, Any]])
Inferred type: (x1: Optional[TypeVar('T', int)], x2: Union[TypeVar('T', int), Tuple[Any, Any]]) -> None
\ No newline at end of file diff --git a/python/testData/quickdoc/OptionalAndUnionTypesContainingTypeVars.py b/python/testData/quickdoc/OptionalAndUnionTypesContainingTypeVars.py new file mode 100644 index 000000000000..61f83aa38952 --- /dev/null +++ b/python/testData/quickdoc/OptionalAndUnionTypesContainingTypeVars.py @@ -0,0 +1,11 @@ +from typing import TypeVar, Optional, Union, Tuple, Any + + +T = TypeVar('T', int) + + +def f(x1: Optional[T], x2: Union[T, Tuple[Any, Any]]): + print(x1, x2) + + +f diff --git a/python/testSrc/com/jetbrains/python/PyQuickDocTest.java b/python/testSrc/com/jetbrains/python/PyQuickDocTest.java index d635a492df46..d4f4a6041c9f 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickDocTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickDocTest.java @@ -282,4 +282,10 @@ public class PyQuickDocTest extends LightMarkedTestCase { myFixture.copyDirectoryToProject("typing", ""); runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHTMLOnly); } + + // PY-22730 + public void testOptionalAndUnionTypesContainingTypeVars() { + myFixture.copyDirectoryToProject("typing", ""); + runWithLanguageLevel(LanguageLevel.PYTHON36, this::checkHTMLOnly); + } }