PY-81676 Don't report lines with assert_never as unreachable

(cherry picked from commit afdbf35915823de02a6b8551f57770113d0feb2f)

IJ-CR-172556

GitOrigin-RevId: 0f8526e2877736ac606db9ed4657a530a66d6f23
This commit is contained in:
Aleksandr.Govenko
2025-06-13 20:56:01 +02:00
committed by intellij-monorepo-bot
parent 5a60b17b4d
commit adcc559e5c
47 changed files with 652 additions and 477 deletions

View File

@@ -1,17 +1,19 @@
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.python.ast;
package com.jetbrains.python.ast
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Experimental
public interface PyAstCapturePattern extends PyAstPattern {
@Override
default boolean isIrrefutable() {
return true;
interface PyAstCapturePattern : PyAstPattern {
override fun isIrrefutable(): Boolean {
return true
}
@Override
default void acceptPyVisitor(PyAstElementVisitor pyVisitor) {
pyVisitor.visitPyCapturePattern(this);
fun getTarget(): PyAstTargetExpression {
return requireNotNull(findChildByClass(PyAstTargetExpression::class.java)) { "${this}: target cannot be null" }
}
override fun acceptPyVisitor(pyVisitor: PyAstElementVisitor) {
pyVisitor.visitPyCapturePattern(this)
}
}

View File

@@ -23,6 +23,7 @@ import com.intellij.codeInsight.controlflow.TransparentInstruction;
import com.intellij.codeInsight.controlflow.impl.ConditionalInstructionImpl;
import com.intellij.codeInsight.controlflow.impl.TransparentInstructionImpl;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.util.PsiTreeUtil;
@@ -32,6 +33,7 @@ import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.*;
import com.jetbrains.python.psi.types.PyNeverType;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -45,6 +47,9 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
private @Nullable TrueFalseNodes myTrueFalseNodes;
// see com.jetbrains.python.PyPatternTypeTest.testMatchClassPatternShadowingCapture
private final @NotNull List<String> myPatternBindingNames = new ArrayList<>();
private record TrueFalseNodes(@NotNull Instruction trueNode, @NotNull Instruction falseNode) {}
public ControlFlow buildControlFlow(final @NotNull ScopeOwner owner) {
@@ -334,12 +339,46 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
public void visitPyMatchStatement(@NotNull PyMatchStatement matchStatement) {
myBuilder.startNode(matchStatement);
PyExpression subject = matchStatement.getSubject();
String subjectName = PyTypeAssertionEvaluator.getAssertionTargetName(subject);
if (subject != null) {
subject.accept(this);
}
for (PyCaseClause caseClause : matchStatement.getCaseClauses()) {
visitPyCaseClause(caseClause);
Instruction nextClause = myBuilder.prevInstruction;
boolean unreachable = false;
for (PyCaseClause clause : matchStatement.getCaseClauses()) {
myBuilder.prevInstruction = nextClause;
nextClause = addTransparentInstruction();
myPatternBindingNames.clear();
PyPattern pattern = clause.getPattern();
if (pattern != null) {
pattern.accept(this);
if (!myPatternBindingNames.contains(subjectName)) {
addTypeAssertionNodes(clause, true);
}
}
PyExpression guard = clause.getGuardCondition();
if (guard != null) {
TransparentInstruction trueNode = addTransparentInstruction();
visitCondition(guard, trueNode, nextClause);
myBuilder.prevInstruction = trueNode;
addTypeAssertionNodes(guard, true);
}
if (unreachable) {
addAssertTypeNever();
}
if (pattern != null && pattern.isIrrefutable()) {
unreachable = true;
}
myBuilder.startNode(clause.getStatementList());
clause.getStatementList().accept(this);
myBuilder.addPendingEdge(matchStatement, myBuilder.prevInstruction);
myBuilder.updatePendingElementScope(clause.getStatementList(), matchStatement);
}
myBuilder.prevInstruction = nextClause;
myBuilder.addNodeAndCheckPending(new TransparentInstructionImpl(myBuilder, matchStatement, ""));
if (!myBuilder.prevInstruction.allPred().isEmpty()) {
addTypeAssertionNodes(matchStatement, false);
@@ -348,53 +387,20 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
myBuilder.prevInstruction = null;
}
@Override
public void visitPyCaseClause(@NotNull PyCaseClause clause) {
PyPattern pattern = clause.getPattern();
if (pattern != null) {
pattern.accept(this);
}
TransparentInstruction trueNode = addTransparentInstruction();
TransparentInstruction falseNode = addTransparentInstruction();
PyExpression guard = clause.getGuardCondition();
if (guard != null) {
visitCondition(guard, trueNode, falseNode);
addTypeAssertionNodes(guard, true);
myBuilder.addPendingEdge(clause, falseNode);
}
else {
myBuilder.addEdge(myBuilder.prevInstruction, trueNode);
}
myBuilder.prevInstruction = trueNode;
clause.getStatementList().accept(this);
if (clause.getParent() instanceof PyMatchStatement matchStatement) {
myBuilder.addPendingEdge(matchStatement, myBuilder.prevInstruction);
myBuilder.updatePendingElementScope(clause.getStatementList(), matchStatement);
}
myBuilder.prevInstruction = null;
}
@Override
public void visitWildcardPattern(@NotNull PyWildcardPattern node) {
myBuilder.startNode(node);
addTypeAssertionNodes(node, true);
}
@Override
public void visitPyPattern(@NotNull PyPattern node) {
boolean isRefutable = !node.isIrrefutable();
if (isRefutable) {
myBuilder.addNodeAndCheckPending(new RefutablePatternInstruction(myBuilder, node, false));
myBuilder.addPendingEdge(node.getParent(), myBuilder.prevInstruction);
}
else {
myBuilder.startNode(node);
}
myBuilder.addPendingEdge(node.getParent(), myBuilder.prevInstruction);
node.acceptChildren(this);
myBuilder.updatePendingElementScope(node, node.getParent());
addTypeAssertionNodes(node, true);
if (isRefutable) {
myBuilder.addNode(new RefutablePatternInstruction(myBuilder, node, true));
}
@@ -429,7 +435,6 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
node.getClassNameReference().accept(this);
myBuilder.addPendingEdge(node.getParent(), myBuilder.prevInstruction);
addTypeAssertionNodes(node, true);
node.getArgumentList().acceptChildren(this);
myBuilder.updatePendingElementScope(node, node.getParent());
@@ -443,7 +448,6 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
node.getValue().accept(this);
myBuilder.addPendingEdge(node.getParent(), myBuilder.prevInstruction);
addTypeAssertionNodes(node, true);
myBuilder.addNode(new RefutablePatternInstruction(myBuilder, node, true));
}
@@ -453,9 +457,20 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
// So no need to create an additional fail edge
myBuilder.startNode(node);
node.acceptChildren(this);
myPatternBindingNames.add(node.getTarget().getName());
myBuilder.updatePendingElementScope(node, node.getParent());
}
@Override
public void visitPyCapturePattern(@NotNull PyCapturePattern node) {
node.acceptChildren(this);
// Although capture pattern is irrefutable, I add fail edge
// here to add some connection to the next case clause.
// Perhaps this can be reworked and simplified later.
myBuilder.addPendingEdge(node.getParent(), myBuilder.prevInstruction);
myPatternBindingNames.add(node.getTarget().getName());
}
@Override
public void visitPyGroupPattern(@NotNull PyGroupPattern node) {
// GroupPattern can't fail by itself it fails only if its child fails.
@@ -478,13 +493,16 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
if (condition != null) {
visitCondition(condition, thenNode, elseNode);
}
myBuilder.prevInstruction = thenNode;
Boolean conditionResult = PyEvaluator.evaluateAsBooleanNoResolve(condition);
myBuilder.prevInstruction = unreachable || Boolean.FALSE.equals(conditionResult) ? null : thenNode;
if (unreachable || Boolean.FALSE.equals(conditionResult)) {
// Condition is always False, or some previous condition is always True.
addAssertTypeNever();
}
if (Boolean.TRUE.equals(conditionResult)) {
unreachable = true;
}
visitPyStatementPart(ifPart);
exitInstructions.add(myBuilder.prevInstruction);
@@ -494,7 +512,7 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
final PyElsePart elsePart = node.getElsePart();
if (elsePart != null) {
if (unreachable) {
myBuilder.prevInstruction = null;
addAssertTypeNever();
}
visitPyStatementPart(elsePart);
}
@@ -1124,6 +1142,13 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
return instruction;
}
/**
* Can be used to mark a branch as unreachable.
*/
private void addAssertTypeNever() {
myBuilder.addNode(ReadWriteInstruction.assertType(myBuilder, null, null, context -> Ref.create(PyNeverType.NEVER)));
}
/**
* Can be used to collect all pending edges
* that we used to build CFG for `node`,

View File

@@ -5,6 +5,7 @@ import com.intellij.codeInsight.controlflow.Instruction
import com.intellij.openapi.util.Version
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.util.findParentOfType
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil
import com.jetbrains.python.psi.*
import com.jetbrains.python.psi.impl.PyEvaluator
@@ -88,7 +89,16 @@ class PyDataFlow(scopeOwner: ScopeOwner, controlFlow: ControlFlow, private val c
* - calls to functions annotated with `NoReturn`
*/
fun PsiElement.isUnreachableForInspection(context: TypeEvalContext): Boolean {
return isUnreachableByControlFlow(context) && !isFirstTerminatingStatement(context)
return PyUtil.getParameterizedCachedValue(this, context) { isUnreachableForInspectionNoCache(it) }
}
private fun PsiElement.isUnreachableForInspectionNoCache(context: TypeEvalContext): Boolean {
if (parent is PyElement && parent.isUnreachableForInspection(context)) return true
return isUnreachableByControlFlow(context) && when (this) {
is PyStatementList -> !(statements.firstOrNull()?.isIgnoredUnreachableStatement(context) ?: true)
is PyStatement -> !this.isIgnoredUnreachableStatement(context)
else -> false
}
}
/**
@@ -128,12 +138,11 @@ fun PsiElement.findInstructionNumber(flow: Array<Instruction>): Int {
return -1
}
private fun PsiElement.isFirstTerminatingStatement(context: TypeEvalContext): Boolean {
if (this.isTerminatingStatement(context)) {
val prevSibling = prevSiblingOfType<PyElement>() ?: return true
return !prevSibling.isTerminatingStatement(context) && !prevSibling.isUnreachableByControlFlow(context)
}
return false
private fun PyStatement.isIgnoredUnreachableStatement(context: TypeEvalContext): Boolean {
val parentBlock = this.parent as? PyStatementList ?: return false
if (parentBlock.statements[0] != this) return false
val parentCompoundStatement = parentBlock.findParentOfType<PyStatement>() ?: return false
return !parentCompoundStatement.isUnreachableByControlFlow(context) && isTerminatingStatement(context)
}
private fun PsiElement.isTerminatingStatement(context: TypeEvalContext): Boolean {

View File

@@ -168,10 +168,11 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
}
@Override
public void visitPyPattern(@NotNull PyPattern node) {
final PsiElement parent = PsiTreeUtil.skipParentsOfType(node, PyCaseClause.class, PyGroupPattern.class, PyAsPattern.class, PyOrPattern.class);
if (parent instanceof PyMatchStatement matchStatement) {
pushAssertion(matchStatement.getSubject(), myPositive, context -> context.getType(node));
public void visitPyCaseClause(@NotNull PyCaseClause node) {
var pattern = node.getPattern();
if (pattern == null) return;
if (node.getParent() instanceof PyMatchStatement matchStatement) {
pushAssertion(matchStatement.getSubject(), myPositive, context -> context.getType(pattern));
}
}
@@ -189,6 +190,10 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
for (PyCaseClause cs : matchStatement.getCaseClauses()) {
if (cs.getPattern() == null) continue;
if (cs.getGuardCondition() != null) continue;
if (cs.getPattern().isIrrefutable()) {
subjectType = PyNeverType.NEVER;
break;
}
subjectType = Ref.deref(createAssertionType(subjectType, context.getType(cs.getPattern()), false, context));
}
@@ -358,6 +363,19 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
}
}
public static @Nullable String getAssertionTargetName(@Nullable PyExpression expression) {
PyExpression target = PyPsiUtils.flattenParens(expression);
if (target instanceof PyAssignmentExpression walrus) {
return getAssertionTargetName(walrus.getTarget());
}
if (target instanceof PyReferenceExpression || target instanceof PyTargetExpression) {
if (!((PyQualifiedExpression)target).isQualified()) {
return target.getName();
}
}
return null;
}
private static boolean isIfReferenceStatement(@NotNull PyExpression node) {
return PsiTreeUtil.skipParentsOfType(node, PyParenthesizedExpression.class) instanceof PyIfPart;
}

View File

@@ -7,7 +7,7 @@ import com.intellij.codeInsight.dataflow.map.DfaMapInstance;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.codeInsight.controlflow.CallInstruction;
import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache;
import com.jetbrains.python.codeInsight.controlflow.PyDataFlowKt;
import com.jetbrains.python.codeInsight.controlflow.ReadWriteInstruction;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeVariable;
@@ -37,12 +37,9 @@ public class PyReachingDefsDfaInstance implements DfaMapInstance<ScopeVariable>
if (element == null || ((PyFile) element.getContainingFile()).getLanguageLevel().isPython2()){
return processReducedMap(map, instruction, element);
}
var scope = ScopeUtil.getScopeOwner(element);
if (scope != null) {
if (ControlFlowCache.getDataFlow(scope, myContext).isUnreachable(instruction)) {
if (PyDataFlowKt.isUnreachableForInspection(element, myContext)) {
return UNREACHABLE_MARKER;
}
}
if (instruction instanceof CallInstruction callInstruction) {
if (callInstruction.isNoReturnCall(myContext)) {
return UNREACHABLE_MARKER;

View File

@@ -5,13 +5,13 @@ import com.intellij.codeInspection.LocalInspectionToolSession
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.util.findParentInFile
import com.jetbrains.python.PyPsiBundle
import com.jetbrains.python.codeInsight.controlflow.isUnreachableForInspection
import com.jetbrains.python.psi.PyElement
import com.jetbrains.python.psi.PyStatement
import com.jetbrains.python.psi.PyStatementList
/**
* Detects unreachable code using control flow graph
* Detects unreachable code using the control flow graph
*/
class PyUnreachableCodeInspection : PyInspection() {
override fun buildVisitor(
@@ -20,12 +20,16 @@ class PyUnreachableCodeInspection : PyInspection() {
session: LocalInspectionToolSession
): PsiElementVisitor {
return object : PyInspectionVisitor(holder, getContext(session)) {
override fun visitPyElement(node: PyElement) {
override fun visitPyStatementList(node: PyStatementList) {
if (node.parent.isUnreachableForInspection(myTypeEvalContext)) return
if (node.isUnreachableForInspection(myTypeEvalContext)) {
if (node.findParentInFile { it.isUnreachableForInspection(myTypeEvalContext) } != null) {
// We only want to highlight top level unreachable code
return
registerProblem(node, PyPsiBundle.message("INSP.unreachable.code"), ProblemHighlightType.LIKE_UNUSED_SYMBOL)
}
}
override fun visitPyStatement(node: PyStatement) {
if (node.parent.isUnreachableForInspection(myTypeEvalContext)) return
if (node.isUnreachableForInspection(myTypeEvalContext)) {
registerProblem(node, PyPsiBundle.message("INSP.unreachable.code"), ProblemHighlightType.LIKE_UNUSED_SYMBOL)
}
}

View File

@@ -5,28 +5,30 @@
4(5) element: null. Condition: c:true
5(6) ASSERTTYPE ACCESS: c
6(7) element: PyStatementList
7(15) element: PyPassStatement
7(16) element: PyPassStatement
8(9,10) READ ACCESS: False
9(15) element: null. Condition: False:false
9(16) element: null. Condition: False:false
10(11) element: null. Condition: False:true
11() ASSERTTYPE ACCESS: False
12(13) element: PyStatementList
13(14) element: PyAssignmentStatement
14(15) WRITE ACCESS: a
15(16) element: PyIfStatement
16(17,18) READ ACCESS: d
17(22) element: null. Condition: d:false
18(19) element: null. Condition: d:true
19(20) ASSERTTYPE ACCESS: d
20(21) element: PyStatementList
21(31) element: PyPassStatement
22(23,24) READ ACCESS: False
23(29) element: null. Condition: False:false
24(25) element: null. Condition: False:true
25() ASSERTTYPE ACCESS: False
26(27) element: PyStatementList
27(28) element: PyAssignmentStatement
28(31) WRITE ACCESS: b
29(30) element: PyStatementList
30(31) element: PyPassStatement
31() element: null
11(12) ASSERTTYPE ACCESS: False
12(13) ASSERTTYPE ACCESS: null
13(14) element: PyStatementList
14(15) element: PyAssignmentStatement
15(16) WRITE ACCESS: a
16(17) element: PyIfStatement
17(18,19) READ ACCESS: d
18(23) element: null. Condition: d:false
19(20) element: null. Condition: d:true
20(21) ASSERTTYPE ACCESS: d
21(22) element: PyStatementList
22(33) element: PyPassStatement
23(24,25) READ ACCESS: False
24(31) element: null. Condition: False:false
25(26) element: null. Condition: False:true
26(27) ASSERTTYPE ACCESS: False
27(28) ASSERTTYPE ACCESS: null
28(29) element: PyStatementList
29(30) element: PyAssignmentStatement
30(33) WRITE ACCESS: b
31(32) element: PyStatementList
32(33) element: PyPassStatement
33() element: null

View File

@@ -18,14 +18,15 @@
17(18) element: null. Condition: d:true
18(19) ASSERTTYPE ACCESS: d
19(20) element: PyStatementList
20(30) element: PyPassStatement
20(31) element: PyPassStatement
21(22,23) READ ACCESS: True
22() element: null. Condition: True:false
22(27) element: null. Condition: True:false
23(24) element: null. Condition: True:true
24(25) ASSERTTYPE ACCESS: True
25(26) element: PyStatementList
26(30) element: PyPassStatement
27(28) element: PyStatementList
28(29) element: PyAssignmentStatement
29(30) WRITE ACCESS: e
30() element: null
26(31) element: PyPassStatement
27(28) ASSERTTYPE ACCESS: null
28(29) element: PyStatementList
29(30) element: PyAssignmentStatement
30(31) WRITE ACCESS: e
31() element: null

View File

@@ -1,36 +1,39 @@
0(1) element: null
1(2) element: PyIfStatement
2(3,4) READ ACCESS: False
3(9) element: null. Condition: False:false
3(10) element: null. Condition: False:false
4(5) element: null. Condition: False:true
5() ASSERTTYPE ACCESS: False
6(7) element: PyStatementList
7(8) element: PyAssignmentStatement
8(9) WRITE ACCESS: a
9(10) element: PyIfStatement
10(11,12) READ ACCESS: False
11(17) element: null. Condition: False:false
12(13) element: null. Condition: False:true
13() ASSERTTYPE ACCESS: False
14(15) element: PyStatementList
15(16) element: PyAssignmentStatement
16(19) WRITE ACCESS: b
17(18) element: PyStatementList
18(19) element: PyPassStatement
19(20) element: PyIfStatement
20(21,22) READ ACCESS: False
21(27) element: null. Condition: False:false
22(23) element: null. Condition: False:true
23() ASSERTTYPE ACCESS: False
24(25) element: PyStatementList
25(26) element: PyAssignmentStatement
26(35) WRITE ACCESS: c
27(28,29) READ ACCESS: d
28(33) element: null. Condition: d:false
29(30) element: null. Condition: d:true
30(31) ASSERTTYPE ACCESS: d
31(32) element: PyStatementList
32(35) element: PyPassStatement
33(34) element: PyStatementList
34(35) element: PyPassStatement
35() element: null
5(6) ASSERTTYPE ACCESS: False
6(7) ASSERTTYPE ACCESS: null
7(8) element: PyStatementList
8(9) element: PyAssignmentStatement
9(10) WRITE ACCESS: a
10(11) element: PyIfStatement
11(12,13) READ ACCESS: False
12(19) element: null. Condition: False:false
13(14) element: null. Condition: False:true
14(15) ASSERTTYPE ACCESS: False
15(16) ASSERTTYPE ACCESS: null
16(17) element: PyStatementList
17(18) element: PyAssignmentStatement
18(21) WRITE ACCESS: b
19(20) element: PyStatementList
20(21) element: PyPassStatement
21(22) element: PyIfStatement
22(23,24) READ ACCESS: False
23(30) element: null. Condition: False:false
24(25) element: null. Condition: False:true
25(26) ASSERTTYPE ACCESS: False
26(27) ASSERTTYPE ACCESS: null
27(28) element: PyStatementList
28(29) element: PyAssignmentStatement
29(38) WRITE ACCESS: c
30(31,32) READ ACCESS: d
31(36) element: null. Condition: d:false
32(33) element: null. Condition: d:true
33(34) ASSERTTYPE ACCESS: d
34(35) element: PyStatementList
35(38) element: PyPassStatement
36(37) element: PyStatementList
37(38) element: PyPassStatement
38() element: null

View File

@@ -1,21 +1,22 @@
0(1) element: null
1(2) element: PyIfStatement
2(3,4) READ ACCESS: True
3() element: null. Condition: True:false
3(13) element: null. Condition: True:false
4(5) element: null. Condition: True:true
5(6) ASSERTTYPE ACCESS: True
6(7) element: PyStatementList
7(8) element: PyForStatement
8(9) READ ACCESS: range
9(10,18) element: PyCallExpression: range
9(10,19) element: PyCallExpression: range
10(11) element: PyTargetExpression: _
11(12) WRITE ACCESS: _
12(10,18) element: PyPrintStatement
13(14) element: PyStatementList
14(15) element: PyRaiseStatement
15(16) READ ACCESS: Exception
16(17) element: PyCallExpression: Exception
17(20) raise: PyRaiseStatement
18(19) element: PyReturnStatement
19(20) READ ACCESS: True
20() element: null
12(10,19) element: PyPrintStatement
13(14) ASSERTTYPE ACCESS: null
14(15) element: PyStatementList
15(16) element: PyRaiseStatement
16(17) READ ACCESS: Exception
17(18) element: PyCallExpression: Exception
18(21) raise: PyRaiseStatement
19(20) element: PyReturnStatement
20(21) READ ACCESS: True
21() element: null

View File

@@ -8,29 +8,32 @@
7(8) element: PyPassStatement
8(9) element: PyIfStatement
9(10,11) READ ACCESS: True
10() element: null. Condition: True:false
10(15) element: null. Condition: True:false
11(12) element: null. Condition: True:true
12(13) ASSERTTYPE ACCESS: True
13(14) element: PyStatementList
14(18) element: PyPassStatement
15(16) element: PyStatementList
16(17) element: PyAssignmentStatement
17(18) WRITE ACCESS: b
18(19) element: PyIfStatement
19(20,21) READ ACCESS: True
20(25) element: null. Condition: True:false
21(22) element: null. Condition: True:true
22(23) ASSERTTYPE ACCESS: True
23(24) element: PyStatementList
24(35) element: PyPassStatement
25(26,27) READ ACCESS: c
26() element: null. Condition: c:false
27(28) element: null. Condition: c:true
28() ASSERTTYPE ACCESS: c
29(30) element: PyStatementList
30(31) element: PyAssignmentStatement
31(35) WRITE ACCESS: d
32(33) element: PyStatementList
33(34) element: PyAssignmentStatement
34(35) WRITE ACCESS: e
35() element: null
14(19) element: PyPassStatement
15(16) ASSERTTYPE ACCESS: null
16(17) element: PyStatementList
17(18) element: PyAssignmentStatement
18(19) WRITE ACCESS: b
19(20) element: PyIfStatement
20(21,22) READ ACCESS: True
21(26) element: null. Condition: True:false
22(23) element: null. Condition: True:true
23(24) ASSERTTYPE ACCESS: True
24(25) element: PyStatementList
25(38) element: PyPassStatement
26(27,28) READ ACCESS: c
27(34) element: null. Condition: c:false
28(29) element: null. Condition: c:true
29(30) ASSERTTYPE ACCESS: c
30(31) ASSERTTYPE ACCESS: null
31(32) element: PyStatementList
32(33) element: PyAssignmentStatement
33(38) WRITE ACCESS: d
34(35) ASSERTTYPE ACCESS: null
35(36) element: PyStatementList
36(37) element: PyAssignmentStatement
37(38) WRITE ACCESS: e
38() element: null

View File

@@ -1,18 +1,19 @@
0(1) element: null
1(2) element: PyWhileStatement
2(3,4) READ ACCESS: x
3(15) element: null. Condition: x:false
3(16) 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,12) refutable pattern: 42
9(10) ASSERTTYPE ACCESS: x
10(11) matched pattern: 42
11(15) element: PyBreakStatement
12(13) ASSERTTYPE ACCESS: x
13(14) element: PyExpressionStatement
14(1) READ ACCESS: y
15(16) element: PyExpressionStatement
16(17) READ ACCESS: z
17() element: null
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

View File

@@ -1,18 +1,19 @@
0(1) element: null
1(2) element: PyWhileStatement
2(3,4) READ ACCESS: x
3(15) element: null. Condition: x:false
3(16) 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,12) refutable pattern: 42
9(10) ASSERTTYPE ACCESS: x
10(11) matched pattern: 42
11(1) element: PyContinueStatement
12(13) ASSERTTYPE ACCESS: x
13(14) element: PyExpressionStatement
14(1) READ ACCESS: y
15(16) element: PyExpressionStatement
16(17) READ ACCESS: z
17() element: null
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

View File

@@ -2,11 +2,12 @@
1(2) WRITE ACCESS: x
2(3) element: PyMatchStatement
3(4) READ ACCESS: x
4(5,8) refutable pattern: 42
5(6) ASSERTTYPE ACCESS: x
6(7) matched pattern: 42
7(11) element: PyReturnStatement
8(9) ASSERTTYPE ACCESS: x
9(10) element: PyExpressionStatement
10(11) READ ACCESS: y
11() element: null
4(5,9) refutable pattern: 42
5(6) matched pattern: 42
6(7) ASSERTTYPE ACCESS: x
7(8) element: PyStatementList
8(12) element: PyReturnStatement
9(10) ASSERTTYPE ACCESS: x
10(11) element: PyExpressionStatement
11(12) READ ACCESS: y
12() element: null

View File

@@ -1,20 +1,23 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3,12) refutable pattern: 1
2(3,14) refutable pattern: 1
3(4) matched pattern: 1
4(5) element: PyMatchStatement
5(6,9) refutable pattern: 11
6(7) matched pattern: 11
7(8) element: PyExpressionStatement
8(10) READ ACCESS: y11
9(10) ASSERTTYPE ACCESS: null
10(11) element: PyExpressionStatement
11(17) READ ACCESS: y1
12(13,16) refutable pattern: 2
13(14) matched pattern: 2
14(15) element: PyExpressionStatement
15(17) READ ACCESS: y2
16(17) ASSERTTYPE ACCESS: null
4(5) element: PyStatementList
5(6) element: PyMatchStatement
6(7,11) refutable pattern: 11
7(8) matched pattern: 11
8(9) element: PyStatementList
9(10) element: PyExpressionStatement
10(12) READ ACCESS: y11
11(12) ASSERTTYPE ACCESS: null
12(13) element: PyExpressionStatement
13(20) READ ACCESS: y1
14(15,19) refutable pattern: 2
15(16) matched pattern: 2
16(17) element: PyStatementList
17(18) element: PyExpressionStatement
18(19) READ ACCESS: z
19() element: null
18(20) READ ACCESS: y2
19(20) ASSERTTYPE ACCESS: null
20(21) element: PyExpressionStatement
21(22) READ ACCESS: z
22() element: null

View File

@@ -1,18 +1,21 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3,10) refutable pattern: 1
2(3,12) refutable pattern: 1
3(4) matched pattern: 1
4(5) element: PyMatchStatement
5(6,9) refutable pattern: 11
6(7) matched pattern: 11
7(8) element: PyExpressionStatement
8(15) READ ACCESS: y11
9(15) ASSERTTYPE ACCESS: null
10(11,14) refutable pattern: 2
11(12) matched pattern: 2
12(13) element: PyExpressionStatement
13(15) READ ACCESS: y2
14(15) ASSERTTYPE ACCESS: null
4(5) element: PyStatementList
5(6) element: PyMatchStatement
6(7,11) refutable pattern: 11
7(8) matched pattern: 11
8(9) element: PyStatementList
9(10) element: PyExpressionStatement
10(18) READ ACCESS: y11
11(18) ASSERTTYPE ACCESS: null
12(13,17) refutable pattern: 2
13(14) matched pattern: 2
14(15) element: PyStatementList
15(16) element: PyExpressionStatement
16(17) READ ACCESS: z
17() element: null
16(18) READ ACCESS: y2
17(18) ASSERTTYPE ACCESS: null
18(19) element: PyExpressionStatement
19(20) READ ACCESS: z
20() element: null

View File

@@ -7,13 +7,14 @@
6(7) matched pattern: 42
7(11) matched pattern: [42]
8(9) refutable pattern: foo.bar
9(10,15) READ ACCESS: foo
9(10,16) READ ACCESS: foo
10(11) matched pattern: foo.bar
11(12) matched pattern: [42] | foo.bar
12(13) WRITE ACCESS: x
13(14) element: PyExpressionStatement
14(16) READ ACCESS: y
15(16) ASSERTTYPE ACCESS: null
16(17) element: PyExpressionStatement
17(18) READ ACCESS: z
18() element: null
13(14) element: PyStatementList
14(15) element: PyExpressionStatement
15(17) READ ACCESS: y
16(17) ASSERTTYPE ACCESS: null
17(18) element: PyExpressionStatement
18(19) READ ACCESS: z
19() element: null

View File

@@ -1,11 +1,12 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3,7) refutable pattern: [x]
3(4) WRITE ACCESS: x
2(3,8) refutable pattern: [x]
3(4,8) WRITE ACCESS: x
4(5) matched pattern: [x]
5(6) element: PyExpressionStatement
6(8) READ ACCESS: y
7(8) ASSERTTYPE ACCESS: null
8(9) element: PyExpressionStatement
9(10) READ ACCESS: z
10() element: null
5(6) element: PyStatementList
6(7) element: PyExpressionStatement
7(9) READ ACCESS: y
8(9) ASSERTTYPE ACCESS: null
9(10) element: PyExpressionStatement
10(11) READ ACCESS: z
11() element: null

View File

@@ -1,8 +1,10 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3) WRITE ACCESS: x
3(4) element: PyExpressionStatement
4(5) READ ACCESS: y
5(6) element: PyExpressionStatement
6(7) READ ACCESS: z
7() element: null
2(3,6) WRITE ACCESS: x
3(4) element: PyStatementList
4(5) element: PyExpressionStatement
5(7) READ ACCESS: y
6(7) ASSERTTYPE ACCESS: null
7(8) element: PyExpressionStatement
8(9) READ ACCESS: z
9() element: null

View File

@@ -1,18 +1,19 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3) refutable pattern: Class(1, attr=foo.bar)
3(4,14) READ ACCESS: Class
4(5,14) refutable pattern: 1
3(4,15) READ ACCESS: Class
4(5,15) refutable pattern: 1
5(6) matched pattern: 1
6(7,14) refutable pattern: attr=foo.bar
6(7,15) refutable pattern: attr=foo.bar
7(8) refutable pattern: foo.bar
8(9,14) READ ACCESS: foo
8(9,15) READ ACCESS: foo
9(10) matched pattern: foo.bar
10(11) matched pattern: attr=foo.bar
11(12) matched pattern: Class(1, attr=foo.bar)
12(13) element: PyExpressionStatement
13(15) READ ACCESS: x
14(15) ASSERTTYPE ACCESS: null
15(16) element: PyExpressionStatement
16(17) READ ACCESS: y
17() element: null
12(13) element: PyStatementList
13(14) element: PyExpressionStatement
14(16) READ ACCESS: x
15(16) ASSERTTYPE ACCESS: null
16(17) element: PyExpressionStatement
17(18) READ ACCESS: y
18() element: null

View File

@@ -1,16 +1,17 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3) WRITE ACCESS: x
2(3,13) WRITE ACCESS: x
3(4) element: PyBinaryExpression
4(5,6) READ ACCESS: x
5(12) element: null. Condition: x > 0:false
5(13) element: null. Condition: x > 0:false
6(7) element: null. Condition: x > 0:true
7(8,9) READ ACCESS: x
8(12) element: null. Condition: x < 10:false
8(13) element: null. Condition: x < 10:false
9(10) element: null. Condition: x < 10:true
10(11) element: PyExpressionStatement
11(13) READ ACCESS: y
12(13) ASSERTTYPE ACCESS: null
13(14) element: PyExpressionStatement
14(15) READ ACCESS: z
15() element: null
10(11) element: PyStatementList
11(12) element: PyExpressionStatement
12(14) READ ACCESS: y
13(14) ASSERTTYPE ACCESS: null
14(15) element: PyExpressionStatement
15(16) READ ACCESS: z
16() element: null

View File

@@ -1,20 +1,21 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3) WRITE ACCESS: x
2(3,17) WRITE ACCESS: x
3(4) element: PyBinaryExpression
4(5,6) READ ACCESS: x
5(16) element: null. Condition: x % 4 == 0:false
5(17) element: null. Condition: x % 4 == 0:false
6(7) element: null. Condition: x % 4 == 0:true
7(8) element: PyBinaryExpression
8(9,10) READ ACCESS: x
9(11) element: null. Condition: x % 400 == 0:false
10(14) element: null. Condition: x % 400 == 0:true
11(12,13) READ ACCESS: x
12(16) element: null. Condition: x % 100 != 0:false
12(17) element: null. Condition: x % 100 != 0:false
13(14) element: null. Condition: x % 100 != 0:true
14(15) element: PyExpressionStatement
15(17) READ ACCESS: y
16(17) ASSERTTYPE ACCESS: null
17(18) element: PyExpressionStatement
18(19) READ ACCESS: z
19() element: null
14(15) element: PyStatementList
15(16) element: PyExpressionStatement
16(18) READ ACCESS: y
17(18) ASSERTTYPE ACCESS: null
18(19) element: PyExpressionStatement
19(20) READ ACCESS: z
20() element: null

View File

@@ -1,16 +1,17 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3) WRITE ACCESS: x
2(3,13) WRITE ACCESS: x
3(4) element: PyBinaryExpression
4(5,6) READ ACCESS: x
5(7) element: null. Condition: x > 0:false
6(10) element: null. Condition: x > 0:true
7(8,9) READ ACCESS: x
8(12) element: null. Condition: x < 0:false
8(13) element: null. Condition: x < 0:false
9(10) element: null. Condition: x < 0:true
10(11) element: PyExpressionStatement
11(13) READ ACCESS: y
12(13) ASSERTTYPE ACCESS: null
13(14) element: PyExpressionStatement
14(15) READ ACCESS: z
15() element: null
10(11) element: PyStatementList
11(12) element: PyExpressionStatement
12(14) READ ACCESS: y
13(14) ASSERTTYPE ACCESS: null
14(15) element: PyExpressionStatement
15(16) READ ACCESS: z
16() element: null

View File

@@ -1,17 +1,19 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3,13) refutable pattern: {"foo": 1, **x}
3(4,13) refutable pattern: "foo": 1
4(5,13) refutable pattern: "foo"
2(3,15) refutable pattern: {"foo": 1, **x}
3(4,15) refutable pattern: "foo": 1
4(5,15) refutable pattern: "foo"
5(6) matched pattern: "foo"
6(7,13) refutable pattern: 1
6(7,15) refutable pattern: 1
7(8) matched pattern: 1
8(9) matched pattern: "foo": 1
9(10) WRITE ACCESS: x
10(11) matched pattern: {"foo": 1, **x}
11(12) element: PyExpressionStatement
12(14) READ ACCESS: y
13(14) ASSERTTYPE ACCESS: null
14(15) element: PyExpressionStatement
15(16) READ ACCESS: z
16() element: null
9(10,15) element: PyDoubleStarPattern
10(11,15) WRITE ACCESS: x
11(12) matched pattern: {"foo": 1, **x}
12(13) element: PyStatementList
13(14) element: PyExpressionStatement
14(16) READ ACCESS: y
15(16) ASSERTTYPE ACCESS: null
16(17) element: PyExpressionStatement
17(18) READ ACCESS: z
18() element: null

