From 2c79c98d22513936691a4dee2e3ff80ed477fd4d Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 15 Feb 2017 15:26:05 +0300 Subject: [PATCH] PY-20057 Consider incompatible types one of which is Type[] in the type checker --- .../python/psi/types/PyTypeChecker.java | 10 ++++++- .../ClassObjectType.py | 28 +++++++++++++++++++ .../Py3TypeCheckerInspectionTest.java | 5 ++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 python/testData/inspections/PyTypeCheckerInspection/ClassObjectType.py diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index a507ffc5a876..abe39749ae37 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -73,10 +73,18 @@ public class PyTypeChecker { return match(expected, builtinCache.getStrOrUnicodeType(), context, substitutions, recursive); } } + if (expected instanceof PyInstantiableType && actual instanceof PyInstantiableType + && ((PyInstantiableType)expected).isDefinition() ^ ((PyInstantiableType)actual).isDefinition()) { + return false; + } if (expected instanceof PyGenericType && substitutions != null) { final PyGenericType generic = (PyGenericType)expected; final PyType subst = substitutions.get(generic); - final PyType bound = generic.getBound(); + PyType bound = generic.getBound(); + // Promote int in Type[TypeVar('T', int)] to Type[int] before checking that bounds match + if (generic.isDefinition() && bound instanceof PyInstantiableType) { + bound = ((PyInstantiableType)bound).toClass(); + } if (!match(bound, actual, context, substitutions, recursive)) { return false; } diff --git a/python/testData/inspections/PyTypeCheckerInspection/ClassObjectType.py b/python/testData/inspections/PyTypeCheckerInspection/ClassObjectType.py new file mode 100644 index 000000000000..4bb448278189 --- /dev/null +++ b/python/testData/inspections/PyTypeCheckerInspection/ClassObjectType.py @@ -0,0 +1,28 @@ +from typing import Type, TypeVar + +class MyClass: + pass + +def expects_myclass(x: Type[MyClass]): + pass + +expects_myclass(MyClass()) +expects_class(MyClass) + +T1 = TypeVar('T1') +def expects_any_class(x: Type[T1]): + pass + +# expects_any_class(MyClass) +expects_any_class(MyClass()) +# expects_any_class(object) +expects_any_class(object()) + +T2 = TypeVar('T2', MyClass) +def expects_myclass_descendant(x: Type[T2]): + pass + +expects_myclass_descendant(MyClass) +expects_myclass_descendant(MyClass()) +expects_myclass_descendant(object) +expects_myclass_descendant(object()) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java index 62775974104c..4b0e8ac896c0 100644 --- a/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java @@ -198,4 +198,9 @@ public class Py3TypeCheckerInspectionTest extends PyTestCase { public void testBuiltinInputPy3() { doTest(); } + + // PY-200057 + public void testClassObjectType() { + doTest(); + } }