mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-48760 Implement CFG for PEP-634 match statements
I introduced a new type of CFG instructions, similar to ConditionalInstruction, called RefutablePatternInstruction. The idea is that every pattern that can possibly fail to match is surrounded with a pair of such instructions, helping to describe how the control flow moves in each case. The PEP calls the opposite type of patterns that always match "irrefutable", hence the name. We need these synthetic instructions because otherwise some refutable patterns such as literal ones (e.g. "42") don't leave any nodes in the graph. Incorporating the information about irrefutable patterns right into the graph allows catching cases such as "wildcard/name capture makes remaining patterns unreachable", both in OR patterns and independent case clauses. GitOrigin-RevId: beebe1890a6a824b188e6954a2c92f7ec52079e0
This commit is contained in:
committed by
intellij-monorepo-bot
parent
79999b52e4
commit
cb08d4de98
@@ -1,4 +1,7 @@
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface PyAsPattern extends PyPattern {
|
||||
@NotNull PyPattern getPattern();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
// 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.psi;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface PyCaseClause extends PyStatementPart {
|
||||
@Nullable PyPattern getPattern();
|
||||
@Nullable PyExpression getGuardCondition();
|
||||
}
|
||||
|
||||
@@ -326,6 +326,10 @@ public class PyElementVisitor extends PsiElementVisitor {
|
||||
visitPyPattern(node);
|
||||
}
|
||||
|
||||
public void visitWildcardPattern(@NotNull PyWildcardPattern node) {
|
||||
visitPyPattern(node);
|
||||
}
|
||||
|
||||
public void visitPyClassPattern(@NotNull PyClassPattern node) {
|
||||
visitPyPattern(node);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// 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.psi;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface PyGroupPattern extends PyPattern {
|
||||
@NotNull PyPattern getPattern();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
// 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.psi;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface PyMatchStatement extends PyStatement {
|
||||
@Nullable PyExpression getSubject();
|
||||
@NotNull List<PyCaseClause> getCaseClauses();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
// 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.psi;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface PyOrPattern extends PyPattern {
|
||||
@NotNull List<PyPattern> getAlternatives();
|
||||
}
|
||||
|
||||
+6
-1
@@ -353,6 +353,11 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyMatchStatement(@NotNull PyMatchStatement matchStatement) {
|
||||
new PyMatchStatementControlFlowBuilder(myBuilder, this).build(matchStatement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyIfStatement(final @NotNull PyIfStatement node) {
|
||||
myBuilder.startNode(node);
|
||||
@@ -506,7 +511,7 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isConjunctionOrDisjunction(@Nullable PyExpression node) {
|
||||
static boolean isConjunctionOrDisjunction(@Nullable PyExpression node) {
|
||||
if (node instanceof PyBinaryExpression) {
|
||||
final var operator = ((PyBinaryExpression)node).getOperator();
|
||||
return operator == PyTokenTypes.AND_KEYWORD || operator == PyTokenTypes.OR_KEYWORD;
|
||||
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
package com.jetbrains.python.codeInsight.controlflow;
|
||||
|
||||
import com.intellij.codeInsight.controlflow.ConditionalInstruction;
|
||||
import com.intellij.codeInsight.controlflow.ControlFlowBuilder;
|
||||
import com.intellij.codeInsight.controlflow.Instruction;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static com.jetbrains.python.codeInsight.controlflow.PyControlFlowBuilder.isConjunctionOrDisjunction;
|
||||
|
||||
public final class PyMatchStatementControlFlowBuilder {
|
||||
private final ControlFlowBuilder myBuilder;
|
||||
private final PyElementVisitor myBaseVisitor;
|
||||
|
||||
public PyMatchStatementControlFlowBuilder(@NotNull ControlFlowBuilder builder, @NotNull PyElementVisitor baseVisitor) {
|
||||
myBuilder = builder;
|
||||
myBaseVisitor = baseVisitor;
|
||||
}
|
||||
|
||||
public final void build(@NotNull PyMatchStatement matchStatement) {
|
||||
myBuilder.startNode(matchStatement);
|
||||
PyExpression subject = matchStatement.getSubject();
|
||||
if (subject != null) {
|
||||
subject.accept(myBaseVisitor);
|
||||
}
|
||||
for (PyCaseClause caseClause : matchStatement.getCaseClauses()) {
|
||||
processCaseClause(caseClause);
|
||||
}
|
||||
}
|
||||
|
||||
private void processCaseClause(@NotNull PyCaseClause clause) {
|
||||
PyPattern pattern = clause.getPattern();
|
||||
if (pattern != null) {
|
||||
processPattern(pattern);
|
||||
retargetOutgoingPatternEdges(pattern, (oldScope, instr) -> {
|
||||
return instr.isMatched() ? pattern : clause;
|
||||
});
|
||||
}
|
||||
PyStatementList statementList = clause.getStatementList();
|
||||
PyExpression guard = clause.getGuardCondition();
|
||||
if (guard != null) {
|
||||
guard.accept(myBaseVisitor);
|
||||
// Retarget failure edges coming from inner OR and AND expressions
|
||||
retargetOutgoingEdges(guard, (pendingScope, instr) -> {
|
||||
if (instr instanceof ConditionalInstruction && !((ConditionalInstruction)instr).getResult()) {
|
||||
return clause;
|
||||
}
|
||||
return pendingScope;
|
||||
});
|
||||
// Top-level OR and AND expressions should have had their own outgoing failure edges
|
||||
if (!isConjunctionOrDisjunction(guard)) {
|
||||
myBuilder.addPendingEdge(clause, myBuilder.prevInstruction);
|
||||
}
|
||||
myBuilder.startConditionalNode(statementList, guard, true);
|
||||
}
|
||||
statementList.accept(myBaseVisitor);
|
||||
PyMatchStatement matchStatement = PsiTreeUtil.getParentOfType(clause, PyMatchStatement.class);
|
||||
assert matchStatement != null;
|
||||
retargetOutgoingEdges(statementList, (pendingScope, instruction) -> matchStatement);
|
||||
myBuilder.addPendingEdge(matchStatement, myBuilder.prevInstruction);
|
||||
myBuilder.prevInstruction = null;
|
||||
}
|
||||
|
||||
private void processPattern(@NotNull PyPattern pattern) {
|
||||
boolean isRefutable = !isIrrefutablePattern(pattern);
|
||||
if (isRefutable) {
|
||||
RefutablePatternInstruction instruction = new RefutablePatternInstruction(myBuilder, pattern, false);
|
||||
myBuilder.addNodeAndCheckPending(instruction);
|
||||
myBuilder.addPendingEdge(pattern, instruction);
|
||||
}
|
||||
|
||||
if (pattern instanceof PyWildcardPattern) {
|
||||
myBuilder.startNode(pattern);
|
||||
}
|
||||
else if (pattern instanceof PyOrPattern) {
|
||||
List<PyPattern> alternatives = ((PyOrPattern)pattern).getAlternatives();
|
||||
PyPattern lastAlternative = ContainerUtil.getLastItem(alternatives);
|
||||
for (PyPattern alternative : alternatives) {
|
||||
processPattern(alternative);
|
||||
if (alternative != lastAlternative) {
|
||||
myBuilder.addPendingEdge(alternative, myBuilder.prevInstruction);
|
||||
myBuilder.prevInstruction = null;
|
||||
}
|
||||
retargetOutgoingEdges(alternative, (pendingScope, instruction) -> {
|
||||
if (instruction instanceof RefutablePatternInstruction && !((RefutablePatternInstruction)instruction).isMatched()) {
|
||||
// Pattern has failed, jump to the next alternative if any
|
||||
return alternative;
|
||||
}
|
||||
// Pattern succeeded, jump out of OR-pattern. It can be either a refutable pattern or a capture/wildcard node.
|
||||
else {
|
||||
return pattern;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
pattern.acceptChildren(new PyElementVisitor() {
|
||||
@Override
|
||||
public void visitPyReferenceExpression(@NotNull PyReferenceExpression node) {
|
||||
myBaseVisitor.visitPyReferenceExpression(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyTargetExpression(@NotNull PyTargetExpression node) {
|
||||
myBaseVisitor.visitPyTargetExpression(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyPattern(@NotNull PyPattern node) {
|
||||
processPattern(node);
|
||||
retargetOutgoingPatternEdges(pattern, (oldScope, instr) -> {
|
||||
// Mismatch in a non-OR pattern means mismatch of the containing pattern as well
|
||||
return instr.isMatched() ? oldScope : pattern;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyPatternArgumentList(@NotNull PyPatternArgumentList node) {
|
||||
node.acceptChildren(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (isRefutable) {
|
||||
myBuilder.addNode(new RefutablePatternInstruction(myBuilder, pattern, true));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isIrrefutablePattern(@NotNull PyPattern pattern) {
|
||||
Ref<Boolean> result = Ref.create(false);
|
||||
pattern.accept(new PyElementVisitor() {
|
||||
@Override
|
||||
public void visitPyAsPattern(@NotNull PyAsPattern node) {
|
||||
result.set(isIrrefutablePattern(node.getPattern()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyCapturePattern(@NotNull PyCapturePattern node) {
|
||||
result.set(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWildcardPattern(@NotNull PyWildcardPattern node) {
|
||||
result.set(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyDoubleStarPattern(@NotNull PyDoubleStarPattern node) {
|
||||
result.set(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPySingleStarPattern(@NotNull PySingleStarPattern node) {
|
||||
result.set(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyGroupPattern(@NotNull PyGroupPattern node) {
|
||||
result.set(isIrrefutablePattern(node.getPattern()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyOrPattern(@NotNull PyOrPattern node) {
|
||||
result.set(ContainerUtil.exists(node.getAlternatives(), p -> isIrrefutablePattern(p)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyPattern(@NotNull PyPattern node) {
|
||||
result.set(false);
|
||||
}
|
||||
});
|
||||
return result.get();
|
||||
}
|
||||
|
||||
private void retargetOutgoingEdges(@NotNull PsiElement scopeAncestor,
|
||||
@NotNull BiFunction<PsiElement, Instruction, PsiElement> newScopeProvider) {
|
||||
myBuilder.processPending((oldScope, instruction) -> {
|
||||
if (oldScope != null && PsiTreeUtil.isAncestor(scopeAncestor, oldScope, false)) {
|
||||
myBuilder.addPendingEdge(newScopeProvider.apply(oldScope, instruction), instruction);
|
||||
}
|
||||
else {
|
||||
myBuilder.addPendingEdge(oldScope, instruction);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void retargetOutgoingPatternEdges(@NotNull PsiElement scopeAncestor,
|
||||
@NotNull BiFunction<PsiElement, RefutablePatternInstruction, PsiElement> newScopeProvider) {
|
||||
retargetOutgoingEdges(scopeAncestor, (pendingScope, instruction) -> {
|
||||
if (instruction instanceof RefutablePatternInstruction) {
|
||||
return newScopeProvider.apply(pendingScope, (RefutablePatternInstruction)instruction);
|
||||
}
|
||||
return pendingScope;
|
||||
});
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.jetbrains.python.codeInsight.controlflow;
|
||||
|
||||
import com.intellij.codeInsight.controlflow.ControlFlowBuilder;
|
||||
import com.intellij.codeInsight.controlflow.impl.InstructionImpl;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.python.psi.PyPattern;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class RefutablePatternInstruction extends InstructionImpl {
|
||||
private final boolean myMatched;
|
||||
|
||||
public RefutablePatternInstruction(@NotNull ControlFlowBuilder builder,
|
||||
@NotNull PyPattern element, boolean matched) {
|
||||
super(builder, element);
|
||||
myMatched = matched;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PsiElement getElement() {
|
||||
PsiElement element = super.getElement();
|
||||
assert element != null;
|
||||
return element;
|
||||
}
|
||||
|
||||
public boolean isMatched() {
|
||||
return myMatched;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getElementPresentation() {
|
||||
return (myMatched ? "matched" : "refutable") + " pattern: " + getElement().getText();
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package com.jetbrains.python.psi.impl;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.jetbrains.python.psi.PyAsPattern;
|
||||
import com.jetbrains.python.psi.PyElementVisitor;
|
||||
import com.jetbrains.python.psi.PyPattern;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PyAsPatternImpl extends PyElementImpl implements PyAsPattern {
|
||||
public PyAsPatternImpl(ASTNode astNode) {
|
||||
@@ -13,4 +15,9 @@ public class PyAsPatternImpl extends PyElementImpl implements PyAsPattern {
|
||||
protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
|
||||
pyVisitor.visitPyAsPattern(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PyPattern getPattern() {
|
||||
return findNotNullChildByClass(PyPattern.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,23 +2,32 @@ package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.psi.PyCaseClause;
|
||||
import com.jetbrains.python.psi.PyElementVisitor;
|
||||
import com.jetbrains.python.psi.PyStatementList;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class PyCaseClauseImpl extends PyElementImpl implements PyCaseClause {
|
||||
public PyCaseClauseImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PyStatementList getStatementList() {
|
||||
return childToPsiNotNull(PyElementTypes.STATEMENT_LIST);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
|
||||
pyVisitor.visitPyCaseClause(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PyPattern getPattern() {
|
||||
return findChildByClass(PyPattern.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PyExpression getGuardCondition() {
|
||||
return findChildByClass(PyExpression.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PyStatementList getStatementList() {
|
||||
return childToPsiNotNull(PyElementTypes.STATEMENT_LIST);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.jetbrains.python.psi.impl;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.jetbrains.python.psi.PyElementVisitor;
|
||||
import com.jetbrains.python.psi.PyGroupPattern;
|
||||
import com.jetbrains.python.psi.PyPattern;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PyGroupPatternImpl extends PyElementImpl implements PyGroupPattern {
|
||||
public PyGroupPatternImpl(ASTNode astNode) {
|
||||
@@ -13,4 +15,9 @@ public class PyGroupPatternImpl extends PyElementImpl implements PyGroupPattern
|
||||
protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
|
||||
pyVisitor.visitPyGroupPattern(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PyPattern getPattern() {
|
||||
return findNotNullChildByClass(PyPattern.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.psi.PyCaseClause;
|
||||
import com.jetbrains.python.psi.PyElementVisitor;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.PyMatchStatement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PyMatchStatementImpl extends PyElementImpl implements PyMatchStatement {
|
||||
public PyMatchStatementImpl(ASTNode astNode) {
|
||||
@@ -13,4 +20,14 @@ public class PyMatchStatementImpl extends PyElementImpl implements PyMatchStatem
|
||||
protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
|
||||
pyVisitor.visitPyMatchStatement(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PyExpression getSubject() {
|
||||
return findChildByClass(PyExpression.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<PyCaseClause> getCaseClauses() {
|
||||
return findChildrenByType(PyElementTypes.CASE_CLAUSE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,11 @@ package com.jetbrains.python.psi.impl;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.jetbrains.python.psi.PyElementVisitor;
|
||||
import com.jetbrains.python.psi.PyOrPattern;
|
||||
import com.jetbrains.python.psi.PyPattern;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class PyOrPatternImpl extends PyElementImpl implements PyOrPattern {
|
||||
public PyOrPatternImpl(ASTNode astNode) {
|
||||
@@ -13,4 +18,9 @@ public class PyOrPatternImpl extends PyElementImpl implements PyOrPattern {
|
||||
protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
|
||||
pyVisitor.visitPyOrPattern(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<PyPattern> getAlternatives() {
|
||||
return Arrays.asList(findChildrenByClass(PyPattern.class));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.jetbrains.python.psi.PyElementVisitor;
|
||||
import com.jetbrains.python.psi.PyWildcardPattern;
|
||||
|
||||
public class PyWildcardPatternImpl extends PyElementImpl implements PyWildcardPattern {
|
||||
public PyWildcardPatternImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
|
||||
pyVisitor.visitWildcardPattern(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
while x:
|
||||
match x:
|
||||
case 42:
|
||||
break
|
||||
y
|
||||
z
|
||||
@@ -0,0 +1,14 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyWhileStatement
|
||||
2(3,11) READ ACCESS: x
|
||||
3(4) element: PyStatementList. Condition: x:true
|
||||
4(5) element: PyMatchStatement
|
||||
5(6) READ ACCESS: x
|
||||
6(7,9) refutable pattern: 42
|
||||
7(8) matched pattern: 42
|
||||
8(11) element: PyBreakStatement
|
||||
9(10) element: PyExpressionStatement
|
||||
10(1) READ ACCESS: y
|
||||
11(12) element: PyExpressionStatement
|
||||
12(13) READ ACCESS: z
|
||||
13() element: null
|
||||
@@ -0,0 +1,6 @@
|
||||
while x:
|
||||
match x:
|
||||
case 42:
|
||||
continue
|
||||
y
|
||||
z
|
||||
@@ -0,0 +1,14 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyWhileStatement
|
||||
2(3,11) READ ACCESS: x
|
||||
3(4) element: PyStatementList. Condition: x:true
|
||||
4(5) element: PyMatchStatement
|
||||
5(6) READ ACCESS: x
|
||||
6(7,9) refutable pattern: 42
|
||||
7(8) matched pattern: 42
|
||||
8(1) element: PyContinueStatement
|
||||
9(10) element: PyExpressionStatement
|
||||
10(1) READ ACCESS: y
|
||||
11(12) element: PyExpressionStatement
|
||||
12(13) READ ACCESS: z
|
||||
13() element: null
|
||||
@@ -0,0 +1,5 @@
|
||||
def func(x):
|
||||
match x:
|
||||
case 42:
|
||||
return
|
||||
y
|
||||
@@ -0,0 +1,10 @@
|
||||
0(1) element: null
|
||||
1(2) WRITE ACCESS: x
|
||||
2(3) element: PyMatchStatement
|
||||
3(4) READ ACCESS: x
|
||||
4(5,7) refutable pattern: 42
|
||||
5(6) matched pattern: 42
|
||||
6(9) element: PyReturnStatement
|
||||
7(8) element: PyExpressionStatement
|
||||
8(9) READ ACCESS: y
|
||||
9() element: null
|
||||
@@ -0,0 +1,9 @@
|
||||
match 1:
|
||||
case 1:
|
||||
match 11:
|
||||
case 11:
|
||||
y11
|
||||
y1
|
||||
case 2:
|
||||
y2
|
||||
z
|
||||
@@ -0,0 +1,18 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,11) 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(9) READ ACCESS: y11
|
||||
9(10) element: PyExpressionStatement
|
||||
10(15) READ ACCESS: y1
|
||||
11(12,15) refutable pattern: 2
|
||||
12(13) matched pattern: 2
|
||||
13(14) element: PyExpressionStatement
|
||||
14(15) READ ACCESS: y2
|
||||
15(16) element: PyExpressionStatement
|
||||
16(17) READ ACCESS: z
|
||||
17() element: null
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
match 1:
|
||||
case 1:
|
||||
match 11:
|
||||
case 11:
|
||||
y11
|
||||
case 2:
|
||||
y2
|
||||
z
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,9) refutable pattern: 1
|
||||
3(4) matched pattern: 1
|
||||
4(5) element: PyMatchStatement
|
||||
5(6,13) refutable pattern: 11
|
||||
6(7) matched pattern: 11
|
||||
7(8) element: PyExpressionStatement
|
||||
8(13) READ ACCESS: y11
|
||||
9(10,13) refutable pattern: 2
|
||||
10(11) matched pattern: 2
|
||||
11(12) element: PyExpressionStatement
|
||||
12(13) READ ACCESS: y2
|
||||
13(14) element: PyExpressionStatement
|
||||
14(15) READ ACCESS: z
|
||||
15() element: null
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case [42] | foo.bar as x:
|
||||
y
|
||||
z
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,16) refutable pattern: [42] | foo.bar as x
|
||||
3(4,16) refutable pattern: [42] | foo.bar
|
||||
4(5,8) refutable pattern: [42]
|
||||
5(6,8) refutable pattern: 42
|
||||
6(7) matched pattern: 42
|
||||
7(12) matched pattern: [42]
|
||||
8(9,16) refutable pattern: foo.bar
|
||||
9(10) READ ACCESS: foo
|
||||
10(11) matched pattern: foo.bar
|
||||
11(12) matched pattern: [42] | foo.bar
|
||||
12(13) WRITE ACCESS: x
|
||||
13(14) matched pattern: [42] | foo.bar as x
|
||||
14(15) element: PyExpressionStatement
|
||||
15(16) READ ACCESS: y
|
||||
16(17) element: PyExpressionStatement
|
||||
17(18) READ ACCESS: z
|
||||
18() element: null
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case [x]:
|
||||
y
|
||||
z
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,7) refutable pattern: [x]
|
||||
3(4) WRITE ACCESS: x
|
||||
4(5) matched pattern: [x]
|
||||
5(6) element: PyExpressionStatement
|
||||
6(7) READ ACCESS: y
|
||||
7(8) element: PyExpressionStatement
|
||||
8(9) READ ACCESS: z
|
||||
9() element: null
|
||||
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case x:
|
||||
y
|
||||
z
|
||||
@@ -0,0 +1,8 @@
|
||||
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
|
||||
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case Class(1, attr=foo.bar):
|
||||
x
|
||||
y
|
||||
@@ -0,0 +1,17 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,14) refutable pattern: Class(1, attr=foo.bar)
|
||||
3(4) READ ACCESS: Class
|
||||
4(5,14) refutable pattern: 1
|
||||
5(6) matched pattern: 1
|
||||
6(7,14) refutable pattern: attr=foo.bar
|
||||
7(8,14) refutable pattern: foo.bar
|
||||
8(9) 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(14) READ ACCESS: x
|
||||
14(15) element: PyExpressionStatement
|
||||
15(16) READ ACCESS: y
|
||||
16() element: null
|
||||
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case x if x > 0 and x < 10:
|
||||
y
|
||||
z
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3) WRITE ACCESS: x
|
||||
3(4) element: PyBinaryExpression
|
||||
4(5,6) READ ACCESS: x
|
||||
5(13) element: null. Condition: x > 0:false
|
||||
6(7) element: null. Condition: x > 0:true
|
||||
7(8,9) READ ACCESS: x
|
||||
8(13) element: null. Condition: x < 10:false
|
||||
9(10) element: null. Condition: x < 10:true
|
||||
10(11) element: PyStatementList. Condition: x > 0 and x < 10:true
|
||||
11(12) element: PyExpressionStatement
|
||||
12(13) READ ACCESS: y
|
||||
13(14) element: PyExpressionStatement
|
||||
14(15) READ ACCESS: z
|
||||
15() element: null
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case x if x % 4 == 0 and (x % 400 == 0 or x % 100 != 0):
|
||||
y
|
||||
z
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3) WRITE ACCESS: x
|
||||
3(4) element: PyBinaryExpression
|
||||
4(5,6) READ ACCESS: x
|
||||
5(19) 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(16) element: null. Condition: x % 400 == 0:true
|
||||
10(11) element: null. Condition: x % 400 == 0:false
|
||||
11(12,13) READ ACCESS: x
|
||||
12(19) element: null. Condition: x % 100 != 0:false
|
||||
13(14,15) element: null. Condition: x % 100 != 0:true
|
||||
14(19) element: null. Condition: (x % 400 == 0 or x % 100 != 0):false
|
||||
15(16) element: null. Condition: (x % 400 == 0 or x % 100 != 0):true
|
||||
16(17) element: PyStatementList. Condition: x % 4 == 0 and (x % 400 == 0 or x % 100 != 0):true
|
||||
17(18) element: PyExpressionStatement
|
||||
18(19) READ ACCESS: y
|
||||
19(20) element: PyExpressionStatement
|
||||
20(21) READ ACCESS: z
|
||||
21() element: null
|
||||
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case x if x > 0 or x < 0:
|
||||
y
|
||||
z
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3) WRITE ACCESS: x
|
||||
3(4) element: PyBinaryExpression
|
||||
4(5,6) READ ACCESS: x
|
||||
5(10) element: null. Condition: x > 0:true
|
||||
6(7) element: null. Condition: x > 0:false
|
||||
7(8,9) READ ACCESS: x
|
||||
8(13) element: null. Condition: x < 0:false
|
||||
9(10) element: null. Condition: x < 0:true
|
||||
10(11) element: PyStatementList. Condition: x > 0 or x < 0:true
|
||||
11(12) element: PyExpressionStatement
|
||||
12(13) READ ACCESS: y
|
||||
13(14) element: PyExpressionStatement
|
||||
14(15) READ ACCESS: z
|
||||
15() element: null
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case {"foo": 1, **x}:
|
||||
y
|
||||
z
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
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"
|
||||
5(6) matched pattern: "foo"
|
||||
6(7,13) 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(13) READ ACCESS: y
|
||||
13(14) element: PyExpressionStatement
|
||||
14(15) READ ACCESS: z
|
||||
15() element: null
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case [x1, x2, x3] if (x1 or x2) > x3:
|
||||
y
|
||||
z
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,18) refutable pattern: [x1, x2, x3]
|
||||
3(4) WRITE ACCESS: x1
|
||||
4(5) WRITE ACCESS: x2
|
||||
5(6) WRITE ACCESS: x3
|
||||
6(7) matched pattern: [x1, x2, x3]
|
||||
7(8) element: PyBinaryExpression
|
||||
8(9,10) READ ACCESS: x1
|
||||
9(14) element: null. Condition: x1:true
|
||||
10(11) element: null. Condition: x1:false
|
||||
11(12,13) READ ACCESS: x2
|
||||
12(14) element: null. Condition: x2:false
|
||||
13(14) element: null. Condition: x2:true
|
||||
14(15,18) READ ACCESS: x3
|
||||
15(16) element: PyStatementList. Condition: (x1 or x2) > x3:true
|
||||
16(17) element: PyExpressionStatement
|
||||
17(18) READ ACCESS: y
|
||||
18(19) element: PyExpressionStatement
|
||||
19(20) READ ACCESS: z
|
||||
20() element: null
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case x | [x]:
|
||||
y
|
||||
z
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(6) WRITE ACCESS: x
|
||||
3(4,8) refutable pattern: [x]
|
||||
4(5) WRITE ACCESS: x
|
||||
5(6) matched pattern: [x]
|
||||
6(7) element: PyExpressionStatement
|
||||
7(8) READ ACCESS: y
|
||||
8(9) element: PyExpressionStatement
|
||||
9(10) READ ACCESS: z
|
||||
10() element: null
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case [x] | x :
|
||||
y
|
||||
z
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,5) refutable pattern: [x]
|
||||
3(4) WRITE ACCESS: x
|
||||
4(6) matched pattern: [x]
|
||||
5(6) WRITE ACCESS: x
|
||||
6(7) element: PyExpressionStatement
|
||||
7(8) READ ACCESS: y
|
||||
8(9) element: PyExpressionStatement
|
||||
9(10) READ ACCESS: z
|
||||
10() element: null
|
||||
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case 42:
|
||||
y
|
||||
z
|
||||
@@ -0,0 +1,9 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,6) refutable pattern: 42
|
||||
3(4) matched pattern: 42
|
||||
4(5) element: PyExpressionStatement
|
||||
5(6) READ ACCESS: y
|
||||
6(7) element: PyExpressionStatement
|
||||
7(8) READ ACCESS: z
|
||||
8() element: null
|
||||
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case {'foo': 1, 'bar': foo.bar}:
|
||||
x
|
||||
y
|
||||
@@ -0,0 +1,22 @@
|
||||
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'
|
||||
5(6) matched pattern: 'foo'
|
||||
6(7,19) 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'
|
||||
11(12) matched pattern: 'bar'
|
||||
12(13,19) refutable pattern: foo.bar
|
||||
13(14) 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(19) READ ACCESS: x
|
||||
19(20) element: PyExpressionStatement
|
||||
20(21) READ ACCESS: y
|
||||
21() element: null
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case [1, *x]:
|
||||
y
|
||||
z
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,9) refutable pattern: [1, *x]
|
||||
3(4,9) refutable pattern: 1
|
||||
4(5) matched pattern: 1
|
||||
5(6) WRITE ACCESS: x
|
||||
6(7) matched pattern: [1, *x]
|
||||
7(8) element: PyExpressionStatement
|
||||
8(9) READ ACCESS: y
|
||||
9(10) element: PyExpressionStatement
|
||||
10(11) READ ACCESS: z
|
||||
11() element: null
|
||||
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case 1 | (2 | 3):
|
||||
x
|
||||
y
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,16) refutable pattern: 1 | (2 | 3)
|
||||
3(4,5) refutable pattern: 1
|
||||
4(14) matched pattern: 1
|
||||
5(6,16) refutable pattern: (2 | 3)
|
||||
6(7,16) refutable pattern: 2 | 3
|
||||
7(8,9) refutable pattern: 2
|
||||
8(14) matched pattern: 2
|
||||
9(10,16) refutable pattern: 3
|
||||
10(11) matched pattern: 3
|
||||
11(12) matched pattern: 2 | 3
|
||||
12(13) matched pattern: (2 | 3)
|
||||
13(14) matched pattern: 1 | (2 | 3)
|
||||
14(15) element: PyExpressionStatement
|
||||
15(16) READ ACCESS: x
|
||||
16(17) element: PyExpressionStatement
|
||||
17(18) READ ACCESS: y
|
||||
18() element: null
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case ((x)):
|
||||
y
|
||||
z
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
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
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case [x] | (foo.bar as x):
|
||||
y
|
||||
z
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,17) refutable pattern: [x] | (foo.bar as x)
|
||||
3(4,6) refutable pattern: [x]
|
||||
4(5) WRITE ACCESS: x
|
||||
5(15) matched pattern: [x]
|
||||
6(7,17) refutable pattern: (foo.bar as x)
|
||||
7(8,17) refutable pattern: foo.bar as x
|
||||
8(9,17) refutable pattern: foo.bar
|
||||
9(10) READ ACCESS: foo
|
||||
10(11) matched pattern: foo.bar
|
||||
11(12) WRITE ACCESS: x
|
||||
12(13) matched pattern: foo.bar as x
|
||||
13(14) matched pattern: (foo.bar as x)
|
||||
14(15) matched pattern: [x] | (foo.bar as x)
|
||||
15(16) element: PyExpressionStatement
|
||||
16(17) READ ACCESS: y
|
||||
17(18) element: PyExpressionStatement
|
||||
18(19) READ ACCESS: z
|
||||
19() element: null
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case [] | 42:
|
||||
y
|
||||
z
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,10) refutable pattern: [] | 42
|
||||
3(4,5) refutable pattern: []
|
||||
4(8) matched pattern: []
|
||||
5(6,10) refutable pattern: 42
|
||||
6(7) matched pattern: 42
|
||||
7(8) matched pattern: [] | 42
|
||||
8(9) element: PyExpressionStatement
|
||||
9(10) READ ACCESS: y
|
||||
10(11) element: PyExpressionStatement
|
||||
11(12) READ ACCESS: z
|
||||
12() element: null
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case _ | 42:
|
||||
y
|
||||
z
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(5) element: PyWildcardPattern
|
||||
3(4,7) refutable pattern: 42
|
||||
4(5) matched pattern: 42
|
||||
5(6) element: PyExpressionStatement
|
||||
6(7) READ ACCESS: y
|
||||
7(8) element: PyExpressionStatement
|
||||
8(9) READ ACCESS: z
|
||||
9() element: null
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case [x] if x > 0 and x % 2 == 0:
|
||||
y
|
||||
z
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,15) refutable pattern: [x]
|
||||
3(4) WRITE ACCESS: x
|
||||
4(5) matched pattern: [x]
|
||||
5(6) element: PyBinaryExpression
|
||||
6(7,8) READ ACCESS: x
|
||||
7(15) element: null. Condition: x > 0:false
|
||||
8(9) element: null. Condition: x > 0:true
|
||||
9(10,11) READ ACCESS: x
|
||||
10(15) element: null. Condition: x % 2 == 0:false
|
||||
11(12) element: null. Condition: x % 2 == 0:true
|
||||
12(13) element: PyStatementList. Condition: x > 0 and x % 2 == 0:true
|
||||
13(14) element: PyExpressionStatement
|
||||
14(15) READ ACCESS: y
|
||||
15(16) element: PyExpressionStatement
|
||||
16(17) READ ACCESS: z
|
||||
17() element: null
|
||||
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case [1, foo.bar]:
|
||||
x
|
||||
y
|
||||
@@ -0,0 +1,14 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,11) refutable pattern: [1, foo.bar]
|
||||
3(4,11) refutable pattern: 1
|
||||
4(5) matched pattern: 1
|
||||
5(6,11) refutable pattern: foo.bar
|
||||
6(7) READ ACCESS: foo
|
||||
7(8) matched pattern: foo.bar
|
||||
8(9) matched pattern: [1, foo.bar]
|
||||
9(10) element: PyExpressionStatement
|
||||
10(11) READ ACCESS: x
|
||||
11(12) element: PyExpressionStatement
|
||||
12(13) READ ACCESS: y
|
||||
13() element: null
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case [1 | x]:
|
||||
y
|
||||
z
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,9) refutable pattern: [1 | x]
|
||||
3(4,5) refutable pattern: 1
|
||||
4(7) matched pattern: 1
|
||||
5(6) WRITE ACCESS: x
|
||||
6(7) matched pattern: [1 | x]
|
||||
7(8) element: PyExpressionStatement
|
||||
8(9) READ ACCESS: y
|
||||
9(10) element: PyExpressionStatement
|
||||
10(11) READ ACCESS: z
|
||||
11() element: null
|
||||
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case x if x > 0:
|
||||
y
|
||||
z
|
||||
@@ -0,0 +1,10 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3) WRITE ACCESS: x
|
||||
3(4,7) READ ACCESS: x
|
||||
4(5) element: PyStatementList. Condition: x > 0:true
|
||||
5(6) element: PyExpressionStatement
|
||||
6(7) READ ACCESS: y
|
||||
7(8) element: PyExpressionStatement
|
||||
8(9) READ ACCESS: z
|
||||
9() element: null
|
||||
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case _:
|
||||
y
|
||||
z
|
||||
@@ -0,0 +1,8 @@
|
||||
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
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
match 42:
|
||||
case [1, *_]:
|
||||
y
|
||||
z
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,9) refutable pattern: [1, *_]
|
||||
3(4,9) refutable pattern: 1
|
||||
4(5) matched pattern: 1
|
||||
5(6) element: PyWildcardPattern
|
||||
6(7) matched pattern: [1, *_]
|
||||
7(8) element: PyExpressionStatement
|
||||
8(9) READ ACCESS: y
|
||||
9(10) element: PyExpressionStatement
|
||||
10(11) READ ACCESS: z
|
||||
11() element: null
|
||||
@@ -0,0 +1,6 @@
|
||||
match 42:
|
||||
case x:
|
||||
y
|
||||
case 42:
|
||||
y
|
||||
z
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3) WRITE ACCESS: x
|
||||
3(4) element: PyExpressionStatement
|
||||
4(9) READ ACCESS: y
|
||||
5(6,9) refutable pattern: 42
|
||||
6(7) matched pattern: 42
|
||||
7(8) element: PyExpressionStatement
|
||||
8(9) READ ACCESS: y
|
||||
9(10) element: PyExpressionStatement
|
||||
10(11) READ ACCESS: z
|
||||
11() element: null
|
||||
@@ -0,0 +1,6 @@
|
||||
match 42:
|
||||
case 42:
|
||||
y
|
||||
case x:
|
||||
y
|
||||
z
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyMatchStatement
|
||||
2(3,6) 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
|
||||
9(10) element: PyExpressionStatement
|
||||
10(11) READ ACCESS: z
|
||||
11() element: null
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
match x:
|
||||
case (1 as y) | y:
|
||||
pass
|
||||
@@ -0,0 +1,3 @@
|
||||
match x:
|
||||
case [1 as y, <warning descr="Redeclared 'y' defined above without usage">y</warning>]:
|
||||
pass
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
def func(x):
|
||||
match x:
|
||||
case 42 as y:
|
||||
pass
|
||||
case z:
|
||||
pass
|
||||
print(<warning descr="Local variable 'y' might be referenced before assignment">y</warning>, <warning descr="Local variable 'z' might be referenced before assignment">z</warning>)
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
def func(x):
|
||||
match x:
|
||||
case 42:
|
||||
y = 'foo'
|
||||
print(<warning descr="Local variable 'y' might be referenced before assignment">y</warning>)
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
def func(x):
|
||||
match x:
|
||||
case [1, y] | [2, z]:
|
||||
print(<warning descr="Local variable 'y' might be referenced before assignment">y</warning>, <warning descr="Local variable 'z' might be referenced before assignment">z</warning>)
|
||||
@@ -0,0 +1,6 @@
|
||||
def func(xs):
|
||||
for x in xs:
|
||||
match x:
|
||||
case 42:
|
||||
break
|
||||
print(x)
|
||||
@@ -0,0 +1,6 @@
|
||||
def func(xs):
|
||||
for x in xs:
|
||||
match x:
|
||||
case 42:
|
||||
continue
|
||||
print(x)
|
||||
@@ -0,0 +1,5 @@
|
||||
def func(x):
|
||||
match x:
|
||||
case 42:
|
||||
return
|
||||
print(x)
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
match 42:
|
||||
case x:
|
||||
pass
|
||||
case <warning descr="This code is unreachable">42</warning>:
|
||||
pass
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
match 42:
|
||||
case x | <warning descr="This code is unreachable">42</warning>:
|
||||
pass
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
def func(x):
|
||||
match x:
|
||||
case (1 as y) | (2 as y):
|
||||
print(y)
|
||||
@@ -0,0 +1,4 @@
|
||||
def func(x):
|
||||
match x:
|
||||
case [used, <weak_warning descr="Local variable 'unused' value is not used">unused</weak_warning>]:
|
||||
print(used)
|
||||
@@ -318,6 +318,166 @@ public class PyControlFlowBuilderTest extends LightMarkedTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseCapturePattern() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseWildcardPattern() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseLiteralPattern() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseBindingSequencePattern() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementTwoClausesCapturePatternFirst() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementTwoClausesCapturePatternLast() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseAliasedRefutableOrPattern() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseRefutableOrPattern() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseIrrefutableOrPatternCaptureVariantFirst() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseIrrefutableOrPatternCaptureVariantLast() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseRefutableOrPatternWithNonBindingVariants() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseRefutableOrPatternWithWildcard() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseSequencePatternWithSingleOrPattern() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseNestedOrPatterns() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseClassPattern() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseMappingPattern() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseSequencePattern() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseParenthesizedCapturePattern() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseNamedSingleStarPatternIsIrrefutable() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseWildcardSingleStarPatternIsIrrefutable() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseDoubleStarPatternIsIrrefutable() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementClauseWithBreak() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementClauseWithContinue() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementClauseWithReturn() {
|
||||
doTestFirstStatement();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementNestedMatchStatementLastInClause() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementNestedMatchStatement() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseTrivialGuard() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseDisjunctionGuard() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseConjunctionGuard() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseDisjunctionConjunctionGuard() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseRefutablePatternAndConjunctionGuard() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testMatchStatementSingleClauseGuardWithNonTopLevelDisjunction() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTestFirstStatement() {
|
||||
final String testName = getTestName(false);
|
||||
configureByFile(testName + ".py");
|
||||
|
||||
@@ -198,6 +198,16 @@ public class PyRedeclarationInspectionTest extends PyInspectionTestCase {
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON36, this::doTest);
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testNotReportedForNameRedeclarationInOrPattern() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testPatternBindsSameNameTwice() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<? extends PyInspection> getInspectionClass() {
|
||||
|
||||
+15
@@ -362,6 +362,21 @@ public class PyUnboundLocalVariableInspectionTest extends PyInspectionTestCase {
|
||||
" print(<warning descr=\"Name 'r' can be undefined\">r</warning>)");
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testCapturePatternNameUsedAfterMatchStatement() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testOrPatternAlternativesDefineDifferentNames() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testNameDefinedInCaseClauseBodyUsedAfterMatchStatement() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<? extends PyInspection> getInspectionClass() {
|
||||
|
||||
@@ -170,6 +170,31 @@ public class PyUnreachableCodeInspectionTest extends PyInspectionTestCase {
|
||||
);
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testContinueInCaseClause() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testBreakInCaseClause() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testReturnInCaseClause() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testUnreachablePatternAfterIrrefutableCaseClause() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testUnreachablePatternAfterIrrefutableOrPatternAlternative() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<? extends PyInspection> getInspectionClass() {
|
||||
|
||||
@@ -203,6 +203,16 @@ public class PyUnusedLocalInspectionTest extends PyInspectionTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testAllBindingsOfSameNameInOrPatternConsideredUsed() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-48760
|
||||
public void testUnusedCapturePatterns() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<? extends PyInspection> getInspectionClass() {
|
||||
|
||||
Reference in New Issue
Block a user