View File

@@ -1,23 +1,24 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3,19) refutable pattern: [x1, x2, x3]
3(4) WRITE ACCESS: x1
4(5) WRITE ACCESS: x2
5(6) WRITE ACCESS: x3
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
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(19) element: null. Condition: x2:false
12(20) element: null. Condition: x2:false
13(17) element: null. Condition: x2:true
14(15,16) READ ACCESS: x3
15(19) element: null. Condition: (x1 or x2) > x3:false
15(20) element: null. Condition: (x1 or x2) > x3:false
16(17) element: null. Condition: (x1 or x2) > x3:true
17(18) element: PyExpressionStatement
18(20) READ ACCESS: y
19(20) ASSERTTYPE ACCESS: null
20(21) element: PyExpressionStatement
21(22) READ ACCESS: z
22() element: null
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

View File

@@ -1,14 +1,15 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3) refutable pattern: x | [x]
3(7) WRITE ACCESS: x
4(5,10) refutable pattern: [x]
5(6) WRITE ACCESS: x
3(4,7) WRITE ACCESS: x
4(5,11) refutable pattern: [x]
5(6,11) WRITE ACCESS: x
6(7) matched pattern: [x]
7(8) matched pattern: x | [x]
8(9) element: PyExpressionStatement
9(11) READ ACCESS: y
10(11) ASSERTTYPE ACCESS: null
11(12) element: PyExpressionStatement
12(13) READ ACCESS: z
13() element: null
8(9) element: PyStatementList
9(10) element: PyExpressionStatement
10(12) READ ACCESS: y
11(12) ASSERTTYPE ACCESS: null
12(13) element: PyExpressionStatement
13(14) READ ACCESS: z
14() element: null

