@Override
  public void visitPyOrPattern(@NotNull PyOrPattern orPattern) {
    List<PyPattern> alternatives = orPattern.getAlternatives();
    PyPattern lastAlternative = alternatives.get(alternatives.size() - 1);
    Map<PyPattern, Set<String>> patternToBoundNames = new HashMap<>();
    Set<String> allBoundNames = new HashSet<>();

    for (PyPattern alternative : alternatives) {
      Set<String> boundNames = SyntaxTraverser.psiTraverser(alternative)
        .filter(PyTargetExpression.class)
        .map(PyTargetExpression::getName)
        .toSet();
      patternToBoundNames.put(alternative, boundNames);
      allBoundNames.addAll(boundNames);

      if (alternative != lastAlternative && alternative.isIrrefutable()) {
        markError(alternative, PyPsiBundle.message("ANN.patterns.pattern.makes.remaining.alternatives.unreachable"));
      }
    }

    for (Map.Entry<PyPattern, Set<String>> entry : patternToBoundNames.entrySet()) {
      Set<String> boundNames = entry.getValue();
      if (!boundNames.equals(allBoundNames)) {
        Collection<String> missingNames = ContainerUtil.subtract(allBoundNames, boundNames);
        String nameList = StringUtil.join(ContainerUtil.sorted(missingNames), ", ");
        markError(entry.getKey(), PyPsiBundle.message("ANN.patterns.pattern.does.not.bind.names", missingNames.size(), nameList));
      }
    }
  }
@Override
  public void visitPyOrPattern(@NotNull PyOrPattern orPattern)