code: private ParseTree parseArrayPattern(PatternKind kind) {
      SourcePosition start = getTreeStartLocation();
      ImmutableList.Builder<ParseTree> elements = ImmutableList.builder();
      eat(TokenType.OPEN_SQUARE);
      while (peek(TokenType.COMMA) || peekArrayPatternElement()) {
        if (peek(TokenType.COMMA)) {
          SourcePosition nullStart = getTreeStartLocation();
          eat(TokenType.COMMA);
          elements.add(new NullTree(getTreeLocation(nullStart)));
        } else {
          elements.add(parsePatternAssignmentTarget(kind));
  
          if (peek(TokenType.COMMA)) {
            // Consume the comma separator
            eat(TokenType.COMMA);
          } else {
            // Otherwise we must be done
            break;
          }
        }
      }
      if (peek(TokenType.SPREAD)) {
        recordFeatureUsed(Feature.ARRAY_PATTERN_REST);
        elements.add(parsePatternRest(kind));
      }
      if (eat(TokenType.CLOSE_SQUARE) == null) {
        // If we get no closing bracket then return invalid tree to avoid compiler tripping
        // downstream. It's needed only for IDE mode where compiler continues processing even if
        // source has syntactic errors.
        return new MissingPrimaryExpressionTree(getTreeLocation(getTreeStartLocation()));
      }
      return new ArrayPatternTree(getTreeLocation(start), elements.build());
    }
docs: Pattern ::= ... | "[" Element? ("," Element?)* "]"