View File

@@ -2,12 +2,14 @@
1(2) element: PyMatchStatement
2(3) refutable pattern: [x] | x
3(4,6) refutable pattern: [x]
4(5) WRITE ACCESS: x
4(5,6) WRITE ACCESS: x
5(7) matched pattern: [x]
6(7) WRITE ACCESS: x
6(7,11) WRITE ACCESS: x
7(8) matched pattern: [x] | x
8(9) element: PyExpressionStatement
9(10) READ ACCESS: y
10(11) element: PyExpressionStatement
11(12) READ ACCESS: z
12() element: null
8(9) element: PyStatementList
9(10) element: PyExpressionStatement
10(12) READ ACCESS: y
11(12) ASSERTTYPE ACCESS: null
12(13) element: PyExpressionStatement
13(14) READ ACCESS: z
14() element: null

View File

@@ -1,10 +1,11 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3,6) refutable pattern: 42
2(3,7) refutable pattern: 42
3(4) matched pattern: 42
4(5) element: PyExpressionStatement
5(7) READ ACCESS: y
6(7) ASSERTTYPE ACCESS: null
7(8) element: PyExpressionStatement
8(9) READ ACCESS: z
9() element: null
4(5) element: PyStatementList
5(6) element: PyExpressionStatement
6(8) READ ACCESS: y
7(8) ASSERTTYPE ACCESS: null
8(9) element: PyExpressionStatement
9(10) READ ACCESS: z
10() element: null

