mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-83597 False positive type narrowing in expressions with "and"
GitOrigin-RevId: e39cae3490ef0f0f151842f428a45d14d2c4d9ed
This commit is contained in:
committed by
intellij-monorepo-bot
parent
acba8a231a
commit
663b57857e
+21
-9
@@ -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
|
||||
+27
-23
@@ -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
|
||||
+31
-27
@@ -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
|
||||
+21
-19
@@ -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", """
|
||||
|
||||
Reference in New Issue
Block a user