Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: align pattern matching with Java 21 spec #611

Merged

Conversation

jtkiesel
Copy link
Contributor

@jtkiesel jtkiesel commented Oct 27, 2023

What changed with this PR:

Aligns pattern matching parsing with the Java 21 spec, and attempts to improve the formatting of switch pattern matching. Record patterns are now supported, and the preview-style guards (&&) have been replaced with the official-style guards (when).

NOTE: This means that the &&-style guards will no longer be supported by the parser/printer. Because that style was only present as a preview feature (and has been removed as of Java 21 in favor of the official style), perhaps that is okay. I will defer to the project owners. If they decide we must continue supporting the pattern matching preview-style guards, I can attempt to modify this PR to support both simultaneously. My initial thought is that it would be incredibly easy to support both -- I should be able to simply allow a Guard to contain either a When or an AndAnd, instead of only a When.

Example

Input

class Example {

  void example() {
    return switch (r) {
      case null, default -> 0;
      case MyRecord(A a) -> 0;
      case MyRecord(A a, B b) -> 0;
      case MyRecord(MyRecord(A a), B b) -> 0;
      case MyRecord(MyLongRecordTypeName(LongTypeName longVariableName, LongTypeName longVariableName), MyLongRecordTypeName(LongTypeName longVariableName, LongTypeName longVariableName)) -> 0;
      case MyRecord(LongTypeName longVariableName, LongTypeName longVariableName) -> 0;
      case MyRecord(LongTypeName longVariableName, LongTypeName longVariableName) when this.longVariableName > longVariableName && this.longVariableName > longVariableName -> 0;
      case MyRecord(LongTypeName longVariableName, LongTypeName longVariableName) when this.longVariableName > longVariableName && this.longVariableName > longVariableName -> longMethodName(longVariableName, longVariableName, longVariableName, longVariableName);
    };
  }
}

Output

class Example {

  void example() {
    return switch (r) {
      case null, default -> 0;
      case MyRecord(A a) -> 0;
      case MyRecord(A a, B b) -> 0;
      case MyRecord(MyRecord(A a), B b) -> 0;
      case MyRecord(
        MyLongRecordTypeName(
          LongTypeName longVariableName,
          LongTypeName longVariableName
        ),
        MyLongRecordTypeName(
          LongTypeName longVariableName,
          LongTypeName longVariableName
        )
      ) -> 0;
      case MyRecord(
        LongTypeName longVariableName,
        LongTypeName longVariableName
      ) -> 0;
      case MyRecord(
        LongTypeName longVariableName,
        LongTypeName longVariableName
      ) when (
        this.longVariableName > longVariableName &&
        this.longVariableName > longVariableName
      ) -> 0;
      case MyRecord(
        LongTypeName longVariableName,
        LongTypeName longVariableName
      ) when (
        this.longVariableName > longVariableName &&
        this.longVariableName > longVariableName
      ) -> longMethodName(
        longVariableName,
        longVariableName,
        longVariableName,
        longVariableName
      );
    };
  }
}

Simultaneously fixes an instanceof pattern matching printer bug.

Example

Input

class Example {

  public boolean test(final Object obj) {
    return (
      obj instanceof
      final Integer x &&
      (x == 5 || x == 6 || x == 7 || x == 8 || x == 9 || x == 10 || x == 11)
    );
  }
}

Output

class Example {

  public boolean test(final Object obj) {
    return (
      obj instanceof final Integer x &&
      (x == 5 || x == 6 || x == 7 || x == 8 || x == 9 || x == 10 || x == 11)
    );
  }
}

Relative issues or prs:

Closes #605
Closes #610
Obsoletes #606

@jtkiesel
Copy link
Contributor Author

Fixed a printer indentation bug with (and added a test for) nested record patterns.

$.SUBRULE($.pattern);
$.CONSUME(t.RBrace);
}
GATE: () => this.BACKTRACK_LOOKAHEAD($.recordPattern),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could switch the two options: as there is recursion in the pattern/recordPattern definition, I would suggest backtracking on the typePattern instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! Done.

@jtkiesel jtkiesel force-pushed the feat/java-21-pattern-matching branch 2 times, most recently from 079cf1d to ea767b9 Compare October 29, 2023 07:45
@jtkiesel jtkiesel force-pushed the feat/java-21-pattern-matching branch from ea767b9 to 46e379e Compare October 29, 2023 17:57
@jtkiesel jtkiesel force-pushed the feat/java-21-pattern-matching branch from 46e379e to 9b6e751 Compare October 29, 2023 18:00
@clementdessoude clementdessoude merged commit 87192b4 into jhipster:main Nov 11, 2023
6 checks passed
@clementdessoude
Copy link
Contributor

Thanks @jtkiesel !

@jtkiesel jtkiesel deleted the feat/java-21-pattern-matching branch November 11, 2023 17:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Record pattern in exhaustive switch syntax unsupported Line break between instanceof and final
2 participants