View File

@@ -1,23 +1,24 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3,19) refutable pattern: {'foo': 1, 'bar': foo.bar}
3(4,19) refutable pattern: 'foo': 1
4(5,19) refutable pattern: 'foo'
2(3,20) refutable pattern: {'foo': 1, 'bar': foo.bar}
3(4,20) refutable pattern: 'foo': 1
4(5,20) refutable pattern: 'foo'
5(6) matched pattern: 'foo'
6(7,19) refutable pattern: 1
6(7,20) refutable pattern: 1
7(8) matched pattern: 1
8(9) matched pattern: 'foo': 1
9(10,19) refutable pattern: 'bar': foo.bar
10(11,19) refutable pattern: 'bar'
9(10,20) refutable pattern: 'bar': foo.bar
10(11,20) refutable pattern: 'bar'
11(12) matched pattern: 'bar'
12(13) refutable pattern: foo.bar
13(14,19) READ ACCESS: foo
13(14,20) READ ACCESS: foo
14(15) matched pattern: foo.bar
15(16) matched pattern: 'bar': foo.bar
16(17) matched pattern: {'foo': 1, 'bar': foo.bar}
17(18) element: PyExpressionStatement
18(20) READ ACCESS: x
19(20) ASSERTTYPE ACCESS: null
20(21) element: PyExpressionStatement
21(22) READ ACCESS: y
22() element: null
17(18) element: PyStatementList
18(19) element: PyExpressionStatement
19(21) READ ACCESS: x
20(21) ASSERTTYPE ACCESS: null
21(22) element: PyExpressionStatement
22(23) READ ACCESS: y
23() element: null

