@Override
  public void visitPyCaseClause(@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);
      }
    });
  }
@Override
  public void visitPyCaseClause(@NotNull PyCaseClause caseClause)