PY-83597 False positive type narrowing in expressions with "and"

GitOrigin-RevId: e39cae3490ef0f0f151842f428a45d14d2c4d9ed
This commit is contained in:
Aleksandr.Govenko
2025-09-30 10:30:37 +00:00
committed by intellij-monorepo-bot
parent acba8a231a
commit 663b57857e
19 changed files with 339 additions and 272 deletions
@@ -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 {
@@ -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
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
@@ -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
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
@@ -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
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
@@ -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
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
@@ -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
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
@@ -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
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
@@ -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
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
@@ -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
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
@@ -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
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
@@ -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
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
@@ -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
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
@@ -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
20(21) ASSERTTYPE ACCESS: var
21(22) element: PyStatementList
22(23) element: PyPassStatement
23() element: null
@@ -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
28(29) ASSERTTYPE ACCESS: var
29(30) element: PyStatementList
30(31) element: PyPassStatement
31() element: null
@@ -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
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
@@ -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
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
@@ -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
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
@@ -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
5(6) ASSERTTYPE ACCESS: True
6(7) element: PyStatementList
7(1) element: PyPassStatement
8(9) element: PyStatementList
9(10) element: PyPrintStatement
10() element: null
@@ -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", """