View File

@@ -1,13 +1,15 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3,9) refutable pattern: [1, *x]
3(4,9) refutable pattern: 1
2(3,11) refutable pattern: [1, *x]
3(4,11) refutable pattern: 1
4(5) matched pattern: 1
5(6) WRITE ACCESS: x
6(7) matched pattern: [1, *x]
7(8) element: PyExpressionStatement
8(10) READ ACCESS: y
9(10) ASSERTTYPE ACCESS: null
10(11) element: PyExpressionStatement
11(12) READ ACCESS: z
12() element: null
5(6,11) element: PySingleStarPattern
6(7,11) WRITE ACCESS: x
7(8) matched pattern: [1, *x]
8(9) element: PyStatementList
9(10) element: PyExpressionStatement
10(12) READ ACCESS: y
11(12) ASSERTTYPE ACCESS: null
12(13) element: PyExpressionStatement
13(14) READ ACCESS: z
14() element: null

View File

@@ -6,13 +6,14 @@
5(6) refutable pattern: 2 | 3
6(7,8) refutable pattern: 2
7(10) matched pattern: 2
8(9,14) refutable pattern: 3
8(9,15) refutable pattern: 3
9(10) matched pattern: 3
10(11) matched pattern: 2 | 3
11(12) matched pattern: 1 | (2 | 3)
12(13) element: PyExpressionStatement
13(15) READ ACCESS: x
14(15) ASSERTTYPE ACCESS: null
15(16) element: PyExpressionStatement
16(17) READ ACCESS: y
17() element: null
12(13) element: PyStatementList
13(14) element: PyExpressionStatement
14(16) READ ACCESS: x
15(16) ASSERTTYPE ACCESS: null
16(17) element: PyExpressionStatement
17(18) READ ACCESS: y
18() element: null

