Bug 573516 - [17][406] Grammar for Switch pattern - AST Changes

Change-Id: Id58493465ecea5eba4d733ad0a6b324d5d99ab72
Signed-off-by: Manoj Palat <manpalat@in.ibm.com>
Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/181462
Tested-by: JDT Bot <jdt-bot@eclipse.org>
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchPatternTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchPatternTest.java
index 0f6a81b..6c481a1 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchPatternTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchPatternTest.java
@@ -422,4 +422,35 @@
 			"The method Zork() is undefined for the type X\n" +
 			"----------\n");
 	}
+	public void _testBug573516_012() {
+		runNegativeTest(
+			new String[] {
+				"X.java",
+				"public class X {\n"+
+				" private static void foo(Object o) {\n"+
+				"   switch (o.hashCode()) {\n"+
+				"     case 1 : System.out.println(\"Error mix n match\");\n"+
+				"     case var s : System.out.println(\"Error should be ANY_PATTERN\");\n"+
+				"     default : System.out.println(\"Object\");\n"+
+				"   }\n"+
+				" }\n"+
+				" public static void main(String[] args) {\n"+
+				"   foo(\"Hello World\");\n"+
+				"   Zork();\n"+
+				" }\n"+
+				"}\n"+
+				"class Y {}",
+			},
+			"----------\n" +
+			"1. ERROR in X.java (at line 3)\n" +
+			"	switch (o) {\n" +
+			"	        ^\n" +
+			"Cannot switch on a value of type Object. Only convertible int values, strings or enum variables are permitted\n" +
+			"----------\n" +
+			"2. ERROR in X.java (at line 10)\n" +
+			"	Zork();\n" +
+			"	^^^^\n" +
+			"The method Zork() is undefined for the type X\n" +
+			"----------\n");
+	}
 }
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter_16Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter_16Test.java
index 576bdf8..2995de6 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter_16Test.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter_16Test.java
@@ -50,6 +50,11 @@
 
 	ICompilationUnit workingCopy;
 
