diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/controlflow/PyTypeAssertionEvaluator.java b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/controlflow/PyTypeAssertionEvaluator.java index 2422c37e8aa3..e0aeae237934 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/controlflow/PyTypeAssertionEvaluator.java +++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/controlflow/PyTypeAssertionEvaluator.java @@ -68,7 +68,12 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor { } private void visitExpressionInCondition(@NotNull PyExpression node) { - if (myPositive && (isIfReferenceStatement(node) || isIfReferenceConditionalStatement(node) || isIfNotReferenceStatement(node))) { + if (myPositive && ( + isIfReferenceStatement(node) || + isIfReferenceConditionalStatement(node) || + isBinaryExpressionPart(node) + )) { + // TODO: we can actually check if the class defines __bool__ or __len__, and use it to exclude the type // we could not suggest `None` because it could be a reference to an empty collection // so we could push only non-`None` assertions pushAssertion(node, !myPositive, context -> PyBuiltinCache.getInstance(node).getNoneType()); @@ -393,23 +398,30 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor { }; } - + private static @Nullable PsiElement skipNotAndParens(@Nullable PsiElement element) { + if (element == null) return null; + for (PsiElement e = element.getParent(); e != null; e = e.getParent()) { + if (!(e instanceof PyParenthesizedExpression) && + !(e instanceof PyPrefixExpression prefixExpr && prefixExpr.getOperator() == PyTokenTypes.NOT_KEYWORD)) { + return e; + } + } + return null; + } private static boolean isIfReferenceStatement(@NotNull PyExpression node) { - return PsiTreeUtil.skipParentsOfType(node, PyParenthesizedExpression.class) instanceof PyIfPart; + return skipNotAndParens(node) instanceof PyConditionalStatementPart; } private static boolean isIfReferenceConditionalStatement(@NotNull PyExpression node) { - final PsiElement parent = PsiTreeUtil.skipParentsOfType(node, PyParenthesizedExpression.class); + final PsiElement parent = skipNotAndParens(node); return parent instanceof PyConditionalExpression cond && PsiTreeUtil.isAncestor(cond.getCondition(), node, false); } - private static boolean isIfNotReferenceStatement(@NotNull PyExpression node) { - final PsiElement parent = PsiTreeUtil.skipParentsOfType(node, PyParenthesizedExpression.class); - return parent instanceof PyPrefixExpression && - ((PyPrefixExpression)parent).getOperator() == PyTokenTypes.NOT_KEYWORD && - parent.getParent() instanceof PyIfPart; + private static boolean isBinaryExpressionPart(@NotNull PyExpression node) { + return skipNotAndParens(node) instanceof PyBinaryExpression binExpr && + (binExpr.isOperator(PyNames.AND) || binExpr.isOperator(PyNames.OR)); } static class Assertion { diff --git a/python/testData/codeInsight/controlflow/AndBooleanExpression.txt b/python/testData/codeInsight/controlflow/AndBooleanExpression.txt index ea39136f0e94..118e1b18bd49 100644 --- a/python/testData/codeInsight/controlflow/AndBooleanExpression.txt +++ b/python/testData/codeInsight/controlflow/AndBooleanExpression.txt @@ -2,10 +2,12 @@ 1(2) element: PyAssignmentStatement 2(3) element: PyBinaryExpression 3(4,5) READ ACCESS: bar -4(9) element: null. Condition: bar:false +4(11) element: null. Condition: bar:false 5(6) element: null. Condition: bar:true -6(7,8) READ ACCESS: baz -7(9) element: null. Condition: baz:false -8(9) element: null. Condition: baz:true -9(10) WRITE ACCESS: foo -10() element: null \ No newline at end of file +6(7) ASSERTTYPE ACCESS: bar +7(8,9) READ ACCESS: baz +8(11) element: null. Condition: baz:false +9(10) element: null. Condition: baz:true +10(11) ASSERTTYPE ACCESS: baz +11(12) WRITE ACCESS: foo +12() element: null \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/AssignmentExpressionInsideBinaryInWhile.txt b/python/testData/codeInsight/controlflow/AssignmentExpressionInsideBinaryInWhile.txt index aa59d17b3fd9..cfd7c3665369 100644 --- a/python/testData/codeInsight/controlflow/AssignmentExpressionInsideBinaryInWhile.txt +++ b/python/testData/codeInsight/controlflow/AssignmentExpressionInsideBinaryInWhile.txt @@ -2,27 +2,31 @@ 1(2) element: PyWhileStatement 2(3) element: PyBinaryExpression 3(4,5) READ ACCESS: undefined1 -4(14) element: null. Condition: undefined1:false +4(16) element: null. Condition: undefined1:false 5(6) element: null. Condition: undefined1:true -6(7) READ ACCESS: undefined2 -7(8) element: PyCallExpression: undefined2 -8(9,10) WRITE ACCESS: r -9(14) element: null. Condition: (r := undefined2()):false -10(11) element: null. Condition: (r := undefined2()):true -11(12) element: PyStatementList -12(13) element: PyPrintStatement -13(1) READ ACCESS: r -14(15) element: PyWhileStatement -15(16) element: PyBinaryExpression -16(17,18) READ ACCESS: undefined3 -17(19) element: null. Condition: undefined3:false -18(24) element: null. Condition: undefined3:true -19(20) READ ACCESS: undefined4 -20(21) element: PyCallExpression: undefined4 -21(22,23) WRITE ACCESS: r2 -22(27) element: null. Condition: (r2 := undefined4()):false -23(24) element: null. Condition: (r2 := undefined4()):true -24(25) element: PyStatementList -25(26) element: PyPrintStatement -26(14) READ ACCESS: r2 -27() element: null \ No newline at end of file +6(7) ASSERTTYPE ACCESS: undefined1 +7(8) READ ACCESS: undefined2 +8(9) element: PyCallExpression: undefined2 +9(10,11) WRITE ACCESS: r +10(16) element: null. Condition: (r := undefined2()):false +11(12) element: null. Condition: (r := undefined2()):true +12(13) ASSERTTYPE ACCESS: r +13(14) element: PyStatementList +14(15) element: PyPrintStatement +15(1) READ ACCESS: r +16(17) element: PyWhileStatement +17(18) element: PyBinaryExpression +18(19,20) READ ACCESS: undefined3 +19(22) element: null. Condition: undefined3:false +20(21) element: null. Condition: undefined3:true +21(28) ASSERTTYPE ACCESS: undefined3 +22(23) READ ACCESS: undefined4 +23(24) element: PyCallExpression: undefined4 +24(25,26) WRITE ACCESS: r2 +25(31) element: null. Condition: (r2 := undefined4()):false +26(27) element: null. Condition: (r2 := undefined4()):true +27(28) ASSERTTYPE ACCESS: r2 +28(29) element: PyStatementList +29(30) element: PyPrintStatement +30(16) READ ACCESS: r2 +31() element: null \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/AssignmentExpressionInsideBinaryInWhileElse.txt b/python/testData/codeInsight/controlflow/AssignmentExpressionInsideBinaryInWhileElse.txt index 2f9bbd7576bc..5dc66a87b9b1 100644 --- a/python/testData/codeInsight/controlflow/AssignmentExpressionInsideBinaryInWhileElse.txt +++ b/python/testData/codeInsight/controlflow/AssignmentExpressionInsideBinaryInWhileElse.txt @@ -2,31 +2,35 @@ 1(2) element: PyWhileStatement 2(3) element: PyBinaryExpression 3(4,5) READ ACCESS: undefined1 -4(14) element: null. Condition: undefined1:false +4(16) element: null. Condition: undefined1:false 5(6) element: null. Condition: undefined1:true -6(7) READ ACCESS: undefined2 -7(8) element: PyCallExpression: undefined2 -8(9,10) WRITE ACCESS: r -9(14) element: null. Condition: (r := undefined2()):false -10(11) element: null. Condition: (r := undefined2()):true -11(12) element: PyStatementList -12(13) element: PyPrintStatement -13(1) READ ACCESS: r -14(15) element: PyStatementList -15(16) element: PyPrintStatement -16(17) element: PyWhileStatement -17(18) element: PyBinaryExpression -18(19,20) READ ACCESS: undefined3 -19(21) element: null. Condition: undefined3:false -20(26) element: null. Condition: undefined3:true -21(22) READ ACCESS: undefined4 -22(23) element: PyCallExpression: undefined4 -23(24,25) WRITE ACCESS: r2 -24(29) element: null. Condition: (r2 := undefined4()):false -25(26) element: null. Condition: (r2 := undefined4()):true -26(27) element: PyStatementList -27(28) element: PyPrintStatement -28(16) READ ACCESS: r2 -29(30) element: PyStatementList -30(31) element: PyPrintStatement -31() element: null \ No newline at end of file +6(7) ASSERTTYPE ACCESS: undefined1 +7(8) READ ACCESS: undefined2 +8(9) element: PyCallExpression: undefined2 +9(10,11) WRITE ACCESS: r +10(16) element: null. Condition: (r := undefined2()):false +11(12) element: null. Condition: (r := undefined2()):true +12(13) ASSERTTYPE ACCESS: r +13(14) element: PyStatementList +14(15) element: PyPrintStatement +15(1) READ ACCESS: r +16(17) element: PyStatementList +17(18) element: PyPrintStatement +18(19) element: PyWhileStatement +19(20) element: PyBinaryExpression +20(21,22) READ ACCESS: undefined3 +21(24) element: null. Condition: undefined3:false +22(23) element: null. Condition: undefined3:true +23(30) ASSERTTYPE ACCESS: undefined3 +24(25) READ ACCESS: undefined4 +25(26) element: PyCallExpression: undefined4 +26(27,28) WRITE ACCESS: r2 +27(33) element: null. Condition: (r2 := undefined4()):false +28(29) element: null. Condition: (r2 := undefined4()):true +29(30) ASSERTTYPE ACCESS: r2 +30(31) element: PyStatementList +31(32) element: PyPrintStatement +32(18) READ ACCESS: r2 +33(34) element: PyStatementList +34(35) element: PyPrintStatement +35() element: null \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/Break.txt b/python/testData/codeInsight/controlflow/Break.txt index d448f9451a41..f35e00206d1d 100644 --- a/python/testData/codeInsight/controlflow/Break.txt +++ b/python/testData/codeInsight/controlflow/Break.txt @@ -1,15 +1,16 @@ 0(1) element: null 1(2) element: PyWhileStatement 2(3,4) READ ACCESS: foo -3(14) element: null. Condition: foo:false +3(15) element: null. Condition: foo:false 4(5) element: null. Condition: foo:true -5(6) element: PyStatementList -6(7) element: PyIfStatement -7(8,9) READ ACCESS: condition -8(13) element: null. Condition: condition:false -9(10) element: null. Condition: condition:true -10(11) ASSERTTYPE ACCESS: condition -11(12) element: PyStatementList -12(14) element: PyBreakStatement -13(1) element: PyPrintStatement -14() element: null \ No newline at end of file +5(6) ASSERTTYPE ACCESS: foo +6(7) element: PyStatementList +7(8) element: PyIfStatement +8(9,10) READ ACCESS: condition +9(14) element: null. Condition: condition:false +10(11) element: null. Condition: condition:true +11(12) ASSERTTYPE ACCESS: condition +12(13) element: PyStatementList +13(15) element: PyBreakStatement +14(1) element: PyPrintStatement +15() element: null \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/Continue.txt b/python/testData/codeInsight/controlflow/Continue.txt index cbad412f1411..a1d4da7e34c4 100644 --- a/python/testData/codeInsight/controlflow/Continue.txt +++ b/python/testData/codeInsight/controlflow/Continue.txt @@ -1,15 +1,16 @@ 0(1) element: null 1(2) element: PyWhileStatement 2(3,4) READ ACCESS: foo -3(14) element: null. Condition: foo:false +3(15) element: null. Condition: foo:false 4(5) element: null. Condition: foo:true -5(6) element: PyStatementList -6(7) element: PyIfStatement -7(8,9) READ ACCESS: condition -8(13) element: null. Condition: condition:false -9(10) element: null. Condition: condition:true -10(11) ASSERTTYPE ACCESS: condition -11(12) element: PyStatementList -12(1) element: PyContinueStatement -13(1) element: PyPrintStatement -14() element: null \ No newline at end of file +5(6) ASSERTTYPE ACCESS: foo +6(7) element: PyStatementList +7(8) element: PyIfStatement +8(9,10) READ ACCESS: condition +9(14) element: null. Condition: condition:false +10(11) element: null. Condition: condition:true +11(12) ASSERTTYPE ACCESS: condition +12(13) element: PyStatementList +13(1) element: PyContinueStatement +14(1) element: PyPrintStatement +15() element: null \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/Function.txt b/python/testData/codeInsight/controlflow/Function.txt index ad5e48966139..e6d262dd5ada 100644 --- a/python/testData/codeInsight/controlflow/Function.txt +++ b/python/testData/codeInsight/controlflow/Function.txt @@ -25,32 +25,33 @@ 24(25) element: PyBinaryExpression 25(26) element: PyBinaryExpression 26(27,28) READ ACCESS: collapse -27(32) element: null. Condition: collapse:false +27(33) element: null. Condition: collapse:false 28(29) element: null. Condition: collapse:true -29(30,31) element: PyLambdaExpression -30(32) element: null. Condition: (lambda s: " ".join(s.split())):false -31(35) element: null. Condition: (lambda s: " ".join(s.split())):true -32(33,34) element: PyLambdaExpression -33(35) element: null. Condition: (lambda s: s):false -34(35) element: null. Condition: (lambda s: s):true -35(36) WRITE ACCESS: processFunc -36(37) element: PyPrintStatement -37(38) element: PyListCompExpression -38(39) element: PyReferenceExpression: methodList -39(40,54) READ ACCESS: methodList -40(41) element: PyTargetExpression: method -41(42) WRITE ACCESS: method -42(43) element: PyBinaryExpression -43(44) READ ACCESS: method -44(45) READ ACCESS: spacing -45(46) element: PyCallExpression: method.ljust -46(47) READ ACCESS: processFunc -47(48) READ ACCESS: str -48(49) READ ACCESS: getattr -49(50) READ ACCESS: object -50(51) READ ACCESS: method -51(52) element: PyCallExpression: getattr -52(53) element: PyCallExpression: str -53(40,54) element: PyCallExpression: processFunc -54(55) element: PyCallExpression: "\n".join -55() element: null \ No newline at end of file +29(30) ASSERTTYPE ACCESS: collapse +30(31,32) element: PyLambdaExpression +31(33) element: null. Condition: (lambda s: " ".join(s.split())):false +32(36) element: null. Condition: (lambda s: " ".join(s.split())):true +33(34,35) element: PyLambdaExpression +34(36) element: null. Condition: (lambda s: s):false +35(36) element: null. Condition: (lambda s: s):true +36(37) WRITE ACCESS: processFunc +37(38) element: PyPrintStatement +38(39) element: PyListCompExpression +39(40) element: PyReferenceExpression: methodList +40(41,55) READ ACCESS: methodList +41(42) element: PyTargetExpression: method +42(43) WRITE ACCESS: method +43(44) element: PyBinaryExpression +44(45) READ ACCESS: method +45(46) READ ACCESS: spacing +46(47) element: PyCallExpression: method.ljust +47(48) READ ACCESS: processFunc +48(49) READ ACCESS: str +49(50) READ ACCESS: getattr +50(51) READ ACCESS: object +51(52) READ ACCESS: method +52(53) element: PyCallExpression: getattr +53(54) element: PyCallExpression: str +54(41,55) element: PyCallExpression: processFunc +55(56) element: PyCallExpression: "\n".join +56() element: null \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/MatchStatementClauseWithBreak.txt b/python/testData/codeInsight/controlflow/MatchStatementClauseWithBreak.txt index 60a057dc3e03..693d445fca01 100644 --- a/python/testData/codeInsight/controlflow/MatchStatementClauseWithBreak.txt +++ b/python/testData/codeInsight/controlflow/MatchStatementClauseWithBreak.txt @@ -1,19 +1,20 @@ 0(1) element: null 1(2) element: PyWhileStatement 2(3,4) READ ACCESS: x -3(16) element: null. Condition: x:false +3(17) element: null. Condition: x:false 4(5) element: null. Condition: x:true -5(6) element: PyStatementList -6(7) element: PyMatchStatement -7(8) READ ACCESS: x -8(9,13) refutable pattern: 42 -9(10) matched pattern: 42 -10(11) ASSERTTYPE ACCESS: x -11(12) element: PyStatementList -12(16) element: PyBreakStatement -13(14) ASSERTTYPE ACCESS: x -14(15) element: PyExpressionStatement -15(1) READ ACCESS: y -16(17) element: PyExpressionStatement -17(18) READ ACCESS: z -18() element: null \ No newline at end of file +5(6) ASSERTTYPE ACCESS: x +6(7) element: PyStatementList +7(8) element: PyMatchStatement +8(9) READ ACCESS: x +9(10,14) refutable pattern: 42 +10(11) matched pattern: 42 +11(12) ASSERTTYPE ACCESS: x +12(13) element: PyStatementList +13(17) element: PyBreakStatement +14(15) ASSERTTYPE ACCESS: x +15(16) element: PyExpressionStatement +16(1) READ ACCESS: y +17(18) element: PyExpressionStatement +18(19) READ ACCESS: z +19() element: null \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/MatchStatementClauseWithContinue.txt b/python/testData/codeInsight/controlflow/MatchStatementClauseWithContinue.txt index 3b4130587aa7..b6875cab6e97 100644 --- a/python/testData/codeInsight/controlflow/MatchStatementClauseWithContinue.txt +++ b/python/testData/codeInsight/controlflow/MatchStatementClauseWithContinue.txt @@ -1,19 +1,20 @@ 0(1) element: null 1(2) element: PyWhileStatement 2(3,4) READ ACCESS: x -3(16) element: null. Condition: x:false +3(17) element: null. Condition: x:false 4(5) element: null. Condition: x:true -5(6) element: PyStatementList -6(7) element: PyMatchStatement -7(8) READ ACCESS: x -8(9,13) refutable pattern: 42 -9(10) matched pattern: 42 -10(11) ASSERTTYPE ACCESS: x -11(12) element: PyStatementList -12(1) element: PyContinueStatement -13(14) ASSERTTYPE ACCESS: x -14(15) element: PyExpressionStatement -15(1) READ ACCESS: y -16(17) element: PyExpressionStatement -17(18) READ ACCESS: z -18() element: null \ No newline at end of file +5(6) ASSERTTYPE ACCESS: x +6(7) element: PyStatementList +7(8) element: PyMatchStatement +8(9) READ ACCESS: x +9(10,14) refutable pattern: 42 +10(11) matched pattern: 42 +11(12) ASSERTTYPE ACCESS: x +12(13) element: PyStatementList +13(1) element: PyContinueStatement +14(15) ASSERTTYPE ACCESS: x +15(16) element: PyExpressionStatement +16(1) READ ACCESS: y +17(18) element: PyExpressionStatement +18(19) READ ACCESS: z +19() element: null \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/MatchStatementSingleClauseGuardWithNonTopLevelDisjunction.txt b/python/testData/codeInsight/controlflow/MatchStatementSingleClauseGuardWithNonTopLevelDisjunction.txt index 6385736f7557..3d789bf80911 100644 --- a/python/testData/codeInsight/controlflow/MatchStatementSingleClauseGuardWithNonTopLevelDisjunction.txt +++ b/python/testData/codeInsight/controlflow/MatchStatementSingleClauseGuardWithNonTopLevelDisjunction.txt @@ -1,24 +1,26 @@ 0(1) element: null 1(2) element: PyMatchStatement -2(3,20) refutable pattern: [x1, x2, x3] -3(4,20) WRITE ACCESS: x1 -4(5,20) WRITE ACCESS: x2 -5(6,20) WRITE ACCESS: x3 +2(3,22) refutable pattern: [x1, x2, x3] +3(4,22) WRITE ACCESS: x1 +4(5,22) WRITE ACCESS: x2 +5(6,22) WRITE ACCESS: x3 6(7) matched pattern: [x1, x2, x3] 7(8) element: PyBinaryExpression 8(9,10) READ ACCESS: x1 -9(11) element: null. Condition: x1:false -10(17) element: null. Condition: x1:true -11(12,13,14) READ ACCESS: x2 -12(20) element: null. Condition: x2:false -13(17) element: null. Condition: x2:true -14(15,16) READ ACCESS: x3 -15(20) element: null. Condition: (x1 or x2) > x3:false -16(17) element: null. Condition: (x1 or x2) > x3:true -17(18) element: PyStatementList -18(19) element: PyExpressionStatement -19(21) READ ACCESS: y -20(21) ASSERTTYPE ACCESS: null -21(22) element: PyExpressionStatement -22(23) READ ACCESS: z -23() element: null \ No newline at end of file +9(12) element: null. Condition: x1:false +10(11) element: null. Condition: x1:true +11(19) ASSERTTYPE ACCESS: x1 +12(13,14,16) READ ACCESS: x2 +13(22) element: null. Condition: x2:false +14(15) element: null. Condition: x2:true +15(19) ASSERTTYPE ACCESS: x2 +16(17,18) READ ACCESS: x3 +17(22) element: null. Condition: (x1 or x2) > x3:false +18(19) element: null. Condition: (x1 or x2) > x3:true +19(20) element: PyStatementList +20(21) element: PyExpressionStatement +21(23) READ ACCESS: y +22(23) ASSERTTYPE ACCESS: null +23(24) element: PyExpressionStatement +24(25) READ ACCESS: z +25() element: null \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/OrBooleanExpression.txt b/python/testData/codeInsight/controlflow/OrBooleanExpression.txt index f5cf83aa2680..e2ad1a9b400b 100644 --- a/python/testData/codeInsight/controlflow/OrBooleanExpression.txt +++ b/python/testData/codeInsight/controlflow/OrBooleanExpression.txt @@ -2,10 +2,12 @@ 1(2) element: PyAssignmentStatement 2(3) element: PyBinaryExpression 3(4,5) READ ACCESS: bar -4(6) element: null. Condition: bar:false -5(9) element: null. Condition: bar:true -6(7,8) READ ACCESS: baz -7(9) element: null. Condition: baz:false -8(9) element: null. Condition: baz:true -9(10) WRITE ACCESS: foo -10() element: null \ No newline at end of file +4(7) element: null. Condition: bar:false +5(6) element: null. Condition: bar:true +6(11) ASSERTTYPE ACCESS: bar +7(8,9) READ ACCESS: baz +8(11) element: null. Condition: baz:false +9(10) element: null. Condition: baz:true +10(11) ASSERTTYPE ACCESS: baz +11(12) WRITE ACCESS: foo +12() element: null \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/Return.txt b/python/testData/codeInsight/controlflow/Return.txt index 9e4c1327d3e4..fc2d5b4568d3 100644 --- a/python/testData/codeInsight/controlflow/Return.txt +++ b/python/testData/codeInsight/controlflow/Return.txt @@ -1,15 +1,16 @@ 0(1) element: null 1(2) element: PyWhileStatement 2(3,4) READ ACCESS: foo -3(14) element: null. Condition: foo:false +3(15) element: null. Condition: foo:false 4(5) element: null. Condition: foo:true -5(6) element: PyStatementList -6(7) element: PyIfStatement -7(8,9) READ ACCESS: condition -8(13) element: null. Condition: condition:false -9(10) element: null. Condition: condition:true -10(11) ASSERTTYPE ACCESS: condition -11(12) element: PyStatementList -12(14) element: PyReturnStatement -13(1) element: PyPrintStatement -14() element: null \ No newline at end of file +5(6) ASSERTTYPE ACCESS: foo +6(7) element: PyStatementList +7(8) element: PyIfStatement +8(9,10) READ ACCESS: condition +9(14) element: null. Condition: condition:false +10(11) element: null. Condition: condition:true +11(12) ASSERTTYPE ACCESS: condition +12(13) element: PyStatementList +13(15) element: PyReturnStatement +14(1) element: PyPrintStatement +15() element: null \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/TypesInAndBooleanExpression.txt b/python/testData/codeInsight/controlflow/TypesInAndBooleanExpression.txt index 6b86916f8dc8..0b80f7cecaca 100644 --- a/python/testData/codeInsight/controlflow/TypesInAndBooleanExpression.txt +++ b/python/testData/codeInsight/controlflow/TypesInAndBooleanExpression.txt @@ -12,12 +12,13 @@ 11(12) READ ACCESS: A 12(13,15) element: PyCallExpression: isinstance 13(14) element: null. Condition: isinstance(var, A):false -14(22) ASSERTTYPE ACCESS: var +14(23) ASSERTTYPE ACCESS: var 15(16) element: null. Condition: isinstance(var, A):true 16(17) ASSERTTYPE ACCESS: var 17(18,19) READ ACCESS: var -18(22) element: null. Condition: var:false +18(23) element: null. Condition: var:false 19(20) element: null. Condition: var:true -20(21) element: PyStatementList -21(22) element: PyPassStatement -22() element: null \ No newline at end of file +20(21) ASSERTTYPE ACCESS: var +21(22) element: PyStatementList +22(23) element: PyPassStatement +23() element: null \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/TypesInOrBooleanExpression.txt b/python/testData/codeInsight/controlflow/TypesInOrBooleanExpression.txt index af6d1b18ece5..a890ab97d29e 100644 --- a/python/testData/codeInsight/controlflow/TypesInOrBooleanExpression.txt +++ b/python/testData/codeInsight/controlflow/TypesInOrBooleanExpression.txt @@ -9,7 +9,7 @@ 8(9) READ ACCESS: A 9(10,12) element: PyCallExpression: isinstance 10(11) element: null. Condition: isinstance(var, A):false -11(30) ASSERTTYPE ACCESS: var +11(31) ASSERTTYPE ACCESS: var 12(13) element: null. Condition: isinstance(var, A):true 13(14) ASSERTTYPE ACCESS: var 14(15) element: PyStatementList @@ -22,10 +22,11 @@ 21(22) element: null. Condition: isinstance(var, B):false 22(25) ASSERTTYPE ACCESS: var 23(24) element: null. Condition: isinstance(var, B):true -24(28) ASSERTTYPE ACCESS: var +24(29) ASSERTTYPE ACCESS: var 25(26,27) READ ACCESS: var -26(30) element: null. Condition: var:false +26(31) element: null. Condition: var:false 27(28) element: null. Condition: var:true -28(29) element: PyStatementList -29(30) element: PyPassStatement -30() element: null \ No newline at end of file +28(29) ASSERTTYPE ACCESS: var +29(30) element: PyStatementList +30(31) element: PyPassStatement +31() element: null \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/While.txt b/python/testData/codeInsight/controlflow/While.txt index 479f93c00acb..3c848ac41d2c 100644 --- a/python/testData/codeInsight/controlflow/While.txt +++ b/python/testData/codeInsight/controlflow/While.txt @@ -1,58 +1,62 @@ 0(1) element: null 1(2) element: PyWhileStatement 2(3,4) READ ACCESS: c1 -3(8) element: null. Condition: c1:false +3(9) element: null. Condition: c1:false 4(5) element: null. Condition: c1:true -5(6) element: PyStatementList -6(7) element: PyAssignmentStatement -7(1) WRITE ACCESS: x -8(9) element: PyStatementList -9(10) element: PyAssignmentStatement -10(11) WRITE ACCESS: y -11(12) element: PyWhileStatement -12(13,14) READ ACCESS: c2 -13(21) element: null. Condition: c2:false -14(15) element: null. Condition: c2:true -15(16) element: PyStatementList -16(17) element: PyAssignmentStatement -17(18) WRITE ACCESS: a -18(24) element: PyBreakStatement -19(20) element: PyAssignmentStatement -20(11) WRITE ACCESS: b -21(22) element: PyStatementList -22(23) element: PyAssignmentStatement -23(24) WRITE ACCESS: c -24(25) element: PyWhileStatement -25(26,27) READ ACCESS: c3 -26(40) element: null. Condition: c3:false -27(28) element: null. Condition: c3:true -28(29) element: PyStatementList -29(30) element: PyAssignmentStatement -30(31) WRITE ACCESS: m -31(32) element: PyIfStatement -32(33,34) READ ACCESS: m -33(38) element: null. Condition: m:false -34(35) element: null. Condition: m:true -35(36) ASSERTTYPE ACCESS: m -36(37) element: PyStatementList -37(43) element: PyBreakStatement -38(39) element: PyAssignmentStatement -39(24) WRITE ACCESS: n -40(41) element: PyStatementList +5(6) ASSERTTYPE ACCESS: c1 +6(7) element: PyStatementList +7(8) element: PyAssignmentStatement +8(1) WRITE ACCESS: x +9(10) element: PyStatementList +10(11) element: PyAssignmentStatement +11(12) WRITE ACCESS: y +12(13) element: PyWhileStatement +13(14,15) READ ACCESS: c2 +14(23) element: null. Condition: c2:false +15(16) element: null. Condition: c2:true +16(17) ASSERTTYPE ACCESS: c2 +17(18) element: PyStatementList +18(19) element: PyAssignmentStatement +19(20) WRITE ACCESS: a +20(26) element: PyBreakStatement +21(22) element: PyAssignmentStatement +22(12) WRITE ACCESS: b +23(24) element: PyStatementList +24(25) element: PyAssignmentStatement +25(26) WRITE ACCESS: c +26(27) element: PyWhileStatement +27(28,29) READ ACCESS: c3 +28(43) element: null. Condition: c3:false +29(30) element: null. Condition: c3:true +30(31) ASSERTTYPE ACCESS: c3 +31(32) element: PyStatementList +32(33) element: PyAssignmentStatement +33(34) WRITE ACCESS: m +34(35) element: PyIfStatement +35(36,37) READ ACCESS: m +36(41) element: null. Condition: m:false +37(38) element: null. Condition: m:true +38(39) ASSERTTYPE ACCESS: m +39(40) element: PyStatementList +40(46) element: PyBreakStatement 41(42) element: PyAssignmentStatement -42(43) WRITE ACCESS: o -43(44) element: PyWhileStatement -44(45,46) READ ACCESS: c4 -45(57) element: null. Condition: c4:false -46(47) element: null. Condition: c4:true -47(48) element: PyStatementList -48(49) element: PyAssignmentStatement -49(50) WRITE ACCESS: m -50(51) element: PyIfStatement -51(52,53) READ ACCESS: m -52(43) element: null. Condition: m:false -53(54) element: null. Condition: m:true -54(55) ASSERTTYPE ACCESS: m -55(56) element: PyStatementList -56(57) element: PyBreakStatement -57() element: null \ No newline at end of file +42(26) WRITE ACCESS: n +43(44) element: PyStatementList +44(45) element: PyAssignmentStatement +45(46) WRITE ACCESS: o +46(47) element: PyWhileStatement +47(48,49) READ ACCESS: c4 +48(61) element: null. Condition: c4:false +49(50) element: null. Condition: c4:true +50(51) ASSERTTYPE ACCESS: c4 +51(52) element: PyStatementList +52(53) element: PyAssignmentStatement +53(54) WRITE ACCESS: m +54(55) element: PyIfStatement +55(56,57) READ ACCESS: m +56(46) element: null. Condition: m:false +57(58) element: null. Condition: m:true +58(59) ASSERTTYPE ACCESS: m +59(60) element: PyStatementList +60(61) element: PyBreakStatement +61() element: null \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/WhileInsideIfTrue.txt b/python/testData/codeInsight/controlflow/WhileInsideIfTrue.txt index 8f489f25bb8b..62346a5c1458 100644 --- a/python/testData/codeInsight/controlflow/WhileInsideIfTrue.txt +++ b/python/testData/codeInsight/controlflow/WhileInsideIfTrue.txt @@ -1,17 +1,18 @@ 0(1) element: null 1(2) element: PyIfStatement 2(3,4) READ ACCESS: True -3(13) element: null. Condition: True:false +3(14) element: null. Condition: True:false 4(5) element: null. Condition: True:true 5(6) ASSERTTYPE ACCESS: True 6(7) element: PyStatementList 7(8) element: PyWhileStatement 8(9,10) READ ACCESS: expr -9(16) element: null. Condition: expr:false +9(17) element: null. Condition: expr:false 10(11) element: null. Condition: expr:true -11(12) element: PyStatementList -12(16) element: PyBreakStatement -13(14) ASSERTTYPE ACCESS: null -14(15) element: PyStatementList -15(16) element: PyPrintStatement -16() element: null \ No newline at end of file +11(12) ASSERTTYPE ACCESS: expr +12(13) element: PyStatementList +13(17) element: PyBreakStatement +14(15) ASSERTTYPE ACCESS: null +15(16) element: PyStatementList +16(17) element: PyPrintStatement +17() element: null \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/WhileTrueBreakInsideExcept.txt b/python/testData/codeInsight/controlflow/WhileTrueBreakInsideExcept.txt index efaf39d95465..86d86ee2da8a 100644 --- a/python/testData/codeInsight/controlflow/WhileTrueBreakInsideExcept.txt +++ b/python/testData/codeInsight/controlflow/WhileTrueBreakInsideExcept.txt @@ -3,16 +3,17 @@ 2(3,4) READ ACCESS: True 3() element: null. Condition: True:false 4(5) element: null. Condition: True:true -5(6) element: PyStatementList -6(7) element: PyTryExceptStatement -7(8,12) element: PyTryPart -8(9,12) element: PyAssignmentStatement -9(10,12) READ ACCESS: could_raise -10(11,12) element: PyCallExpression: could_raise -11(12,15) WRITE ACCESS: foo -12(13) element: PyExceptPart -13(14) READ ACCESS: IndexError -14(17) element: PyBreakStatement -15(16) element: PyPrintStatement -16(1) READ ACCESS: foo -17() element: null \ No newline at end of file +5(6) ASSERTTYPE ACCESS: True +6(7) element: PyStatementList +7(8) element: PyTryExceptStatement +8(9,13) element: PyTryPart +9(10,13) element: PyAssignmentStatement +10(11,13) READ ACCESS: could_raise +11(12,13) element: PyCallExpression: could_raise +12(13,16) WRITE ACCESS: foo +13(14) element: PyExceptPart +14(15) READ ACCESS: IndexError +15(18) element: PyBreakStatement +16(17) element: PyPrintStatement +17(1) READ ACCESS: foo +18() element: null \ No newline at end of file diff --git a/python/testData/codeInsight/controlflow/WhileTrueElse.txt b/python/testData/codeInsight/controlflow/WhileTrueElse.txt index ced8d7764b4e..3c199c0d13a1 100644 --- a/python/testData/codeInsight/controlflow/WhileTrueElse.txt +++ b/python/testData/codeInsight/controlflow/WhileTrueElse.txt @@ -3,8 +3,9 @@ 2(3,4) READ ACCESS: True 3() element: null. Condition: True:false 4(5) element: null. Condition: True:true -5(6) element: PyStatementList -6(1) element: PyPassStatement -7(8) element: PyStatementList -8(9) element: PyPrintStatement -9() element: null \ No newline at end of file +5(6) ASSERTTYPE ACCESS: True +6(7) element: PyStatementList +7(1) element: PyPassStatement +8(9) element: PyStatementList +9(10) element: PyPrintStatement +10() element: null \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/Py3TypeTest.java b/python/testSrc/com/jetbrains/python/Py3TypeTest.java index 99bf757e9ae3..f69c574285ee 100644 --- a/python/testSrc/com/jetbrains/python/Py3TypeTest.java +++ b/python/testSrc/com/jetbrains/python/Py3TypeTest.java @@ -151,6 +151,32 @@ public class Py3TypeTest extends PyTestCase { expr = d.pop("abc", None)"""); } + // PY-83351 + public void testWhileStatementNarrowing() { + doTest("int", + """ + def foo(x: int | None): + while x: + expr = x + x = None + """); + doTest("int", + """ + def foo(x: int | None): + while not (not (((not (not x))))): + expr = x + x = None + """); + } + + // PY-83597 + public void testAndExpressionNarrowing() { + doTest("int", """ + def foo(x: int | None): + x and (expr := x) + """); + } + // PY-83348 public void testOrExpressionType() { doTest("int | str", """