View File

@@ -1,8 +1,10 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3) WRITE ACCESS: x
3(4) element: PyExpressionStatement
4(5) READ ACCESS: y
5(6) element: PyExpressionStatement
6(7) READ ACCESS: z
7() element: null
2(3,6) WRITE ACCESS: x
3(4) element: PyStatementList
4(5) element: PyExpressionStatement
5(7) READ ACCESS: y
6(7) ASSERTTYPE ACCESS: null
7(8) element: PyExpressionStatement
8(9) READ ACCESS: z
9() element: null

View File

@@ -2,17 +2,18 @@
1(2) element: PyMatchStatement
2(3) refutable pattern: [x] | (foo.bar as x)
3(4,6) refutable pattern: [x]
4(5) WRITE ACCESS: x
4(5,6) WRITE ACCESS: x
5(11) matched pattern: [x]
6(7) element: PyAsPattern
7(8) refutable pattern: foo.bar
8(9,14) READ ACCESS: foo
8(9,15) READ ACCESS: foo
9(10) matched pattern: foo.bar
10(11) WRITE ACCESS: x
11(12) matched pattern: [x] | (foo.bar as x)
12(13) element: PyExpressionStatement
13(15) READ ACCESS: y
14(15) ASSERTTYPE ACCESS: null
15(16) element: PyExpressionStatement
16(17) READ ACCESS: z
17() element: null
12(13) element: PyStatementList
13(14) element: PyExpressionStatement
14(16) READ ACCESS: y
15(16) ASSERTTYPE ACCESS: null
16(17) element: PyExpressionStatement
17(18) READ ACCESS: z
18() element: null

