diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Scanner.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Scanner.java index e968830657a..2760d441ae4 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Scanner.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Scanner.java @@ -5176,6 +5176,7 @@ public VanguardParser(ProblemReporter reporter) { // Canonical LALR pushdown automaton identical to Parser.parse() minus side effects of any kind, returns the rule reduced. protected boolean parse(Goal goal) { + int parenthesized = 0; this.currentGoal = goal; try { int act = START_STATE; @@ -5201,6 +5202,10 @@ protected boolean parse(Goal goal) { this.unstackedAct = act; try { this.currentToken = this.scanner.getNextToken(); + if (this.currentToken == TokenNameLPAREN) + parenthesized++; + else if (this.currentToken == TokenNameRPAREN) + parenthesized --; } finally { this.unstackedAct = ERROR_ACTION; } @@ -5210,6 +5215,10 @@ protected boolean parse(Goal goal) { this.unstackedAct = act; try { this.currentToken = this.scanner.getNextToken(); + if (this.currentToken == TokenNameLPAREN) + parenthesized++; + else if (this.currentToken == TokenNameRPAREN) + parenthesized --; } finally { this.unstackedAct = ERROR_ACTION; } @@ -5220,6 +5229,15 @@ protected boolean parse(Goal goal) { // ProcessNonTerminals : do { /* reduce */ + // mimic the unfortunate side effect introduced by org.eclipse.jdt.internal.compiler.parser.Parser.consumeCaseLabelElement(CaseLabelKind) + if (parenthesized == 0 && this.currentToken == TerminalTokens.TokenNameCOMMA && this.scanner.caseStartPosition < this.scanner.startPosition) { + for (int patternRule : Goal.PatternRules) { + if (act == patternRule) { + this.scanner.multiCaseLabelComma = true; + break; + } + } + } if (goal.hasBeenReached(act, this.currentToken)) return SUCCESS; if (this.currentToken == TokenNameIdentifier) { diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchPatternTest21.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchPatternTest21.java index edd7110c322..1d07dc26939 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchPatternTest21.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchPatternTest21.java @@ -836,4 +836,126 @@ public static void main(String... args) { """, }, "success"); } + + // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/2070 + // [Switch] Compiler is unable to parse a particular multicase construct + public void testIssue2070() { + runConformTest( + new String[] { + "X.java", + """ + public class X { + public boolean foo(Object o) { + return switch (o) { + case Integer _, Integer[] _ -> true; + default -> false; + }; + } + public static void main(String argv[]) { + System.out.println(new X().foo(new Object())); + } + } + """ + }, + "false"); + } + + // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/2956 + // Unnamed patterns inside of multi case patterns fail to parse + public void testIssue2956() { + runConformTest( + new String[] { + "Main.java", + """ + public class Main { + public sealed interface MyType { + record A() implements MyType { + } + + record B(int value) implements MyType { + } + + record C() implements MyType { + } + } + + public static void main(String[] args) { + MyType myType = new MyType.A(); + switch (myType) { + case MyType.A(), MyType.B(_) -> { System.out.println("A or B");} + case MyType.C() -> {} + } + } + } + """ + }, + "A or B"); + } + + + // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/2956 + // Unnamed patterns inside of multi case patterns fail to parse + public void testIssue2956_2() { + runConformTest( + new String[] { + "Main.java", + """ + public class Main { + public sealed interface MyType { + record A() implements MyType { + } + + record B(int value) implements MyType { + } + + record C() implements MyType { + } + } + + public static void main(String[] args) { + MyType myType = new MyType.A(); + switch (myType) { + case MyType.A() -> { System.out.println("A");} + case MyType.B(_) -> { System.out.println("B");} + case MyType.C() -> { System.out.println("C");} + } + } + } + """ + }, + "A"); + } + + + // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/2956 + // Unnamed patterns inside of multi case patterns fail to parse + public void testIssue2956_3() { + runConformTest( + new String[] { + "Main.java", + """ + public class Main { + public sealed interface MyType { + record A() implements MyType { + } + + record B(int value) implements MyType { + } + + record C() implements MyType { + } + } + + public static void main(String[] args) { + MyType myType = new MyType.A(); + switch (myType) { + case MyType.B(_), MyType.A() -> { System.out.println("A or B");} + case MyType.C() -> {} + } + } + } + """ + }, + "A or B"); + } }