void (@NotNull PyCaseClause caseClause) { PyPattern pattern = caseClause.getPattern(); if (pattern == null) return; Stack<Set<String>> boundNamesPerOrBranch = new Stack<>(); // Assume that the top-level pattern is a single branch of a synthetic OR pattern boundNamesPerOrBranch.push(new HashSet<>()); pattern.accept(new PyRecursiveElementVisitor() { @Override public void visitPyOrPattern(@NotNull PyOrPattern orPattern) { Set<String> allBoundNamesInOrPattern = new HashSet<>(); for (PyPattern alternative : orPattern.getAlternatives()) { boundNamesPerOrBranch.push(new HashSet<>()); alternative.accept(this); allBoundNamesInOrPattern.addAll(boundNamesPerOrBranch.peek()); boundNamesPerOrBranch.pop(); } boundNamesPerOrBranch.peek().addAll(allBoundNamesInOrPattern); } @Override public void visitPyTargetExpression(@NotNull PyTargetExpression target) { String name = target.getName(); boolean alreadyBound = ContainerUtil.exists(boundNamesPerOrBranch, names -> names.contains(name)); if (alreadyBound) { markError(target, PyPsiBundle.message("ANN.patterns.name.already.bound", name)); } boundNamesPerOrBranch.peek().add(name); } }); }