View File

@@ -3,12 +3,13 @@
2(3) refutable pattern: [] | 42
3(4,5) refutable pattern: []
4(7) matched pattern: []
5(6,10) refutable pattern: 42
5(6,11) refutable pattern: 42
6(7) matched pattern: 42
7(8) matched pattern: [] | 42
8(9) element: PyExpressionStatement
9(11) READ ACCESS: y
10(11) ASSERTTYPE ACCESS: null
11(12) element: PyExpressionStatement
12(13) READ ACCESS: z
13() element: null
8(9) element: PyStatementList
9(10) element: PyExpressionStatement
10(12) READ ACCESS: y
11(12) ASSERTTYPE ACCESS: null
12(13) element: PyExpressionStatement
13(14) READ ACCESS: z
14() element: null

View File

@@ -1,13 +1,14 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3) refutable pattern: _ | 42
3(6) element: PyWildcardPattern
4(5,9) refutable pattern: 42
3(4,6) element: PyWildcardPattern
4(5,10) refutable pattern: 42
5(6) matched pattern: 42
6(7) matched pattern: _ | 42
7(8) element: PyExpressionStatement
8(10) READ ACCESS: y
9(10) ASSERTTYPE ACCESS: null
10(11) element: PyExpressionStatement
11(12) READ ACCESS: z
12() element: null
7(8) element: PyStatementList
8(9) element: PyExpressionStatement
9(11) READ ACCESS: y
10(11) ASSERTTYPE ACCESS: null
11(12) element: PyExpressionStatement
12(13) READ ACCESS: z
13() element: null

View File

@@ -1,18 +1,19 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3,14) refutable pattern: [x]
3(4) WRITE ACCESS: x
2(3,15) refutable pattern: [x]
3(4,15) WRITE ACCESS: x
4(5) matched pattern: [x]
5(6) element: PyBinaryExpression
6(7,8) READ ACCESS: x
7(14) element: null. Condition: x > 0:false
7(15) element: null. Condition: x > 0:false
8(9) element: null. Condition: x > 0:true
9(10,11) READ ACCESS: x
10(14) element: null. Condition: x % 2 == 0:false
10(15) element: null. Condition: x % 2 == 0:false
11(12) element: null. Condition: x % 2 == 0:true
12(13) element: PyExpressionStatement
13(15) READ ACCESS: y
14(15) ASSERTTYPE ACCESS: null
15(16) element: PyExpressionStatement
16(17) READ ACCESS: z
17() element: null
12(13) element: PyStatementList
13(14) element: PyExpressionStatement
14(16) READ ACCESS: y
15(16) ASSERTTYPE ACCESS: null
16(17) element: PyExpressionStatement
17(18) READ ACCESS: z
18() element: null

View File

@@ -1,15 +1,16 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3,11) refutable pattern: [1, foo.bar]
3(4,11) refutable pattern: 1
2(3,12) refutable pattern: [1, foo.bar]
3(4,12) refutable pattern: 1
4(5) matched pattern: 1
5(6) refutable pattern: foo.bar
6(7,11) READ ACCESS: foo
6(7,12) READ ACCESS: foo
7(8) matched pattern: foo.bar
8(9) matched pattern: [1, foo.bar]
9(10) element: PyExpressionStatement
10(12) READ ACCESS: x
11(12) ASSERTTYPE ACCESS: null
12(13) element: PyExpressionStatement
13(14) READ ACCESS: y
14() element: null
9(10) element: PyStatementList
10(11) element: PyExpressionStatement
11(13) READ ACCESS: x
12(13) ASSERTTYPE ACCESS: null
13(14) element: PyExpressionStatement
14(15) READ ACCESS: y
15() element: null

View File

@@ -1,15 +1,16 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3,11) refutable pattern: [1 | x]
2(3,12) refutable pattern: [1 | x]
3(4) refutable pattern: 1 | x
4(5,6) refutable pattern: 1
5(7) matched pattern: 1
6(7) WRITE ACCESS: x
6(7,12) WRITE ACCESS: x
7(8) matched pattern: 1 | x
8(9) matched pattern: [1 | x]
9(10) element: PyExpressionStatement
10(12) READ ACCESS: y
11(12) ASSERTTYPE ACCESS: null
12(13) element: PyExpressionStatement
13(14) READ ACCESS: z
14() element: null
9(10) element: PyStatementList
10(11) element: PyExpressionStatement
11(13) READ ACCESS: y
12(13) ASSERTTYPE ACCESS: null
13(14) element: PyExpressionStatement
14(15) READ ACCESS: z
15() element: null

View File

@@ -1,12 +1,13 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3) WRITE ACCESS: x
2(3,9) WRITE ACCESS: x
3(4,5) READ ACCESS: x
4(8) element: null. Condition: x > 0:false
4(9) element: null. Condition: x > 0:false
5(6) element: null. Condition: x > 0:true
6(7) element: PyExpressionStatement
7(9) READ ACCESS: y
8(9) ASSERTTYPE ACCESS: null
9(10) element: PyExpressionStatement
10(11) READ ACCESS: z
11() element: null
6(7) element: PyStatementList
7(8) element: PyExpressionStatement
8(10) READ ACCESS: y
9(10) ASSERTTYPE ACCESS: null
10(11) element: PyExpressionStatement
11(12) READ ACCESS: z
12() element: null

