From 694dadf51aa2fa7c6cbf9632154f9fd4f399c046 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 9 Aug 2011 21:16:44 +0400 Subject: [PATCH 1/2] Fixed nondeterministic ordering in union types, added test data (PY-3496, CR-PY-170) --- .../python/refactoring/PyDefUseUtil.java | 16 ++-------------- python/testData/quickdoc/Variable.html | 1 + python/testData/quickdoc/Variable.py | 6 ++++++ 3 files changed, 9 insertions(+), 14 deletions(-) create mode 100644 python/testData/quickdoc/Variable.html create mode 100644 python/testData/quickdoc/Variable.py diff --git a/python/src/com/jetbrains/python/refactoring/PyDefUseUtil.java b/python/src/com/jetbrains/python/refactoring/PyDefUseUtil.java index 6ebdfb0c79be..e2539f44c9d6 100644 --- a/python/src/com/jetbrains/python/refactoring/PyDefUseUtil.java +++ b/python/src/com/jetbrains/python/refactoring/PyDefUseUtil.java @@ -33,21 +33,9 @@ public class PyDefUseUtil { throw new InstructionNotFoundException(); } final boolean[] visited = new boolean[instructions.length]; - final Collection result = new HashSet(); + final Collection result = new LinkedHashSet(); getLatestDefs(var, instructions, instr, visited, result); - final List sortedResult = new ArrayList(); - sortedResult.addAll(result); - Collections.sort(sortedResult, new Comparator() { - @Override - public int compare(PyElement e1, PyElement e2) { - final String n1 = e1.getName(); - if (n1 != null) { - return n1.compareTo(e2.getName()); - } - return 0; - } - }); - return sortedResult.toArray(new PyElement[sortedResult.size()]); + return result.toArray(new PyElement[result.size()]); } private static void getLatestDefs(final PyElement var, diff --git a/python/testData/quickdoc/Variable.html b/python/testData/quickdoc/Variable.html new file mode 100644 index 000000000000..3b9fee740875 --- /dev/null +++ b/python/testData/quickdoc/Variable.html @@ -0,0 +1 @@ +Assigned to y

Inferred type: one of (str, int)
\ No newline at end of file diff --git a/python/testData/quickdoc/Variable.py b/python/testData/quickdoc/Variable.py new file mode 100644 index 000000000000..9fdac0d1b811 --- /dev/null +++ b/python/testData/quickdoc/Variable.py @@ -0,0 +1,6 @@ +def f(x): + if x: + y = 1 + else: + y = 'foo' + return y \ No newline at end of file From 2898448021376356849372f5e321b43946cae35f Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 9 Aug 2011 21:23:23 +0400 Subject: [PATCH 2/2] Ignore Python union types with unknown components during type checking --- .../python/psi/types/PyTypeChecker.java | 12 +++- .../python/psi/types/PyTypeParser.java | 4 +- .../PyTypeCheckerInspection/test.py | 63 ++++++++++++++++++- 3 files changed, 73 insertions(+), 6 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index 95f8408722ba..f687a0147188 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -3,6 +3,8 @@ package com.jetbrains.python.psi.types; import com.jetbrains.python.psi.PyClass; import org.jetbrains.annotations.Nullable; +import java.util.List; + /** * @author vlan */ @@ -22,8 +24,14 @@ public class PyTypeChecker { return match(expected, ((PyTypeReference)actual).resolve(null, context), context); } if (actual instanceof PyUnionType) { - for (PyType t : ((PyUnionType)actual).getMembers()) { - if (!match(expected, t, context)) { + final List members = ((PyUnionType)actual).getMembers(); + for (PyType m : members) { + if (m == null) { + return true; + } + } + for (PyType m : members) { + if (!match(expected, m, context)) { return false; } } diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeParser.java b/python/src/com/jetbrains/python/psi/types/PyTypeParser.java index d541496f1cc6..83fd47d9c3de 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeParser.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeParser.java @@ -237,9 +237,7 @@ public class PyTypeParser { PyType result = null; for (TextRange range : ranges) { final PyType t = parse(anchor, range.substring(type), types, fullRanges, offset + range.getStartOffset()); - if (t != null) { - result = (result == null) ? t : PyUnionType.union(result, t); - } + result = (result == null) ? t : PyUnionType.union(result, t); } return result; } diff --git a/python/testData/inspections/PyTypeCheckerInspection/test.py b/python/testData/inspections/PyTypeCheckerInspection/test.py index e1111cb9740c..b49e4b8cc137 100644 --- a/python/testData/inspections/PyTypeCheckerInspection/test.py +++ b/python/testData/inspections/PyTypeCheckerInspection/test.py @@ -220,4 +220,65 @@ def test_old_style_classes(): :type x: object """ pass - f(C()) #pass \ No newline at end of file + f(C()) #pass + + +def test_partly_unknown_type(): + def f(): + """ + :rtype: None or unknown or int or long + """ + def g(x): + """ + :type x: object + """ + g(f()) + + +def test_type_assertions(): + def f_1(): + """ + :rtype: int or str or None + """ + def f_2(): + """ + :rtype: int or None + """ + def f_3(): + """ + :rtype: unknown + """ + def f_4(): + """ + :rtype: object + """ + def f_5(): + """ + :rtype: int or object + """ + def f_6(): + """ + :rtype: int or unknown or float + """ + def f_7(): + """ + :rtype: int or unknown + """ + def print_int(x): + """ + :type x: int + """ + print(x) + def print_int_or_str(x): + """ + :type x: int or str + """ + x_1 = f_1() + print_int(x_1) + print_int_or_str(x_1) + if isinstance(x_1, int): + print_int(x_1) + if isinstance(x_1, str): + print_int_or_str(x_1) + x_7 = f_7() + print_int(x_7) \ No newline at end of file