Bug 543240: [12] Second Case Constant in a switch label is reported as
missing

Change-Id: Ifd3ec58cae737f9a3c47393887c6727e1cbad079
Signed-off-by: Jay Arthanareeswaran <jarthana@in.ibm.com>
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java
index a5a0e5e..ec6f7a7 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java
@@ -1049,7 +1049,6 @@
 	protected INameEnvironment javaClassLib;
 	protected TestVerifier verifier;
 	protected boolean shouldSwallowCaptureId;
-	protected boolean enablePreview;
 	public AbstractRegressionTest(String name) {
 		super(name);
 	}
@@ -1734,6 +1733,9 @@
 			JavacTestOptions.DEFAULT /* default javac test options */);
 	}
 	protected void runConformTest(String[] testFiles, String expectedOutput, Map customOptions) {
+		runConformTest(testFiles, expectedOutput, customOptions, null);
+	}
+	protected void runConformTest(String[] testFiles, String expectedOutput, Map customOptions, String[] vmArguments) {
 		runTest(
 			// test directory preparation
 			true /* flush output directory */,
@@ -1748,7 +1750,7 @@
 			null /* do not check compiler log */,
 			// runtime options
 			false /* do not force execution */,
-			null /* no vm arguments */,
+			vmArguments /* no vm arguments */,
 			// runtime results
 			expectedOutput /* expected output string */,
 			null /* do not check error string */,
@@ -2549,10 +2551,19 @@
 						JavacTestOptions.DEFAULT /* javac test options */);
 		}
 	protected void runNegativeTest(
+			String[] testFiles,
+			String expectedCompilerLog,
+			String[] classLibraries,
+			boolean shouldFlushOutputDirectory,
+			Map customOptions) {
+		runNegativeTest(testFiles, expectedCompilerLog, classLibraries, shouldFlushOutputDirectory, null, customOptions);
+	}
+	protected void runNegativeTest(
 		String[] testFiles,
 		String expectedCompilerLog,
 		String[] classLibraries,
 		boolean shouldFlushOutputDirectory,
+		String[] vmArguments,
 		Map customOptions) {
 		runTest(
 	 		// test directory preparation
@@ -2573,7 +2584,7 @@
 			expectedCompilerLog /* expected compiler log */,
 			// runtime options
 			false /* do not force execution */,
-			null /* no vm arguments */,
+			vmArguments /* no vm arguments */,
 			// runtime results
 			null /* do not check output string */,
 			null /* do not check error string */,
@@ -3113,16 +3124,6 @@
 					this.verifier = new TestVerifier(false);
 					this.createdVerifier = true;
 				}
-				if (this.enablePreview) {
-					if (vmArguments == null) {
-						vmArguments = new String[1];
-						vmArguments[0] = "--enable-preview";
-					} else {
-						int size = vmArguments.length;
-						System.arraycopy(vmArguments, 0, vmArguments = new String[size + 1], 0, size);
-						vmArguments[size] = "--enable-preview";
-					}
-				}
 				boolean passed =
 					this.verifier.verifyClassFiles(
 						sourceFile,
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java
index 143f7c1..4dc1e10 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java
@@ -26,7 +26,7 @@
 
 	static {
 //		TESTS_NUMBERS = new int [] { 40 };
-//		TESTS_NAMES = new String[] { "testBug531714_010" };
+//		TESTS_NAMES = new String[] { "testBug543240_1" };
 	}
 	
 	public static Class<?> testClass() {
@@ -51,37 +51,30 @@
 	
 
 	public void testSimpleExpressions() {
-		boolean old = this.enablePreview;
-		try {
-			this.enablePreview = true;
-			runConformTest(
-					new String[] {
+		runConformTest(
+				new String[] {
 						"X.java",
 						"public class X {\n" +
-						"	static int twice(int i) {\n" +
-						"		int tw = switch (i) {\n" +
-						"			case 0 -> i * 0;\n" +
-						"			case 1 -> 2;\n" +
-						"			default -> 3;\n" +
-						"		};\n" +
-						"		return tw;\n" +
-						"	}\n" +
-						"	public static void main(String... args) {\n" +
-						"		System.out.print(twice(3));\n" +
-						"	}\n" +
-						"}\n"
-					},
-					"3");
-		} finally {
-			this.enablePreview = old;
-		}
+								"	static int twice(int i) {\n" +
+								"		int tw = switch (i) {\n" +
+								"			case 0 -> i * 0;\n" +
+								"			case 1 -> 2;\n" +
+								"			default -> 3;\n" +
+								"		};\n" +
+								"		return tw;\n" +
+								"	}\n" +
+								"	public static void main(String... args) {\n" +
+								"		System.out.print(twice(3));\n" +
+								"	}\n" +
+								"}\n"
+				},
+				"3",
+				null,
+				new String[] {"--enable-preview"});
 	}
 	public void testSwitchExpression_531714_002() {
-		boolean old = this.enablePreview;
-		try {
-			this.enablePreview = true;
-			runConformTest(
-					new String[] {
+		runConformTest(
+				new String[] {
 						"X.java",
 						"public class X {\n"+
 								"	static int twice(int i) throws Exception {\n"+
@@ -109,11 +102,10 @@
 								"		}\n"+
 								"	}\n"+
 								"}\n"
-					},
-					"Got Exception");
-		} finally {
-			this.enablePreview = old;
-		}
+				},
+				"Got Exception",
+				null,
+				new String[] {"--enable-preview"});
 	}
 	public void testBug531714_error_003() {
 		this.runNegativeTest(
@@ -245,36 +237,32 @@
 	 * dev note: ref consumeToken().case Switch 
 	 */
 	public void testBug531714_error_007() {
-		boolean old = this.enablePreview;
-		try {
-			this.enablePreview = true;
-			runConformTest(
-					new String[] {
+		runConformTest(
+				new String[] {
 						"X.java",
 						"public class X {\n"+
-						"	static int foo(int i) {\n"+
-						"		int tw = \n"+
-						"		switch (i) {\n"+
-						"			case 1 -> \n"+
-						"			 {\n"+
-						" 				int z = 100;\n"+
-						" 				break z;\n"+
-						"			}\n"+
-						"			default -> {\n"+
-						"				break 12;\n"+
-						"			}\n"+
-						"		};\n"+
-						"		return tw;\n"+
-						"	}\n"+
-						"	public static void main(String[] args) {\n"+
-						"		System.out.print(foo(1));\n"+
-						"	}\n"+
-						"}\n"
-					},
-					"100");
-		} finally {
-			this.enablePreview = old;
-		}
+								"	static int foo(int i) {\n"+
+								"		int tw = \n"+
+								"		switch (i) {\n"+
+								"			case 1 -> \n"+
+								"			 {\n"+
+								" 				int z = 100;\n"+
+								" 				break z;\n"+
+								"			}\n"+
+								"			default -> {\n"+
+								"				break 12;\n"+
+								"			}\n"+
+								"		};\n"+
+								"		return tw;\n"+
+								"	}\n"+
+								"	public static void main(String[] args) {\n"+
+								"		System.out.print(foo(1));\n"+
+								"	}\n"+
+								"}\n"
+				},
+				"100",
+				null,
+				new String[] {"--enable-preview"});
 	}
 	public void testBug531714_008() {
 		Map<String, String> disablePreviewOptions = getCompilerOptions();
@@ -430,37 +418,32 @@
 				options);
 	}
 	public void testBug531714_011() {
-		boolean old = this.enablePreview;
-		try {
-			Map<String, String> options = getCompilerOptions();
-			options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
-			options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.WARNING);
-			this.enablePreview = true;
-			String[] testFiles = new String[] {
-					"X.java",
-					"public class X {\n" +
-							"   @SuppressWarnings(\"preview\")\n" +
-							"	static int twice(int i) {\n" +
-							"		switch (i) {\n" +
-							"			default -> 3;\n" +
-							"		}\n" +
-							"		return 0;\n" +
-							"	}\n" +
-							"	public static void main(String[] args) {\n" +
-							"		System.out.print(twice(3));\n" +
-							"	}\n" +
-							"}\n",
-			};
+		Map<String, String> options = getCompilerOptions();
+		options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+		options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.WARNING);
+		String[] testFiles = new String[] {
+				"X.java",
+				"public class X {\n" +
+						"   @SuppressWarnings(\"preview\")\n" +
+						"	static int twice(int i) {\n" +
+						"		switch (i) {\n" +
+						"			default -> 3;\n" +
+						"		}\n" +
+						"		return 0;\n" +
+						"	}\n" +
+						"	public static void main(String[] args) {\n" +
+						"		System.out.print(twice(3));\n" +
+						"	}\n" +
+						"}\n",
+		};
 
-			String expectedProblemLog =
-					"0";
-			this.runConformTest(
-					testFiles,
-					expectedProblemLog,
-					options);
-		} finally {
-			this.enablePreview = old;
-		}
+		String expectedProblemLog =
+				"0";
+		this.runConformTest(
+				testFiles,
+				expectedProblemLog,
+				options,
+				new String[] {"--enable-preview"});
 	}
 	public void testBug531714_012() {
 		Map<String, String> options = getCompilerOptions();
@@ -529,4 +512,618 @@
 			false,
 			new String[] { "--enable-preview"});
 	}
+	/*
+	 * A simple multi constant case statement, compiled and run as expected
+	 */
+	public void testBug543240_1() {
+		Map<String, String> options = getCompilerOptions();
+		options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+		options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+		String[] testFiles = new String[] {
+				"X.java",
+				"public class X {\n" +
+						"public static void bar(Day day) {\n" + 
+						"		switch (day) {\n" + 
+						"		case SATURDAY, SUNDAY: \n" + 
+						"			System.out.println(Day.SUNDAY);\n" + 
+						"			break;\n" + 
+						"		case MONDAY : System.out.println(Day.MONDAY);\n" + 
+						"					break;\n" + 
+						"		}\n" + 
+						"	}" +
+						"	public static void main(String[] args) {\n" +
+						"		bar(Day.SATURDAY);\n" +
+						"	}\n" +
+						"}\n" +
+						"enum Day { SATURDAY, SUNDAY, MONDAY;}",
+		};
+
+		String expectedProblemLog =
+				"SUNDAY";
+		this.runConformTest(
+				testFiles,
+				expectedProblemLog,
+				options,
+				new String[] { "--enable-preview"});
+	}
+	/*
+	 * A simple multi constant case statement, compiler reports missing enum constants
+	 */
+	public void testBug543240_1a() {
+		Map<String, String> options = getCompilerOptions();
+		options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+		options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+		String[] testFiles = new String[] {
+				"X.java",
+				"public class X {\n" +
+						"	public static void main(String[] args) {\n" + 
+						"	}\n" + 
+						"public static void bar(Day day) {\n" + 
+						"		switch (day) {\n" + 
+						"		case SATURDAY, SUNDAY: \n" + 
+						"			System.out.println(Day.SUNDAY);\n" + 
+						"			break;\n" + 
+						"		case MONDAY : System.out.println(Day.MONDAY);\n" + 
+						"					break;\n" + 
+						"		}\n" + 
+						"	}" +
+						"}\n" +
+						"enum Day { SATURDAY, SUNDAY, MONDAY, TUESDAY;}",
+		};
+
+		String expectedProblemLog =
+						"----------\n" + 
+						"1. WARNING in X.java (at line 5)\n" + 
+						"	switch (day) {\n" + 
+						"	        ^^^\n" + 
+						"The enum constant TUESDAY needs a corresponding case label in this enum switch on Day\n" + 
+						"----------\n";
+		this.runNegativeTest(
+				testFiles,
+				expectedProblemLog,
+				null,
+				true,
+				new String[] { "--enable-preview"},
+				options);
+	}
+	/*
+	 * A simple multi constant case statement with duplicate enums
+	 */
+	public void testBug543240_2() {
+		Map<String, String> options = getCompilerOptions();
+		options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+		options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+		String[] testFiles = new String[] {
+				"X.java",
+				"public class X {\n" +
+						"public static void bar(Day day) {\n" + 
+						"		switch (day) {\n" + 
+						"		case SATURDAY, SUNDAY: \n" + 
+						"			System.out.println(Day.SUNDAY);\n" + 
+						"			break;\n" + 
+						"		case SUNDAY : System.out.println(Day.SUNDAY);\n" + 
+						"					break;\n" + 
+						"		}\n" + 
+						"	}" +
+						"	public static void main(String[] args) {\n" +
+						"		bar(Day.SATURDAY);\n" +
+						"	}\n" +
+						"}\n" +
+						"enum Day { SATURDAY, SUNDAY, MONDAY;}",
+		};
+
+		String expectedProblemLog =
+						"----------\n" + 
+						"1. ERROR in X.java (at line 7)\n" + 
+						"	case SUNDAY : System.out.println(Day.SUNDAY);\n" + 
+						"	^^^^^^^^^^^\n" + 
+						"Duplicate case\n" + 
+						"----------\n" + 
+						"2. ERROR in X.java (at line 7)\n" + 
+						"	case SUNDAY : System.out.println(Day.SUNDAY);\n" + 
+						"	^^^^^^^^^^^\n" + 
+						"Duplicate case\n" + 
+						"----------\n";
+		this.runNegativeTest(
+				testFiles,
+				expectedProblemLog,
+				null,
+				true,
+				options);
+	}
+	/*
+	 * A simple multi constant case statement with duplicate enums
+	 */
+	public void testBug543240_2a() {
+		Map<String, String> options = getCompilerOptions();
+		options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+		options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+		String[] testFiles = new String[] {
+				"X.java",
+				"public class X {\n" +
+						"public static void bar(Day day) {\n" + 
+						"		switch (day) {\n" + 
+						"		case SATURDAY, SUNDAY: \n" + 
+						"			System.out.println(Day.SUNDAY);\n" + 
+						"			break;\n" + 
+						"		case SUNDAY, SATURDAY : \n" +
+						"			System.out.println(Day.SUNDAY);\n" + 
+						"			break;\n" + 
+						"		}\n" + 
+						"	}" +
+						"}\n" +
+						"enum Day { SATURDAY, SUNDAY, MONDAY;}",
+		};
+
+		String expectedProblemLog =
+						"----------\n" + 
+						"1. WARNING in X.java (at line 3)\n" + 
+						"	switch (day) {\n" + 
+						"	        ^^^\n" + 
+						"The enum constant MONDAY needs a corresponding case label in this enum switch on Day\n" + 
+						"----------\n" + 
+						"2. ERROR in X.java (at line 7)\n" + 
+						"	case SUNDAY, SATURDAY : \n" + 
+						"	^^^^^^^^^^^^^^^^^^^^^\n" + 
+						"Duplicate case\n" + 
+						"----------\n" + 
+						"3. ERROR in X.java (at line 7)\n" + 
+						"	case SUNDAY, SATURDAY : \n" + 
+						"	^^^^^^^^^^^^^^^^^^^^^\n" + 
+						"Duplicate case\n" + 
+						"----------\n" + 
+						"4. ERROR in X.java (at line 7)\n" + 
+						"	case SUNDAY, SATURDAY : \n" + 
+						"	^^^^^^^^^^^^^^^^^^^^^\n" + 
+						"Duplicate case\n" + 
+						"----------\n";
+		this.runNegativeTest(
+				testFiles,
+				expectedProblemLog,
+				null,
+				true,
+				options);
+	}
+	/*
+	 * 
+	 */
+	public void testBug543240_3() {
+		Map<String, String> options = getCompilerOptions();
+		options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+		options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+		String[] testFiles = new String[] {
+				"X.java",
+				"public class X {\n" +
+						"public static void bar(Day day) {\n" + 
+						"		switch (day) {\n" + 
+						"		case SATURDAY, SUNDAY: \n" + 
+						"			System.out.println(Day.SUNDAY);\n" + 
+						"			break;\n" + 
+						"		case TUESDAY : System.out.println(Day.SUNDAY);\n" + 
+						"					break;\n" + 
+						"		}\n" + 
+						"	}" +
+						"	public static void main(String[] args) {\n" +
+						"		bar(Day.SATURDAY);\n" +
+						"	}\n" +
+						"}\n" +
+						"enum Day { SATURDAY, SUNDAY, MONDAY, TUESDAY;}",
+		};
+
+		String expectedProblemLog =
+				"----------\n" + 
+				"1. WARNING in X.java (at line 3)\n" + 
+				"	switch (day) {\n" + 
+				"	        ^^^\n" + 
+				"The enum constant MONDAY needs a corresponding case label in this enum switch on Day\n" + 
+				"----------\n";
+		this.runNegativeTest(
+				testFiles,
+				expectedProblemLog,
+				null,
+				true,
+				new String[] {"--enable-preview"},
+				options);
+	}
+	public void testBug543240_4() {
+		Map<String, String> options = getCompilerOptions();
+		options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+		options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+		String[] testFiles = new String[] {
+				"X.java",
+				"public class X {\n" +
+						"public static void bar(Day day) {\n" + 
+						"		switch (day) {\n" + 
+						"		case SATURDAY, SUNDAY: \n" + 
+						"			System.out.println(day);\n" + 
+						"			break;\n" + 
+						"		case MONDAY : System.out.println(0);\n" + 
+						"					break;\n" + 
+						"		}\n" + 
+						"	}" +
+						"	public static void main(String[] args) {\n" +
+						"		bar(Day.SATURDAY);\n" +
+						"		bar(Day.MONDAY);\n" +
+						"		bar(Day.SUNDAY);\n" +
+						"	}\n" +
+						"}\n" +
+						"enum Day { SATURDAY, SUNDAY, MONDAY;}",
+		};
+
+		String expectedProblemLog =
+				"SATURDAY\n" + 
+				"0\n" + 
+				"SUNDAY";
+		this.runConformTest(
+				testFiles,
+				expectedProblemLog,
+				options,
+				new String[] {"--enable-preview"});
+	}
+	/*
+	 * Simple switch case with string literals
+	 */
+	public void testBug543240_5() {
+		Map<String, String> options = getCompilerOptions();
+		options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+		options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+		String[] testFiles = new String[] {
+				"X.java",
+				"public class X {\n" + 
+						"	public static void main(String[] args) {\n" + 
+						"		bar(\"a\");\n" + 
+						"		bar(\"b\");\n" + 
+						"		bar(\"c\");\n" + 
+						"		bar(\"d\");\n" + 
+						"	}\n" + 
+						"	public static void bar(String s) {\n" + 
+						"		switch(s) {\n" + 
+						"		case \"a\":\n" + 
+						"		case \"b\":\n" + 
+						"			System.out.println(\"A/B\");\n" + 
+						"			break;\n" + 
+						"		case \"c\":\n" + 
+						"			System.out.println(\"C\");\n" + 
+						"			break;\n" + 
+						"		default:\n" + 
+						"			System.out.println(\"NA\");\n" + 
+						"		}\n" + 
+						"	}\n" + 
+						"}",
+		};
+		String expectedProblemLog =
+				"A/B\n" + 
+				"A/B\n" + 
+				"C\n" + 
+				"NA";
+		this.runConformTest(
+				testFiles,
+				expectedProblemLog,
+				options,
+				new String[] {"--enable-preview"});
+	}
+	public void testBug543240_6() {
+		Map<String, String> options = getCompilerOptions();
+		options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+		options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+		String[] testFiles = new String[] {
+				"X.java",
+				"public class X {\n" + 
+						"	public static void main(String[] args) {\n" + 
+						"		bar(\"a\");\n" + 
+						"		bar(\"b\");\n" + 
+						"		bar(\"c\");\n" + 
+						"		bar(\"d\");\n" + 
+						"	}\n" + 
+						"	public static void bar(String s) {\n" + 
+						"		switch(s) {\n" + 
+						"		case \"a\", \"b\":\n" + 
+						"			System.out.println(\"A/B\");\n" + 
+						"			break;\n" + 
+						"		case \"c\":\n" + 
+						"			System.out.println(\"C\");\n" + 
+						"			break;\n" + 
+						"		default:\n" + 
+						"			System.out.println(\"NA\");\n" + 
+						"		}\n" + 
+						"	}\n" + 
+						"}",
+		};
+		String expectedProblemLog =
+				"A/B\n" + 
+				"A/B\n" + 
+				"C\n" + 
+				"NA";
+		this.runConformTest(
+				testFiles,
+				expectedProblemLog,
+				options,
+				new String[] {"--enable-preview"});
+	}
+	/*
+	 * Switch with multi constant case statements with string literals
+	 * two string literals with same hashcode
+	 */
+	public void testBug543240_7() {
+		Map<String, String> options = getCompilerOptions();
+		options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+		options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+		String[] testFiles = new String[] {
+				"X.java",
+				"public class X {\n" + 
+						"	public static void main(String[] args) {\n" + 
+						"		bar(\"FB\");\n" + 
+						"		bar(\"Ea\");\n" + 
+						"		bar(\"c\");\n" + 
+						"		bar(\"D\");\n" + 
+						"	}\n" + 
+						"	public static void bar(String s) {\n" + 
+						"		switch(s) {\n" + 
+						"		case \"FB\", \"c\":\n" + 
+						"			System.out.println(\"A\");\n" + 
+						"			break;\n" + 
+						"		case \"Ea\":\n" + 
+						"			System.out.println(\"B\");\n" + 
+						"			break;\n" + 
+						"		default:\n" + 
+						"			System.out.println(\"NA\");\n" + 
+						"		}\n" + 
+						"	}\n" + 
+						"}",
+		};
+		String expectedProblemLog =
+				"A\n" + 
+				"B\n" + 
+				"A\n" + 
+				"NA";
+		this.runConformTest(
+				testFiles,
+				expectedProblemLog,
+				options,
+				new String[] {"--enable-preview"});
+	}
+	/*
+	 * Switch with multi constant case statements with integer constants
+	 */
+	public void testBug543240_8() {
+		Map<String, String> options = getCompilerOptions();
+		options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+		options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+		String[] testFiles = new String[] {
+				"X.java",
+				"public class X {\n" + 
+						"	public static void main(String[] args) {\n" + 
+						"		bar(1);\n" + 
+						"		bar(2);\n" + 
+						"		bar(3);\n" + 
+						"		bar(4);\n" + 
+						"		bar(5);\n" + 
+						"	}\n" + 
+						"	public static void bar(int i) {\n" + 
+						"		switch (i) {\n" + 
+						"		case 1, 3: \n" + 
+						"			System.out.println(\"Odd\");\n" + 
+						"			break;\n" + 
+						"		case 2, 4: \n" + 
+						"			System.out.println(\"Even\");\n" + 
+						"			break;\n" + 
+						"			default:\n" + 
+						"				System.out.println(\"Out of range\");\n" + 
+						"		}\n" + 
+						"	}\n" + 
+						"}",
+		};
+		String expectedProblemLog =
+				"Odd\n" + 
+				"Even\n" + 
+				"Odd\n" + 
+				"Even\n" + 
+				"Out of range";
+		this.runConformTest(
+				testFiles,
+				expectedProblemLog,
+				options,
+				new String[] {"--enable-preview"});
+	}
+	/*
+	 * Switch multi-constant with mixed constant types, reported
+	 */
+	public void testBug543240_9() {
+		Map<String, String> options = getCompilerOptions();
+		options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+		options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+		String[] testFiles = new String[] {
+				"X.java",
+				"public class X {\n" + 
+						"	public static void main(String[] args) {\n" + 
+						"	}\n" + 
+						"	public static void bar(int i) {\n" + 
+						"		switch (i) {\n" + 
+						"		case 1, 3: \n" + 
+						"			System.out.println(\"Odd\");\n" + 
+						"			break;\n" + 
+						"		case \"2\": \n" + 
+						"			System.out.println(\"Even\");\n" + 
+						"			break;\n" + 
+						"		default:\n" + 
+						"				System.out.println(\"Out of range\");\n" + 
+						"		}\n" + 
+						"	}\n" + 
+						"}",
+		};
+		String expectedProblemLog =
+				"----------\n" + 
+				"1. ERROR in X.java (at line 9)\n" + 
+				"	case \"2\": \n" + 
+				"	     ^^^\n" + 
+				"Type mismatch: cannot convert from String to int\n" + 
+				"----------\n";
+		this.runNegativeTest(
+				testFiles,
+				expectedProblemLog,
+				null,
+				true,
+				options);
+	}
+	/*
+	 * Switch multi-constant without break statement, reported
+	 */
+	public void testBug543240_10() {
+		Map<String, String> options = getCompilerOptions();
+		options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+		options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+		options.put(CompilerOptions.OPTION_ReportFallthroughCase, CompilerOptions.WARNING);
+		String[] testFiles = new String[] {
+				"X.java",
+				"public class X {\n" + 
+						"	public static void main(String[] args) {\n" + 
+						"	}\n" + 
+						"	public static void bar(int i) {\n" + 
+						"		switch (i) {\n" + 
+						"		case 1, 3: \n" + 
+						"			System.out.println(\"Odd\");\n" + 
+						"		case 2, 4: \n" + 
+						"			System.out.println(\"Even\");\n" + 
+						"			break;\n" +
+						"		default:\n" + 
+						"				System.out.println(\"Out of range\");\n" + 
+						"		}\n" + 
+						"	}\n" + 
+						"}",
+		};
+		String expectedProblemLog =
+				"----------\n" + 
+				"1. WARNING in X.java (at line 8)\n" + 
+				"	case 2, 4: \n" + 
+				"	^^^^^^^^^\n" + 
+				"Switch case may be entered by falling through previous case. If intended, add a new comment //$FALL-THROUGH$ on the line above\n" + 
+				"----------\n";
+		this.runNegativeTest(
+				testFiles,
+				expectedProblemLog,
+				null,
+				true,
+				new String[] { "--enable-preview"},
+				options);
+	}
+	/*
+	 * Switch multi-constant without break statement, reported
+	 */
+	public void testBug543240_11() {
+		Map<String, String> options = getCompilerOptions();
+		options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+		options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+		options.put(CompilerOptions.OPTION_ReportMissingDefaultCase, CompilerOptions.WARNING);
+		String[] testFiles = new String[] {
+				"X.java",
+				"public class X {\n" + 
+						"	public static void main(String[] args) {\n" + 
+						"	}\n" + 
+						"	public static void bar(int i) {\n" + 
+						"		switch (i) {\n" + 
+						"		case 1, 3: \n" + 
+						"			System.out.println(\"Odd\");\n" + 
+						"		case 2, 4: \n" + 
+						"			System.out.println(\"Even\");\n" + 
+						"		}\n" + 
+						"	}\n" + 
+						"}",
+		};
+		String expectedProblemLog =
+				"----------\n" + 
+				"1. WARNING in X.java (at line 5)\n" + 
+				"	switch (i) {\n" + 
+				"	        ^\n" + 
+				"The switch statement should have a default case\n" + 
+						"----------\n";
+		this.runNegativeTest(
+				testFiles,
+				expectedProblemLog,
+				null,
+				true,
+				new String[] { "--enable-preview"},
+				options);
+	}
+	/*
+	 * Switch multi-constant with duplicate int constants
+	 */
+	public void testBug543240_12() {
+		Map<String, String> options = getCompilerOptions();
+		options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+		options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+		String[] testFiles = new String[] {
+				"X.java",
+				"public class X {\n" + 
+						"	public static void main(String[] args) {\n" + 
+						"	}\n" + 
+						"	public static void bar(int i) {\n" + 
+						"		switch (i) {\n" + 
+						"		case 1, 3: \n" + 
+						"			System.out.println(\"Odd\");\n" + 
+						"		case 3, 4: \n" + 
+						"			System.out.println(\"Odd\");\n" + 
+						"		}\n" + 
+						"	}\n" + 
+						"}",
+		};
+		String expectedProblemLog =
+				"----------\n" + 
+				"1. ERROR in X.java (at line 8)\n" + 
+				"	case 3, 4: \n" + 
+				"	^^^^^^^^^\n" + 
+				"Duplicate case\n" + 
+				"----------\n" + 
+				"2. ERROR in X.java (at line 8)\n" + 
+				"	case 3, 4: \n" + 
+				"	^^^^^^^^^\n" + 
+				"Duplicate case\n" + 
+				"----------\n";
+		this.runNegativeTest(
+				testFiles,
+				expectedProblemLog,
+				null,
+				true,
+				options);
+	}
+	/*
+	 * Switch multi-constant with duplicate String literals
+	 */
+	public void testBug543240_13() {
+		Map<String, String> options = getCompilerOptions();
+		options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+		options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+		String[] testFiles = new String[] {
+				"X.java",
+				"public class X {\n" + 
+						"	public static void main(String[] args) {\n" + 
+						"	}\n" + 
+						"	public static void bar(String s) {\n" + 
+						"		switch (s) {\n" + 
+						"		case \"a\", \"b\": \n" + 
+						"			System.out.println(\"Odd\");\n" + 
+						"		case \"b\", \"c\": \n" + 
+						"			System.out.println(\"Odd\");\n" + 
+						"		}\n" + 
+						"	}\n" + 
+						"}",
+		};
+		String expectedProblemLog =
+				"----------\n" + 
+				"1. ERROR in X.java (at line 8)\n" + 
+				"	case \"b\", \"c\": \n" + 
+				"	^^^^^^^^^^^^^\n" + 
+				"Duplicate case\n" + 
+				"----------\n" + 
+				"2. ERROR in X.java (at line 8)\n" + 
+				"	case \"b\", \"c\": \n" + 
+				"	^^^^^^^^^^^^^\n" + 
+				"Duplicate case\n" + 
+				"----------\n";
+		this.runNegativeTest(
+				testFiles,
+				expectedProblemLog,
+				null,
+				true,
+				options);
+	}
 }