View File

@@ -1,8 +1,10 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3) element: PyWildcardPattern
3(4) element: PyExpressionStatement
4(5) READ ACCESS: y
5(6) element: PyExpressionStatement
6(7) READ ACCESS: z
7() element: null
2(3,6) element: PyWildcardPattern
3(4) element: PyStatementList
4(5) element: PyExpressionStatement
5(7) READ ACCESS: y
6(7) ASSERTTYPE ACCESS: null
7(8) element: PyExpressionStatement
8(9) READ ACCESS: z
9() element: null

View File

@@ -1,13 +1,15 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3,9) refutable pattern: [1, *_]
3(4,9) refutable pattern: 1
2(3,11) refutable pattern: [1, *_]
3(4,11) refutable pattern: 1
4(5) matched pattern: 1
5(6) element: PyWildcardPattern
6(7) matched pattern: [1, *_]
7(8) element: PyExpressionStatement
8(10) READ ACCESS: y
9(10) ASSERTTYPE ACCESS: null
10(11) element: PyExpressionStatement
11(12) READ ACCESS: z
12() element: null
5(6,11) element: PySingleStarPattern
6(7,11) element: PyWildcardPattern
7(8) matched pattern: [1, *_]
8(9) element: PyStatementList
9(10) element: PyExpressionStatement
10(12) READ ACCESS: y
11(12) ASSERTTYPE ACCESS: null
12(13) element: PyExpressionStatement
13(14) READ ACCESS: z
14() element: null

View File

@@ -1,13 +1,16 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3) WRITE ACCESS: x
3(4) element: PyExpressionStatement
4(10) READ ACCESS: y
5(6,9) refutable pattern: 42
6(7) matched pattern: 42
7(8) element: PyExpressionStatement
8(10) READ ACCESS: y
9(10) ASSERTTYPE ACCESS: null
2(3,6) WRITE ACCESS: x
3(4) element: PyStatementList
4(5) element: PyExpressionStatement
5(13) READ ACCESS: y
6(7,12) refutable pattern: 42
7(8) matched pattern: 42
8(9) ASSERTTYPE ACCESS: null
9(10) element: PyStatementList
10(11) element: PyExpressionStatement
11(12) READ ACCESS: z
12() element: null
11(13) READ ACCESS: y
12(13) ASSERTTYPE ACCESS: null
13(14) element: PyExpressionStatement
14(15) READ ACCESS: z
15() element: null

View File

@@ -1,12 +1,15 @@
0(1) element: null
1(2) element: PyMatchStatement
2(3,6) refutable pattern: 42
2(3,7) refutable pattern: 42
3(4) matched pattern: 42
4(5) element: PyExpressionStatement
5(9) READ ACCESS: y
6(7) WRITE ACCESS: x
7(8) element: PyExpressionStatement
8(9) READ ACCESS: y
4(5) element: PyStatementList
5(6) element: PyExpressionStatement
6(12) READ ACCESS: y
7(8,11) WRITE ACCESS: x
8(9) element: PyStatementList
9(10) element: PyExpressionStatement
10(11) READ ACCESS: z
11() element: null
10(12) READ ACCESS: y
11(12) ASSERTTYPE ACCESS: null
12(13) element: PyExpressionStatement
13(14) READ ACCESS: z
14() element: null

View File

@@ -1,16 +1,17 @@
0(1) element: null
1(2) element: PyIfStatement
2(3,4) READ ACCESS: True
3() element: null. Condition: True:false
3(13) 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(15) element: null. Condition: expr:false
9(16) element: null. Condition: expr:false
10(11) element: null. Condition: expr:true
11(12) element: PyStatementList
12(15) element: PyBreakStatement
13(14) element: PyStatementList
14(15) element: PyPrintStatement
15() element: null
12(16) element: PyBreakStatement
13(14) ASSERTTYPE ACCESS: null
14(15) element: PyStatementList
15(16) element: PyPrintStatement
16() element: null

View File

@@ -1,5 +1,5 @@
match 42:
case <error descr="Pattern makes remaining case clauses unreachable">x</error>:
pass
case <warning descr="This code is unreachable">42</warning>:
case 42:
<warning descr="This code is unreachable">pass</warning>

View File

@@ -1,3 +1,3 @@
match 42:
case <error descr="Pattern makes remaining alternatives unreachable">x</error> | <error descr="Pattern does not bind name x"><warning descr="This code is unreachable">42</warning></error>:
case <error descr="Pattern makes remaining alternatives unreachable">x</error> | <error descr="Pattern does not bind name x">42</error>:
pass

View File

@@ -25,6 +25,37 @@ public class PyUnreachableCodeInspectionTest extends PyInspectionTestCase {
runWithLanguageLevel(LanguageLevel.PYTHON26, () -> doTest());
}
// PY-81676
public void testUnreachableBranchesAreStillConnected() {
// This test ensures that the unreachable branch still
// has some edges to and from the main CFG, which allows us
// to make an exception for assert_never or assert False
doTestByText("""
from typing import assert_never
if False:
<warning descr="This code is unreachable">print("actually unreachable")
print("actually unreachable")</warning>
if False:
assert False
<warning descr="This code is unreachable">print("actually unreachable")</warning>
<warning descr="This code is unreachable">print("actually unreachable")</warning>
def f(obj: int) -> None:
match scalar:
case <error descr="Pattern makes remaining case clauses unreachable">x</error>:
print("everything")
case <error descr="Pattern makes remaining case clauses unreachable">_</error>:
<warning descr="This code is unreachable">print("actually unreachable")
print("actually unreachable")</warning>
case _ as unreachable:
assert_never(unreachable)
<warning descr="This code is unreachable">print("actually unreachable")</warning>
<warning descr="This code is unreachable">print("actually unreachable")</warning>
""");
}
// PY-82712
public void testIfInsideTryExcept() {
doTestByText("""
@@ -129,6 +160,37 @@ def f():
""");
}
// PY-81676
public void testTerminatingInBranch() {
doTestByText("""
from enum import Enum
from typing import assert_never
class Foo(Enum):
A = 0
B = 1
def f1(foo: Foo) -> None:
if foo is Foo.A:
...
elif foo is Foo.B:
...
else:
assert_never(foo)
<warning descr="This code is unreachable">print("unreachable");</warning>
def f2(foo: Foo) -> None:
match foo:
case Foo.A:
...
case Foo.B:
...
case _:
assert_never(foo)
<warning descr="This code is unreachable">print("unreachable");</warning>
""");
}
// PY-81674
public void testConsecutiveTerminating() {
doTestByText("""
@@ -161,7 +223,7 @@ class Foo(Enum):
A = 0
B = 1
<warning descr="This code is unreachable">print(exit())</warning>
print(exit())
<warning descr="This code is unreachable">def unreachable(foo: Foo) -> None:
if foo is Foo.A: