Skip to content

Conversation

@jtkiesel
Copy link
Contributor

@jtkiesel jtkiesel commented May 3, 2025

What changed with this PR:

There exists some ambiguity in the parser within comma-separated TypePatterns, because TypePattern contains a VariableDeclaratorList, which is comma-separated VariableDeclarators. The parser cannot currently determine where the VariableDeclaratorList ends and the next TypePattern begins. This was previously realized in #707, within ComponentPatternList, and is now experienced in #733, within SwitchLabel.

I realized that the JLS specifically mentions semantic restrictions that make it easy to resolve this ambiguity. From 14.30.1. Kinds of Patterns (emphasis mine):

The rules for a local variable declared in a type pattern are specified in §14.4. In addition, all of the following must be true, or a compile-time error occurs:

  • The LocalVariableType in a top level type pattern denotes a reference type (and furthermore is not var).
  • The VariableDeclaratorList consists of a single VariableDeclarator.
  • The VariableDeclarator has no initializer.
  • The VariableDeclaratorId has no bracket pairs.

As such, this PR limits TypePattern's VariableDeclaratorList to a single VariableDeclarator in our parser. That change also allowed me to remove the patch that was added in #708, as this fix also resolves the ambiguity for the issue seen in #707.

Example

Input

public class Fail {

  private Function<ShootResult, ShootResult.Miss> missed() {
    return lastResult -> switch (lastResult) {
      case ShootResult.Miss(int fails) -> new ShootResult.Miss(fails + 1);
      case ShootResult.Many _ ,ShootResult.One _ -> new ShootResult.Miss(0); // crash on this line
             
    };
  }

  private sealed interface ShootResult {
    record One(Pin pin) implements ShootResult {}
    record Many(int number) implements ShootResult {}
    record Miss(int timesInRow) implements ShootResult {}
  }
}

Output

public class Fail {

  private Function<ShootResult, ShootResult.Miss> missed() {
    return lastResult ->
      switch (lastResult) {
        case ShootResult.Miss(int fails) -> new ShootResult.Miss(fails + 1);
        case ShootResult.Many _, ShootResult.One _ -> new ShootResult.Miss(0); // crash on this line
      };
  }

  private sealed interface ShootResult {
    record One(Pin pin) implements ShootResult {}

    record Many(int number) implements ShootResult {}

    record Miss(int timesInRow) implements ShootResult {}
  }
}

Relative issues or prs:

Closes #733

Copy link
Contributor

@clementdessoude clementdessoude left a comment

Choose a reason for hiding this comment

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

Great work ! And well spotted 😀

Just a small suggestion but we also could merge at is

@jtkiesel jtkiesel force-pushed the fix/multiple-type-pattern-ambiguity branch from f61ee29 to 41d70f9 Compare May 11, 2025 06:49
@jtkiesel jtkiesel merged commit d923e8d into jhipster:main May 11, 2025
6 checks passed
@jtkiesel jtkiesel deleted the fix/multiple-type-pattern-ambiguity branch May 11, 2025 06:59
@lanwen
Copy link

lanwen commented May 26, 2025

@clementdessoude, @jtkiesel would you be so kind as of releasing this in the next version? Or maybe it's possible to grab that some other way?

@jtkiesel
Copy link
Contributor Author

jtkiesel commented Jun 4, 2025

@lanwen Sorry for the delay. I'd like to get this project to auto-publish new versions of the package for each meaningful commit pushed to main, but for now releases are manual. Thanks for your patience! I've published version 2.6.8, so please give that a try and let me know if you experience any issues!

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.

Formatting fails with unnamed and multiple patterns from inner interface

3 participants