\ No newline at end of file
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 849f870..5c41e11 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
@@ -17,6 +17,9 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.ast;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.codegen.BranchLabel;
@@ -25,6 +28,7 @@
 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
 import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.impl.IntConstant;
+//import org.eclipse.jdt.internal.compiler.impl.IntConstant;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
@@ -49,13 +53,23 @@
 	BlockScope currentScope,
 	FlowContext flowContext,
 	FlowInfo flowInfo) {
-
-	if (this.constantExpression != null) {
-		if (this.constantExpression.constant == Constant.NotAConstant
-				&& !this.constantExpression.resolvedType.isEnum()) {
-			currentScope.problemReporter().caseExpressionMustBeConstant(this.constantExpression);
+	if (this.constantExpressions != null && this.constantExpressions.length > 1) {
+		for (Expression e : this.constantExpressions) {
+			if (e.constant == Constant.NotAConstant
+					&& !e.resolvedType.isEnum()) {
+				currentScope.problemReporter().caseExpressionMustBeConstant(e);
+			}
+			this.constantExpression.analyseCode(currentScope, flowContext, flowInfo);
 		}
-		this.constantExpression.analyseCode(currentScope, flowContext, flowInfo);
+		
+	} else {
+		if (this.constantExpression != null) {
+			if (this.constantExpression.constant == Constant.NotAConstant
+					&& !this.constantExpression.resolvedType.isEnum()) {
+				currentScope.problemReporter().caseExpressionMustBeConstant(this.constantExpression);
+			}
+			this.constantExpression.analyseCode(currentScope, flowContext, flowInfo);
+		}
 	}
 	return flowInfo;
 }
@@ -108,7 +122,7 @@
  * see org.eclipse.jdt.internal.compiler.ast.Statement#resolveCase(org.eclipse.jdt.internal.compiler.lookup.BlockScope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.ast.SwitchStatement)
  */
 @Override
-public Constant resolveCase(BlockScope scope, TypeBinding switchExpressionType, SwitchStatement switchStatement) {
+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
 
@@ -119,26 +133,55 @@
 
 		// on error the last default will be the selected one ...
 		switchStatement.defaultCase = this;
-		return Constant.NotAConstant;
+		return Constant.NotAConstantList;
 	}
 	// add into the collection of cases of the associated switch statement
 	switchStatement.cases[switchStatement.caseCount++] = this;
-	// tag constant name with enum type for privileged access to its members
 	if (switchExpressionType != null && switchExpressionType.isEnum() && (this.constantExpression instanceof SingleNameReference)) {
 		((SingleNameReference) this.constantExpression).setActualReceiverType((ReferenceBinding)switchExpressionType);
 	}
 	TypeBinding caseType = this.constantExpression.resolveType(scope);
-	if (caseType == null || switchExpressionType == null) return Constant.NotAConstant;
-	if (this.constantExpression.isConstantValueOfTypeAssignableToType(caseType, switchExpressionType)
+	if (caseType == null || switchExpressionType == null) return Constant.NotAConstantList;
+	// tag constant name with enum type for privileged access to its members
+
+	if (this.constantExpressions != null && this.constantExpressions.length > 1) {
+		List<Constant> cases = new ArrayList<>();
+		for (Expression e : this.constantExpressions) {
+			if (e != this.constantExpression) {
+				if (switchExpressionType.isEnum() && (this.constantExpression instanceof SingleNameReference)) {
+					((SingleNameReference) e).setActualReceiverType((ReferenceBinding)switchExpressionType);
+				}
+				e.resolveType(scope);
+			}
+			Constant con = resolveConstantExpression(scope, caseType, switchExpressionType, switchStatement, e);
+			if (con != Constant.NotAConstant) {
+				cases.add(con);
+			}
+		}
+		if (cases.size() > 0) {
+			return cases.toArray(new Constant[cases.size()]);
+		}
+	} else {
+		return new Constant[] { resolveConstantExpression(scope, caseType, switchExpressionType, switchStatement, this.constantExpression) };
+	}
+	return Constant.NotAConstantList;
+}
+public Constant resolveConstantExpression(BlockScope scope, 
+											TypeBinding caseType, 
+											TypeBinding switchExpressionType, 
+											SwitchStatement switchStatement, 
+											Expression expression) {
+	
+	if (expression.isConstantValueOfTypeAssignableToType(caseType, switchExpressionType)
 			|| caseType.isCompatibleWith(switchExpressionType)) {
 		if (caseType.isEnum()) {
-			if (((this.constantExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) != 0) {
-				scope.problemReporter().enumConstantsCannotBeSurroundedByParenthesis(this.constantExpression);
+			if (((expression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) != 0) {
+				scope.problemReporter().enumConstantsCannotBeSurroundedByParenthesis(expression);
 			}
 
-			if (this.constantExpression instanceof NameReference
-					&& (this.constantExpression.bits & ASTNode.RestrictiveFlagMASK) == Binding.FIELD) {
-				NameReference reference = (NameReference) this.constantExpression;
+			if (expression instanceof NameReference
+					&& (expression.bits & ASTNode.RestrictiveFlagMASK) == Binding.FIELD) {
+				NameReference reference = (NameReference) expression;
 				FieldBinding field = reference.fieldBinding();
 				if ((field.modifiers & ClassFileConstants.AccEnum) == 0) {
 					 scope.problemReporter().enumSwitchCannotTargetField(reference, field);
@@ -148,11 +191,11 @@
 				return IntConstant.fromValue(field.original().id + 1); // (ordinal value + 1) zero should not be returned see bug 141810
 			}
 		} else {
-			return this.constantExpression.constant;
+			return expression.constant;
 		}
-	} else if (isBoxingCompatible(caseType, switchExpressionType, this.constantExpression, scope)) {
+	} else if (isBoxingCompatible(caseType, switchExpressionType, expression, scope)) {
 		// constantExpression.computeConversion(scope, caseType, switchExpressionType); - do not report boxing/unboxing conversion
-		return this.constantExpression.constant;
+		return expression.constant;
 	}
 	scope.problemReporter().typeMismatchError(caseType, switchExpressionType, this.constantExpression, switchStatement.expression);
 	return Constant.NotAConstant;
@@ -161,7 +204,14 @@
 @Override
 public void traverse(ASTVisitor visitor, 	BlockScope blockScope) {
 	if (visitor.visit(this, blockScope)) {
-		if (this.constantExpression != null) this.constantExpression.traverse(visitor, blockScope);
+		if (this.constantExpressions != null && this.constantExpressions.length > 1) {
+			for (Expression e : this.constantExpressions) {
+				e.traverse(visitor, blockScope);
+			}
+		} else {
+			if (this.constantExpression != null) this.constantExpression.traverse(visitor, blockScope);
+		}
+		
 	}
 	visitor.endVisit(this, blockScope);
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
index bcafc9b..e7605c2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
@@ -447,10 +447,10 @@
  * Returns case constant associated to this statement (NotAConstant if none)
  * parameter statement has to be either a SwitchStatement or a SwitchExpression
  */
-public Constant resolveCase(BlockScope scope, TypeBinding testType, SwitchStatement switchStatement) {
+public Constant[] resolveCase(BlockScope scope, TypeBinding testType, SwitchStatement switchStatement) {
 	// statement within a switch that are not case are treated as normal statement....
 	resolve(scope);
-	return Constant.NotAConstant;
+	return new Constant[] {Constant.NotAConstant};
 }
 /**
  * Returns the resolved expression if any associated to this statement - used
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 c3e40ca..d21237a 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
@@ -59,6 +59,7 @@
 	public int blockStart;
 	public int caseCount;
 	int[] constants;
+	int[] constMapping;
 	String[] stringConstants;
 	public boolean switchLabeledRules = false; // true if case ->, false if case :
 
@@ -212,33 +213,60 @@
 					       "case " + this.hashCode + ":(" + this.string + ")\n"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$	       
 				}
 			}
-
+			/*
+			 * With multi constant case statements, the number of case statements (hence branch labels)
+			 * and number of constants (hence hashcode labels) could be different. For e.g:
+			  
+			  switch(s) {
+			  	case "FB", "c":
+			  		System.out.println("A/C");
+			 		break;
+			  	case "Ea":
+					System.out.println("B");
+					break;
+					
+				With the above code, we will have 
+				2 branch labels for FB and c
+				3 stringCases for FB, c and Ea
+				2 hashCodeCaseLabels one for FB, Ea and one for c
+				
+				Should produce something like this: 
+				lookupswitch  { // 2
+                      99: 32
+                    2236: 44
+                 default: 87
+				
+				"FB" and "Ea" producing the same hashcode values, but still belonging in different case statements.
+				First, produce the two branch labels pertaining to the case statements
+				And the three string cases and use the this.constMapping to get the correct branch label.
+			 */
 			final boolean hasCases = this.caseCount != 0;
-
-			StringSwitchCase [] stringCases = new StringSwitchCase[this.caseCount]; // may have to shrink later if multiple strings hash to same code.
+			int constSize = hasCases ? this.stringConstants.length : 0;
 			BranchLabel[] sourceCaseLabels = new BranchLabel[this.caseCount];
-			CaseLabel [] hashCodeCaseLabels = new CaseLabel[this.caseCount];
-			this.constants = new int[this.caseCount];  // hashCode() values.
 			for (int i = 0, max = this.caseCount; i < max; i++) {
 				this.cases[i].targetLabel = (sourceCaseLabels[i] = new BranchLabel(codeStream));  // A branch label, not a case label.
 				sourceCaseLabels[i].tagBits |= BranchLabel.USED;
-				stringCases[i] = new StringSwitchCase(this.stringConstants[i].hashCode(), this.stringConstants[i], sourceCaseLabels[i]);
+			}
+			StringSwitchCase [] stringCases = new StringSwitchCase[constSize]; // may have to shrink later if multiple strings hash to same code.
+			CaseLabel [] hashCodeCaseLabels = new CaseLabel[constSize];
+			this.constants = new int[constSize];  // hashCode() values.
+			for (int i = 0; i < constSize; i++) {
+				stringCases[i] = new StringSwitchCase(this.stringConstants[i].hashCode(), this.stringConstants[i], sourceCaseLabels[this.constMapping[i]]);
 				hashCodeCaseLabels[i] = new CaseLabel(codeStream);
 				hashCodeCaseLabels[i].tagBits |= BranchLabel.USED;
-				
 			}
 			Arrays.sort(stringCases);
 
 			int uniqHashCount = 0;
 			int lastHashCode = 0; 
-			for (int i = 0, length = this.caseCount; i < length; ++i) {
+			for (int i = 0, length = constSize; i < length; ++i) {
 				int hashCode = stringCases[i].hashCode;
 				if (i == 0 || hashCode != lastHashCode) {
 					lastHashCode = this.constants[uniqHashCount++] = hashCode;
 				}
 			}
 				
-			if (uniqHashCount != this.caseCount) { // multiple keys hashed to the same value.
+			if (uniqHashCount != constSize) { // multiple keys hashed to the same value.
 				System.arraycopy(this.constants, 0, this.constants = new int[uniqHashCount], 0, uniqHashCount);
 				System.arraycopy(hashCodeCaseLabels, 0, hashCodeCaseLabels = new CaseLabel[uniqHashCount], 0, uniqHashCount);
 			}
@@ -265,7 +293,7 @@
 			codeStream.invokeStringHashCode();
 			if (hasCases) {
 				codeStream.lookupswitch(defaultCaseLabel, this.constants, sortedIndexes, hashCodeCaseLabels);
-				for (int i = 0, j = 0, max = this.caseCount; i < max; i++) {
+				for (int i = 0, j = 0, max = constSize; i < max; i++) {
 					int hashCode = stringCases[i].hashCode;
 					if (i == 0 || hashCode != lastHashCode) {
 						lastHashCode = hashCode;
@@ -352,6 +380,7 @@
 
 			// prepare the labels and constants
 			this.breakLabel.initialize(codeStream);
+			int constantCount = this.constants == null ? 0 : this.constants.length;
 			CaseLabel[] caseLabels = new CaseLabel[this.caseCount];
 			for (int i = 0, max = this.caseCount; i < max; i++) {
 				this.cases[i].targetLabel = (caseLabels[i] = new CaseLabel(codeStream));
@@ -384,18 +413,18 @@
 			}
 			// generate the appropriate switch table/lookup bytecode
 			if (hasCases) {
-				int[] sortedIndexes = new int[this.caseCount];
+				int[] sortedIndexes = new int[constantCount];
 				// we sort the keys to be able to generate the code for tableswitch or lookupswitch
-				for (int i = 0; i < this.caseCount; i++) {
+				for (int i = 0; i < constantCount; i++) {
 					sortedIndexes[i] = i;
 				}
 				int[] localKeysCopy;
-				System.arraycopy(this.constants, 0, (localKeysCopy = new int[this.caseCount]), 0, this.caseCount);
-				CodeStream.sort(localKeysCopy, 0, this.caseCount - 1, sortedIndexes);
+				System.arraycopy(this.constants, 0, (localKeysCopy = new int[constantCount]), 0, constantCount);
+				CodeStream.sort(localKeysCopy, 0, constantCount - 1, sortedIndexes);
 
-				int max = localKeysCopy[this.caseCount - 1];
+				int max = localKeysCopy[constantCount - 1];
 				int min = localKeysCopy[0];
-				if ((long) (this.caseCount * 2.5) > ((long) max - (long) min)) {
+				if ((long) (constantCount * 2.5) > ((long) max - (long) min)) {
 
 					// work-around 1.3 VM bug, if max>0x7FFF0000, must use lookup bytecode
 					// see http://dev.eclipse.org/bugs/show_bug.cgi?id=21557
@@ -409,6 +438,7 @@
 							max,
 							this.constants,
 							sortedIndexes,
+							this.constMapping,
 							caseLabels);
 					}
 				} else {
@@ -424,7 +454,7 @@
 			if (this.statements != null) {
 				for (int i = 0, maxCases = this.statements.length; i < maxCases; i++) {
 					Statement statement = this.statements[i];
-					if ((caseIndex < this.caseCount) && (statement == this.cases[caseIndex])) { // statements[i] is a case
+					if ((caseIndex < constantCount) && (statement == this.cases[caseIndex])) { // statements[i] is a case
 						this.scope.enclosingCase = this.cases[caseIndex]; // record entering in a switch case block
 						if (this.preSwitchInitStateIndex != -1) {
 							codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preSwitchInitStateIndex);
@@ -535,32 +565,52 @@
 				this.cases = new CaseStatement[length = this.statements.length];
 				if (!isStringSwitch) {
 					this.constants = new int[length];
+					this.constMapping = new int[length];
 				} else {
 					this.stringConstants = new String[length];
+					this.constMapping = new int[length];
 				}
 				int counter = 0;
 				for (int i = 0; i < length; i++) {
-					Constant constant1;
+					Constant[] constantsList;
 					final Statement statement = this.statements[i];
-					if ((constant1 = statement.resolveCase(this.scope, expressionType, this)) != Constant.NotAConstant) {
-						if (!isStringSwitch) {
-							int key = constant1.intValue();
-							//----check for duplicate case statement------------
-							for (int j = 0; j < counter; j++) {
-								if (this.constants[j] == key) {
-									reportDuplicateCase((CaseStatement) statement, this.cases[j], length);
+					if (!(statement instanceof CaseStatement))  {
+						statement.resolve(this.scope);
+						continue;
+					}
+					if ((constantsList = statement.resolveCase(this.scope, expressionType, this)) != Constant.NotAConstantList) {
+						for (Constant con : constantsList) {
+							if (con == Constant.NotAConstant) 
+								continue;
+							if (!isStringSwitch) {
+								int key = con.intValue();
+								//----check for duplicate case statement------------
+								for (int j = 0; j < counter; j++) {
+									if (this.constants[j] == key) {
+										reportDuplicateCase((CaseStatement) statement, this.cases[j], length);
+									}
 								}
-							}
-							this.constants[counter++] = key;
-						} else {
-							String key = constant1.stringValue();
-							//----check for duplicate case statement------------
-							for (int j = 0; j < counter; j++) {
-								if (this.stringConstants[j].equals(key)) {
-									reportDuplicateCase((CaseStatement) statement, this.cases[j], length);
+								if (this.constants.length == counter) {
+									System.arraycopy(this.constants, 0, this.constants = new int[counter+1], 0, counter);
+									System.arraycopy(this.constMapping, 0, this.constMapping = new int[counter+1], 0, counter);
 								}
+								this.constants[counter] = key;
+								this.constMapping[counter++] = this.caseCount - 1;
+							} else {
+								String key = con.stringValue();
+								//----check for duplicate case statement------------
+								for (int j = 0; j < counter; j++) {
+									if (this.stringConstants[j].equals(key)) {
+										reportDuplicateCase((CaseStatement) statement, this.cases[j], length);
+									}
+								}
+								if (this.stringConstants.length == counter) {
+									System.arraycopy(this.stringConstants, 0, this.stringConstants = new String[counter+1], 0, counter);
+									System.arraycopy(this.constMapping, 0, this.constMapping = new int[counter+1], 0, counter);
+								}
+								this.stringConstants[counter] = key;
+								this.constMapping[counter++] = this.caseCount - 1;
 							}
-							this.stringConstants[counter++] = key;			
 						}
 					}
 				}
@@ -570,6 +620,7 @@
 					} else {
 						System.arraycopy(this.stringConstants, 0, this.stringConstants = new String[counter], 0, counter);
 					}
+					System.arraycopy(this.constMapping, 0, this.constMapping = new int[counter], 0, counter);
 				}
 			} else {
 				if ((this.bits & UndocumentedEmptyBlock) != 0) {
@@ -591,14 +642,14 @@
 			if (isEnumSwitch && compilerOptions.complianceLevel >= ClassFileConstants.JDK1_5) {
 				if (this.defaultCase == null || compilerOptions.reportMissingEnumCaseDespiteDefault) {
 					int constantCount = this.constants == null ? 0 : this.constants.length; // could be null if no case statement
-					if (constantCount == this.caseCount
-							&& this.caseCount != ((ReferenceBinding)expressionType).enumConstantCount()) {
+					if (constantCount >= this.caseCount
+							&& constantCount != ((ReferenceBinding)expressionType).enumConstantCount()) {
 						FieldBinding[] enumFields = ((ReferenceBinding)expressionType.erasure()).fields();
 						for (int i = 0, max = enumFields.length; i <max; i++) {
 							FieldBinding enumConstant = enumFields[i];
 							if ((enumConstant.modifiers & ClassFileConstants.AccEnum) == 0) continue;
 							findConstant : {
-								for (int j = 0; j < this.caseCount; j++) {
+								for (int j = 0; j < constantCount; j++) {
 									if ((enumConstant.id + 1) == this.constants[j]) // zero should not be returned see bug 141810
 										break findConstant;
 								}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
index cba674a..a3b5793 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
@@ -6895,7 +6895,7 @@
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_swap;
 }
 
-public void tableswitch(CaseLabel defaultLabel, int low, int high, int[] keys, int[] sortedIndexes, CaseLabel[] casesLabel) {
+public void tableswitch(CaseLabel defaultLabel, int low, int high, int[] keys, int[] sortedIndexes, int[] mapping, CaseLabel[] casesLabel) {
 	this.countLabels = 0;
 	this.stackDepth--;
 	int length = casesLabel.length;
@@ -6926,7 +6926,7 @@
 		int index;
 		int key = keys[index = sortedIndexes[j - low]];
 		if (key == i) {
-			casesLabel[index].branch();
+			casesLabel[mapping[index]].branch();
 			j++;
 			if (i == high) break; // if high is maxint, then avoids wrapping to minint.
 		} else {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java
index 3cda404..29a45a3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java
@@ -21,6 +21,7 @@
 public abstract class Constant implements TypeIds, OperatorIds {
 
 	public static final Constant NotAConstant = DoubleConstant.fromValue(Double.NaN);
+	public static final Constant[] NotAConstantList = new Constant[] {DoubleConstant.fromValue(Double.NaN)};
 	
 	public boolean booleanValue() {
 		throw new ShouldNotImplement(Messages.bind(Messages.constant_cannotCastedInto, new String[] { typeName(), "boolean" })); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
index 6201a19..37a77df 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
@@ -976,7 +976,7 @@
 # Switch-Expressions
 1600 = Incompatible switch results expressions {0}
 1601 = A switch expression should have a non-empty switch block
-1602 = A switch expression {0} should have at least one result expression
+1602 = A switch expression should have at least one result expression
 1603 = A switch labeled block in a switch expression should not complete normally
 1604 = The last statement of a switch block in a switch expression should not complete normally
 1605 = Trailing switch labels are not allowed in a switch expression.