+	static {
+//		TESTS_NUMBERS = new int[] { 19 };
+//		TESTS_RANGE = new int[] { 1, -1 };
+//		TESTS_NAMES = new String[] {"testPatternInstanceOfExpression002"};
+	}
 	public void setUpSuite() throws Exception {
 		super.setUpSuite();
 		this.ast = AST.newAST(getAST16(), false);
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
index 71adafe..8ca4944 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
@@ -8,6 +8,10 @@
  *
  * SPDX-License-Identifier: EPL-2.0
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     Timo Kinnunen - Contributions for bug 377373 - [subwords] known limitations with JDT 3.8
  *     							Bug 420953 - [subwords] Constructors that don't match prefix not found
@@ -122,6 +126,7 @@
 import org.eclipse.jdt.internal.compiler.ExtraFlags;
 import org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression;
 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.AbstractExPatNode;
 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
@@ -6462,12 +6467,14 @@
 			char[][] alreadyUsedConstants = new char[switchStatement.caseCount][];
 			int alreadyUsedConstantCount = 0;
 			for (int i = 0; i < switchStatement.caseCount; i++) {
-				Expression[] caseExpressions = cases[i].constantExpressions;
-				Expression caseExpression = caseExpressions != null && caseExpressions.length > 0 ?
-						caseExpressions[0] : null;
-				if((caseExpression instanceof SingleNameReference)
-						&& (caseExpression.resolvedType != null && caseExpression.resolvedType.isEnum())) {
-					alreadyUsedConstants[alreadyUsedConstantCount++] = ((SingleNameReference)caseExpression).token;
+				AbstractExPatNode[] caseLabelElements = cases[i].caseLabelElements;
+				AbstractExPatNode caseLabelElement = caseLabelElements != null && caseLabelElements.length > 0 ?
+						caseLabelElements[0] : null;
+				if(caseLabelElement instanceof SingleNameReference) {
+					SingleNameReference ref = (SingleNameReference) caseLabelElement;
+					if(ref.resolvedType != null && ref.resolvedType.isEnum()) {
+						alreadyUsedConstants[alreadyUsedConstantCount++] = ref.token;
+					}
 				}
 			}
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractExPatNode.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractExPatNode.java
new file mode 100644
index 0000000..892b6cb
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractExPatNode.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2021 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.ast;
+
+/**
+ * Abstract parent of Expression and Pattern
+ */
+public abstract class AbstractExPatNode extends Statement {
+
+	@Override
+	public StringBuffer printStatement(int indent, StringBuffer output) {
+		return print(indent, output).append(";"); //$NON-NLS-1$
+	}
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractTypePattern.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractTypePattern.java
index 891d0bf..71d0d51 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractTypePattern.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractTypePattern.java
@@ -22,7 +22,6 @@
 import org.eclipse.jdt.internal.compiler.flow.FlowContext;
 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
-import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 
 public abstract class AbstractTypePattern extends Pattern {
@@ -52,11 +51,6 @@
 		return new LocalDeclaration[] { this.local };
 	}
 
-	@Override
-	public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
-		// TODO Auto-generated method stub
-
-	}
 
 	@Override
 	public void resolve(BlockScope scope) {
@@ -65,13 +59,7 @@
 	}
 
 	@Override
-	public TypeBinding resolveType(BlockScope scope) {
-		// TODO Auto-generated method stub
-		return null;
-	}
-
-	@Override
-	public StringBuffer print(int indent, StringBuffer output) {
+	public StringBuffer printPattern(int indent, StringBuffer output) {
 		return this.local != null ? this.local.printAsExpression(indent, output) : output;
 	}
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
index 8c504b2..d783f2b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -8,12 +8,17 @@
  *
  * SPDX-License-Identifier: EPL-2.0
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.ast;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
@@ -34,7 +39,7 @@
 public class CaseStatement extends Statement {
 
 	public BranchLabel targetLabel;
-	public Expression[] constantExpressions; // case with multiple expressions
+	public AbstractExPatNode[] caseLabelElements;
 	public BranchLabel[] targetLabels; // for multiple expressions
 	public boolean isExpr = false;
 
@@ -42,8 +47,8 @@
 	this(sourceEnd, sourceStart, constantExpression != null ? new Expression[] {constantExpression} : null);
 }
 
-public CaseStatement(int sourceEnd, int sourceStart, Expression[] constantExpressions) {
-	this.constantExpressions = constantExpressions;
+public CaseStatement(int sourceEnd, int sourceStart, AbstractExPatNode[] caseLabelElements) {
+	this.caseLabelElements = caseLabelElements;
 	this.sourceEnd = sourceEnd;
 	this.sourceStart = sourceStart;
 }
@@ -53,9 +58,13 @@
 	BlockScope currentScope,
 	FlowContext flowContext,
 	FlowInfo flowInfo) {
-	if (this.constantExpressions != null) {
-		for (Expression e : this.constantExpressions) {
-			analyseConstantExpression(currentScope, flowContext, flowInfo, e);
+	if (this.caseLabelElements != null) {
+		for (AbstractExPatNode aep : this.caseLabelElements) {
+			if (aep instanceof Expression)
+				analyseConstantExpression(currentScope, flowContext, flowInfo, (Expression) aep);
+			else if (aep instanceof Pattern)
+				analysePattern(currentScope, flowContext, flowInfo, (Pattern) aep);
+			// TODO: what about case default, case null - should be covered in expressions - check
 		}
 	}
 	return flowInfo;
@@ -72,16 +81,24 @@
 	e.analyseCode(currentScope, flowContext, flowInfo);
 }
 
+private void analysePattern(
+		BlockScope currentScope,
+		FlowContext flowContext,
+		FlowInfo flowInfo,
+		Pattern p) {
+	p.analyseCode(currentScope, flowContext, flowInfo);
+}
+
 @Override
 public StringBuffer printStatement(int tab, StringBuffer output) {
 	printIndent(tab, output);
-	if (this.constantExpressions == null) {
+	if (this.caseLabelElements == null) {
 		output.append("default "); //$NON-NLS-1$
 		output.append(this.isExpr ? "->" : ":"); //$NON-NLS-1$ //$NON-NLS-2$
 	} else {
 		output.append("case "); //$NON-NLS-1$
-		for (int i = 0, l = this.constantExpressions.length; i < l; ++i) {
-			this.constantExpressions[i].printExpression(0, output);
+		for (int i = 0, l = this.caseLabelElements.length; i < l; ++i) {
+			this.caseLabelElements[i].print(0, output);
 			if (i < l -1) output.append(',');
 		}
 		output.append(this.isExpr ? " ->" : " :"); //$NON-NLS-1$ //$NON-NLS-2$
@@ -125,9 +142,10 @@
 public Constant[] resolveCase(BlockScope scope, TypeBinding switchExpressionType, SwitchStatement switchStatement) {
 	// switchExpressionType maybe null in error case
 	scope.enclosingCase = this; // record entering in a switch case block
-	Expression[] constExprs = this.constantExpressions;
-	Expression constExpr = constExprs != null && constExprs.length > 0 ? constExprs[0] : null;
-	if (constExpr == null) {
+	AbstractExPatNode[] aepNodes = this.caseLabelElements;
+	AbstractExPatNode aepNode = aepNodes != null && aepNodes.length > 0 ? aepNodes[0] : null;
+
+	if (aepNode == null) { // TODO check the case for patterns
 		// remember the default case into the associated switch statement
 		if (switchStatement.defaultCase != null)
 			scope.problemReporter().duplicateDefaultCase(this);
@@ -136,6 +154,14 @@
 		switchStatement.defaultCase = this;
 		return Constant.NotAConstantList;
 	}
+	if (aepNode instanceof Pattern) {
+		return resolvePatternCase(scope, switchExpressionType, switchStatement);
+	}
+	// TODO : This needs a revamp - currently we are assuming that mix of pattern and expressions
+	// will not be available here and will be tagged as error and bailed out earlier.
+	// to do this while taking up resolution.
+	Expression[] constExprs = Arrays.asList(aepNodes).toArray(new Expression[0]);
+	Expression constExpr = (Expression) aepNode;
 	// add into the collection of cases of the associated switch statement
 	switchStatement.cases[switchStatement.caseCount++] = this;
 	if (switchExpressionType != null && switchExpressionType.isEnum() && (constExpr instanceof SingleNameReference)) {
@@ -199,11 +225,16 @@
 	return Constant.NotAConstant;
 }
 
+// TODO: Just a placeholder - refactor and add code for patterns;
+private Constant[] resolvePatternCase(BlockScope scope, TypeBinding switchExpressionType, SwitchStatement switchStatement) {
+	return Constant.NotAConstantList;
+}
+
 @Override
 public void traverse(ASTVisitor visitor, 	BlockScope blockScope) {
 	if (visitor.visit(this, blockScope)) {
-		if (this.constantExpressions != null) {
-			for (Expression e : this.constantExpressions) {
+		if (this.caseLabelElements != null) {
+			for (AbstractExPatNode e : this.caseLabelElements) {
 				e.traverse(visitor, blockScope);
 			}
 		}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
index 497cc11..282689c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
@@ -8,6 +8,10 @@
  *
  * SPDX-License-Identifier: EPL-2.0
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contributions for
@@ -65,7 +69,7 @@
 import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement;
 import org.eclipse.jdt.internal.compiler.util.Messages;
 
-public abstract class Expression extends Statement {
+public abstract class Expression extends AbstractExPatNode {
 
 	public Constant constant;
 
@@ -1103,11 +1107,6 @@
 public abstract StringBuffer printExpression(int indent, StringBuffer output);
 
 @Override
-public StringBuffer printStatement(int indent, StringBuffer output) {
-	return print(indent, output).append(";"); //$NON-NLS-1$
-}
-
-@Override
 public void resolve(BlockScope scope) {
 	// drops the returning expression's type whatever the type is.
 	this.resolveType(scope);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/GuardedPattern.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/GuardedPattern.java
index 5c671cc..ab83ff4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/GuardedPattern.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/GuardedPattern.java
@@ -22,7 +22,6 @@
 import org.eclipse.jdt.internal.compiler.flow.FlowContext;
 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
-import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 
 public class GuardedPattern extends Pattern {
@@ -63,13 +62,6 @@
 		// TODO Auto-generated method stub
 
 	}
-
-	@Override
-	public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
-		// TODO Auto-generated method stub
-
-	}
-
 	@Override
 	public void resolve(BlockScope scope) {
 		// TODO Auto-generated method stub
@@ -77,13 +69,7 @@
 	}
 
 	@Override
-	public TypeBinding resolveType(BlockScope scope) {
-		// TODO Auto-generated method stub
-		return null;
-	}
-
-	@Override
-	public StringBuffer print(int indent, StringBuffer output) {
+	public StringBuffer printPattern(int indent, StringBuffer output) {
 		this.primaryPattern.print(indent, output).append(" && "); //$NON-NLS-1$
 		return this.conditionalAndExpression.print(indent, output);
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Pattern.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Pattern.java
index aac1ba7..e9e794d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Pattern.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Pattern.java
@@ -17,13 +17,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.ast;
 
-import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
-import org.eclipse.jdt.internal.compiler.flow.FlowContext;
-import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
-import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
-import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
-
-public abstract class Pattern extends ASTNode {
+public abstract class Pattern extends AbstractExPatNode {
 
 	public enum PatternKind {
 		ANY_PATTERN,
@@ -35,21 +29,18 @@
 	public int parenthesisSourceStart;
 	public int parenthesisSourceEnd;
 
-	public abstract FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo);
-
-	public abstract void generateCode(BlockScope currentScope, CodeStream codeStream);
-
 	public abstract AbstractVariableDeclaration[] getPatternVariables();
 
-	// TODO: Recheck whether we need this in Pattern
-	public abstract void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired);
-
 	public abstract String getKindName(); // convenience method.
 
 	public abstract PatternKind kind();
 
-	public abstract void resolve(BlockScope scope);
+	@Override
+	public StringBuffer print(int indent, StringBuffer output) {
+		printIndent(indent, output);
+		return printPattern(indent, output);
+	}
 
-	public abstract TypeBinding resolveType(BlockScope scope);
+	public abstract StringBuffer printPattern(int indent, StringBuffer output);
 
 }
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
index c5e181e..5369c8a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
@@ -406,7 +406,7 @@
 	{
 		for (int i = 0, j = 0, max = this.caseCount; i < max; i++) {
 			CaseStatement stmt = this.cases[i];
-			int l = stmt.constantExpressions.length;
+			int l = stmt.caseLabelElements.length;
 			stmt.targetLabels = new BranchLabel[l];
 			for (int k = 0; k < l; ++k) {
 				stmt.targetLabels[k] = (caseLabels[j] = newLabel.apply(codeStream));
@@ -607,8 +607,8 @@
 		for (int i = 0, l = this.statements.length; i < l; ++i) {
 			final Statement statement = this.statements[i];
 			if (statement instanceof CaseStatement)  {
-				Expression[] exprs = ((CaseStatement) statement).constantExpressions;
-				n += exprs != null ? exprs.length : 0;
+				ASTNode[] nodes = ((CaseStatement) statement).caseLabelElements;
+				n += nodes != null ? nodes.length : 0;
 			}
 		}
 		return n;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
index 108a7ac..33ab0ed 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
@@ -2266,30 +2266,26 @@
 	concatNodeLists();
 }
 protected void consumeCaseLabel() {
-//	// SwitchLabel ::= 'case' ConstantExpression ':'
-//	this.expressionLengthPtr--;
-//	Expression expression = this.expressionStack[this.expressionPtr--];
-//	CaseStatement caseStatement = new CaseStatement(expression, expression.sourceEnd, this.intStack[this.intPtr--]);
-//	// Look for $fall-through$ tag in leading comment for case statement
-//	if (hasLeadingTagComment(FALL_THROUGH_TAG, caseStatement.sourceStart)) {
-//		caseStatement.bits |= ASTNode.DocumentedFallthrough;
-//	}
-//	pushOnAstStack(caseStatement);
-	Expression[] constantExpressions = null;
-	int length = 0;
-	if ((length = this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
-		this.expressionPtr -= length;
-		System.arraycopy(
-			this.expressionStack,
-			this.expressionPtr + 1,
-			constantExpressions = new Expression[length],
-			0,
-			length);
-	} else {
-		// TODO : ERROR
+	// SwitchLabel ::= 'case' ConstantExpression ':'
+
+	int length = this.expressionLengthStack[this.expressionLengthPtr--];
+	AbstractExPatNode[] caseLabelElements = new AbstractExPatNode[length];
+	this.expressionPtr -= length;
+	int delta = this.expressionPtr + 1;
+	for (int i = 0; i < length; ++i) {
+		Expression expression = this.expressionStack[i + delta];
+		caseLabelElements[i] = expression;
 	}
-	CaseStatement caseStatement = new CaseStatement(constantExpressions[length - 1].sourceEnd, this.intStack[this.intPtr--], constantExpressions);
-	if (constantExpressions.length > 1) {
+
+	System.arraycopy(
+		this.expressionStack,
+		this.expressionPtr + 1,
+		caseLabelElements,
+		0,
+		length);
+
+	CaseStatement caseStatement = new CaseStatement(caseLabelElements[length - 1].sourceEnd, this.intStack[this.intPtr--], caseLabelElements);
+	if (caseLabelElements.length > 1) {
 		if (!this.parsingJava14Plus) {
 			problemReporter().multiConstantCaseLabelsNotSupported(caseStatement);
 		}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
index 4257291..2425941 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
@@ -8,6 +8,10 @@
  *
  * SPDX-License-Identifier: EPL-2.0
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -17,6 +21,7 @@
 package org.eclipse.jdt.core.dom;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Comparator;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -51,6 +56,7 @@
 import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
 import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
 import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.Pattern;
 import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
 import org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference;
 import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
@@ -1404,8 +1410,14 @@
 
 	public SwitchCase convert(org.eclipse.jdt.internal.compiler.ast.CaseStatement statement) {
 		SwitchCase switchCase = new SwitchCase(this.ast);
+		org.eclipse.jdt.internal.compiler.ast.AbstractExPatNode[] aepNodes = statement.caseLabelElements;
+		if (aepNodes != null && aepNodes.length > 0 && (aepNodes[0] instanceof Pattern)) {
+			switchCase.expressions().clear();
+			return switchCase;
+		}
+		org.eclipse.jdt.internal.compiler.ast.Expression[] expressions = aepNodes == null ? null :
+				Arrays.asList(aepNodes).toArray(new org.eclipse.jdt.internal.compiler.ast.Expression[0]);
 		if (this.ast.apiLevel >= AST.JLS14_INTERNAL) {
-			org.eclipse.jdt.internal.compiler.ast.Expression[] expressions = statement.constantExpressions;
 			if (expressions == null || expressions.length == 0) {
 				switchCase.expressions().clear();
 			} else {
@@ -1414,9 +1426,8 @@
 				}
 			}
 		} else {
-			org.eclipse.jdt.internal.compiler.ast.Expression[] constantExpressions = statement.constantExpressions;
 			org.eclipse.jdt.internal.compiler.ast.Expression constantExpression =
-					constantExpressions != null && constantExpressions.length > 0 ? constantExpressions[0] : null;
+					expressions != null && expressions.length > 0 ? expressions[0] : null;
 			if (constantExpression == null) {
 				internalSetExpression(switchCase, null);
 			} else {