From 955e588e03c0040bbbb6458e03cb29e3478ead2d Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 2 Oct 2015 21:50:55 +0300 Subject: [PATCH] Show generic types in PEP 484 notation (PY-16889) In particular, show unresolved refernces in generic bounds as Any. We used to ignore these unresolved types which resulted in incomprehensible warning messages. --- .../python/psi/types/PyGenericType.java | 17 ++++++++++++++++- .../PyTypeCheckerInspection/BoundedGeneric.py | 2 +- .../GenericUserClasses.py | 2 +- .../GenericUserFunctions.py | 2 +- .../PyTypeCheckerInspection/SecondFormIter.py | 2 +- .../TypingTypeVarWithUnresolvedBound.py | 11 +++++++++++ .../pyi/inspections/overloads/Overloads.py | 4 ++-- .../com/jetbrains/python/PyTypeParserTest.java | 4 ++-- .../com/jetbrains/python/PyTypingTest.java | 4 ++-- .../Py3TypeCheckerInspectionTest.java | 5 +++++ 10 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 python/testData/inspections/PyTypeCheckerInspection/TypingTypeVarWithUnresolvedBound.py diff --git a/python/src/com/jetbrains/python/psi/types/PyGenericType.java b/python/src/com/jetbrains/python/psi/types/PyGenericType.java index 0bccf762dff2..c43f14235ab5 100644 --- a/python/src/com/jetbrains/python/psi/types/PyGenericType.java +++ b/python/src/com/jetbrains/python/psi/types/PyGenericType.java @@ -15,8 +15,11 @@ */ package com.jetbrains.python.psi.types; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; +import com.intellij.util.Function; import com.intellij.util.ProcessingContext; +import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.AccessDirection; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.resolve.PyResolveContext; @@ -55,7 +58,19 @@ public class PyGenericType implements PyType { @NotNull @Override public String getName() { - return myBound != null ? myName + " <= " + myBound.getName() : myName; + if (myBound instanceof PyUnionType) { + final PyUnionType bounds = (PyUnionType)myBound; + final String boundsString = StringUtil.join(bounds.getMembers(), new Function() { + @Override + public String fun(PyType type) { + return type != null ? type.getName() : PyNames.UNKNOWN_TYPE; + } + }, ", "); + return "TypeVar('" + myName + "', " + boundsString + ")"; + } + else { + return "TypeVar('" + myName + "')"; + } } @Override diff --git a/python/testData/inspections/PyTypeCheckerInspection/BoundedGeneric.py b/python/testData/inspections/PyTypeCheckerInspection/BoundedGeneric.py index 7c626d093b1b..8de1106ee540 100644 --- a/python/testData/inspections/PyTypeCheckerInspection/BoundedGeneric.py +++ b/python/testData/inspections/PyTypeCheckerInspection/BoundedGeneric.py @@ -8,5 +8,5 @@ def test(): x = f(10) y = f('foo') - z = f([]) + z = f([]) return x + y diff --git a/python/testData/inspections/PyTypeCheckerInspection/GenericUserClasses.py b/python/testData/inspections/PyTypeCheckerInspection/GenericUserClasses.py index e652dcf92fc6..fdef2e5afb96 100644 --- a/python/testData/inspections/PyTypeCheckerInspection/GenericUserClasses.py +++ b/python/testData/inspections/PyTypeCheckerInspection/GenericUserClasses.py @@ -21,4 +21,4 @@ class User1(object): c = User1(10) print(c.get() + 'foo') c.put(14) -c.put('foo') +c.put('foo') diff --git a/python/testData/inspections/PyTypeCheckerInspection/GenericUserFunctions.py b/python/testData/inspections/PyTypeCheckerInspection/GenericUserFunctions.py index 937bffc0fb05..2fd5ffb4c22f 100644 --- a/python/testData/inspections/PyTypeCheckerInspection/GenericUserFunctions.py +++ b/python/testData/inspections/PyTypeCheckerInspection/GenericUserFunctions.py @@ -40,7 +40,7 @@ def test(): print(result) print(result + 'foo') - f2(1, ['foo'], 'bar') + f2(1, ['foo'], 'bar') result = f3(1, 'foo', True) f4(result) diff --git a/python/testData/inspections/PyTypeCheckerInspection/SecondFormIter.py b/python/testData/inspections/PyTypeCheckerInspection/SecondFormIter.py index 4d2cbf6a7a6b..b44e1d22d31f 100644 --- a/python/testData/inspections/PyTypeCheckerInspection/SecondFormIter.py +++ b/python/testData/inspections/PyTypeCheckerInspection/SecondFormIter.py @@ -7,7 +7,7 @@ def test_second_form(): def test_second_form_fail(): - for chunk in iter(10, ''): + for chunk in iter(10, ''): pass diff --git a/python/testData/inspections/PyTypeCheckerInspection/TypingTypeVarWithUnresolvedBound.py b/python/testData/inspections/PyTypeCheckerInspection/TypingTypeVarWithUnresolvedBound.py new file mode 100644 index 000000000000..5953fb4baf5a --- /dev/null +++ b/python/testData/inspections/PyTypeCheckerInspection/TypingTypeVarWithUnresolvedBound.py @@ -0,0 +1,11 @@ +from typing import TypeVar + + +T = TypeVar('T', int, unresolved) + + +def calc(a: T, b: T): + pass + + +calc('a', 0) diff --git a/python/testData/pyi/inspections/overloads/Overloads.py b/python/testData/pyi/inspections/overloads/Overloads.py index af7473a12ab9..954390000ab9 100644 --- a/python/testData/pyi/inspections/overloads/Overloads.py +++ b/python/testData/pyi/inspections/overloads/Overloads.py @@ -31,6 +31,6 @@ def test_stub_only_function(x): def tset_overloaded_generics(x): g(Gen(10).get(10, 10)) - g(Gen(10).get(10, 'foo')) - g(Gen('foo').get(10, 10)) + g(Gen(10).get(10, 'foo')) + g(Gen('foo').get(10, 10)) g(Gen('foo').get(10, 'foo')) diff --git a/python/testSrc/com/jetbrains/python/PyTypeParserTest.java b/python/testSrc/com/jetbrains/python/PyTypeParserTest.java index 91fa46fbe2ed..b0f3b6aa1eeb 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeParserTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeParserTest.java @@ -137,7 +137,7 @@ public class PyTypeParserTest extends PyTestCase { final PyType type = PyTypeParser.getTypeByName(myFixture.getFile(), "T"); assertNotNull(type); assertInstanceOf(type, PyGenericType.class); - assertEquals("T", type.getName()); + assertEquals("TypeVar('T')", type.getName()); } // PY-4223 @@ -251,7 +251,7 @@ public class PyTypeParserTest extends PyTestCase { assertEquals("int", type0.getName()); final PyType type1 = parameterTypes.get(1).getType(context); assertNotNull(type1); - assertEquals("T", type1.getName()); + assertEquals("TypeVar('T')", type1.getName()); } public void testCallableWithoutArgs() { diff --git a/python/testSrc/com/jetbrains/python/PyTypingTest.java b/python/testSrc/com/jetbrains/python/PyTypingTest.java index 876b1e956f8d..2d767ae01891 100644 --- a/python/testSrc/com/jetbrains/python/PyTypingTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypingTest.java @@ -151,7 +151,7 @@ public class PyTypingTest extends PyTestCase { } public void testGenericType() { - doTest("A", + doTest("TypeVar('A')", "from typing import TypeVar\n" + "\n" + "T = TypeVar('A')\n" + @@ -161,7 +161,7 @@ public class PyTypingTest extends PyTestCase { } public void testGenericBoundedType() { - doTest("T <= int | str", + doTest("TypeVar('T', int, str)", "from typing import TypeVar\n" + "\n" + "T = TypeVar('T', int, str)\n" + diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java index b3fc9efa0b0e..84f2290e8a4a 100644 --- a/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java @@ -78,4 +78,9 @@ public class Py3TypeCheckerInspectionTest extends PyTestCase { public void testTypingListSubscriptionExpression() { doTest(); } + + // PY-16855 + public void testTypingTypeVarWithUnresolvedBound() { + doTest(); + } }