Merge "Bug 574039 - [17] Merge master to BETA_JAVA17 periodically" into BETA_JAVA17
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
index 6712460..fabf79e 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
@@ -1297,13 +1297,12 @@
expectedProblemAttributes.put("SealedSuperTypeDisallowed", new ProblemAttributes(CategorizedProblem.CAT_PREVIEW_RELATED));
expectedProblemAttributes.put("SafeVarargsOnSyntheticRecordAccessor", new ProblemAttributes(true));
expectedProblemAttributes.put("DiscouragedValueBasedTypeSynchronization", new ProblemAttributes(true));
- expectedProblemAttributes.put("SwitchPatternConstantCaseLabelIncompatible", new ProblemAttributes(true));
expectedProblemAttributes.put("SwitchPatternConstantWithPatternIncompatible", new ProblemAttributes(true));
expectedProblemAttributes.put("IllegalFallthroughToPattern", new ProblemAttributes(true));
expectedProblemAttributes.put("SwitchPatternOnlyOnePatternCaseLabelAllowed", new ProblemAttributes(true));
expectedProblemAttributes.put("SwitchPatternBothPatternAndDefaultCaseLabelsNotAllowed", new ProblemAttributes(true));
expectedProblemAttributes.put("SwitchPatternBothNullAndNonTypePatternNotAllowed", new ProblemAttributes(true));
- expectedProblemAttributes.put("PatternDominates", new ProblemAttributes(true));
+ expectedProblemAttributes.put("PatternDominated", new ProblemAttributes(true));
expectedProblemAttributes.put("IllegalTotalPatternWithDefault", new ProblemAttributes(true));
expectedProblemAttributes.put("EnhancedSwitchMissingDefaultCase", new ProblemAttributes(true));
@@ -2373,13 +2372,12 @@
expectedProblemAttributes.put("LocalReferencedInGuardMustBeEffectivelyFinal", SKIP);
expectedProblemAttributes.put("SafeVarargsOnSyntheticRecordAccessor", SKIP);
expectedProblemAttributes.put("DiscouragedValueBasedTypeSynchronization", SKIP);
- expectedProblemAttributes.put("SwitchPatternConstantCaseLabelIncompatible", SKIP);
expectedProblemAttributes.put("SwitchPatternConstantWithPatternIncompatible", SKIP);
expectedProblemAttributes.put("IllegalFallthroughToPattern", SKIP);
expectedProblemAttributes.put("SwitchPatternOnlyOnePatternCaseLabelAllowed", SKIP);
expectedProblemAttributes.put("SwitchPatternBothPatternAndDefaultCaseLabelsNotAllowed", SKIP);
expectedProblemAttributes.put("SwitchPatternBothNullAndNonTypePatternNotAllowed", SKIP);
- expectedProblemAttributes.put("PatternDominates", SKIP);
+ expectedProblemAttributes.put("PatternDominated", SKIP);
expectedProblemAttributes.put("IllegalTotalPatternWithDefault", SKIP);
expectedProblemAttributes.put("EnhancedSwitchMissingDefaultCase", SKIP);
Map constantNamesIndex = new HashMap();
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 90593e1..cd96e4c 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
@@ -212,12 +212,12 @@
"1. ERROR in X.java (at line 4)\n" +
" case Integer t, String s, X x : System.out.println(\"Integer, String or X\");\n" +
" ^^^^^^^^\n" +
- "A switch label may not have more than one pattern case label element.\n" +
+ "A switch label may not have more than one pattern case label element\n" +
"----------\n" +
"2. ERROR in X.java (at line 4)\n" +
" case Integer t, String s, X x : System.out.println(\"Integer, String or X\");\n" +
" ^^^\n" +
- "A switch label may not have more than one pattern case label element.\n" +
+ "A switch label may not have more than one pattern case label element\n" +
"----------\n" +
"3. ERROR in X.java (at line 10)\n" +
" Zork();\n" +
@@ -247,7 +247,7 @@
"1. ERROR in X.java (at line 4)\n" +
" case Integer t, String s && s.length > 0, X x && x.hashCode() > 10 : System.out.println(\"Integer, String or X\");\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^\n" +
- "A switch label may not have more than one pattern case label element.\n" +
+ "A switch label may not have more than one pattern case label element\n" +
"----------\n" +
"2. ERROR in X.java (at line 4)\n" +
" case Integer t, String s && s.length > 0, X x && x.hashCode() > 10 : System.out.println(\"Integer, String or X\");\n" +
@@ -257,7 +257,7 @@
"3. ERROR in X.java (at line 4)\n" +
" case Integer t, String s && s.length > 0, X x && x.hashCode() > 10 : System.out.println(\"Integer, String or X\");\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^\n" +
- "A switch label may not have more than one pattern case label element.\n" +
+ "A switch label may not have more than one pattern case label element\n" +
"----------\n" +
"4. ERROR in X.java (at line 10)\n" +
" Zork();\n" +
@@ -396,7 +396,7 @@
"2. ERROR in X.java (at line 4)\n" +
" case String s, default : System.out.println(\"Error should be flagged for String and default\");\n" +
" ^\n" +
- "A switch label may not have both a pattern case label element and a default case label element.\n" +
+ "A switch label may not have both a pattern case label element and a default case label element\n" +
"----------\n" +
"3. ERROR in X.java (at line 5)\n" +
" default : System.out.println(\"Object\");\n" +
@@ -460,7 +460,7 @@
"1. ERROR in X.java (at line 4)\n" +
" case 1: System.out.println(\"Integer\"); break;\n" +
" ^\n" +
- "The constant case label element is not compatible with switch expression type Object\n" +
+ "Type mismatch: cannot convert from int to Object\n" +
"----------\n" +
"2. ERROR in X.java (at line 10)\n" +
" Zork();\n" +
@@ -502,7 +502,7 @@
"1. ERROR in X.java (at line 7)\n" +
" case String s && s.length()>1: \n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
- "Illegal fall-through to a pattern case label \n" +
+ "Illegal fall-through to a pattern case label\n" +
"----------\n");
}
public void testBug573939_01() {
@@ -528,7 +528,7 @@
"1. ERROR in X.java (at line 5)\n" +
" case String s1: System.out.println(\"String \");\n" +
" ^^^^^^^^^^^^^^\n" +
- "Illegal fall-through to a pattern case label \n" +
+ "Illegal fall-through to a pattern case label\n" +
"----------\n" +
"2. ERROR in X.java (at line 11)\n" +
" Zork();\n" +
@@ -1606,7 +1606,7 @@
"1. ERROR in X.java (at line 4)\n" +
" switch (o) {\n" +
" ^\n" +
- "An enhanced switch statement should be exhaustive; a default label expected \n" +
+ "An enhanced switch statement should be exhaustive; a default label expected\n" +
"----------\n" +
"2. ERROR in X.java (at line 5)\n" +
" case null -> System.out.println(\"null\");\n" +
@@ -1616,12 +1616,12 @@
"3. ERROR in X.java (at line 11)\n" +
" case \"F\" :\n" +
" ^^^\n" +
- "The constant case label element is not compatible with switch expression type Object\n" +
+ "Type mismatch: cannot convert from String to Object\n" +
"----------\n" +
"4. ERROR in X.java (at line 13)\n" +
" case 2 :\n" +
" ^\n" +
- "The constant case label element is not compatible with switch expression type Object\n" +
+ "Type mismatch: cannot convert from int to Object\n" +
"----------\n");
}
public void testBug574559_001() {
@@ -1640,11 +1640,6 @@
"----------\n" +
"1. ERROR in X.java (at line 5)\n" +
" case 1, Integer i -> System.out.println(o);\n" +
- " ^\n" +
- "The constant case label element is not compatible with switch expression type Integer\n" +
- "----------\n" +
- "2. ERROR in X.java (at line 5)\n" +
- " case 1, Integer i -> System.out.println(o);\n" +
" ^^^^^^^^^\n" +
"Constant case label elements and pattern case label elements cannot be present in a switch label\n" +
"----------\n");
@@ -1690,12 +1685,12 @@
"1. ERROR in X.java (at line 6)\n" +
" case Float f :\n" +
" ^^^^^^^^^^^^\n" +
- "Illegal fall-through to a pattern case label \n" +
+ "Illegal fall-through to a pattern case label\n" +
"----------\n" +
"2. ERROR in X.java (at line 8)\n" +
" case Object o : break;\n" +
" ^^^^^^^^^^^^^\n" +
- "Illegal fall-through to a pattern case label \n" +
+ "Illegal fall-through to a pattern case label\n" +
"----------\n");
}
// Test that fall-through to a pattern is not allowed (label statement group has zero statement)
@@ -1719,7 +1714,7 @@
"1. ERROR in X.java (at line 5)\n" +
" case Float f :\n" +
" ^^^^^^^^^^^^\n" +
- "Illegal fall-through to a pattern case label \n" +
+ "Illegal fall-through to a pattern case label\n" +
"----------\n");
}
// Test that fall-through to a pattern is not allowed (label statement group has zero statement)
@@ -1742,7 +1737,7 @@
"1. ERROR in X.java (at line 5)\n" +
" case Float f :\n" +
" ^^^^^^^^^^^^\n" +
- "Illegal fall-through to a pattern case label \n" +
+ "Illegal fall-through to a pattern case label\n" +
"----------\n");
}
// Test that falling through from a pattern to a default is allowed
@@ -1875,7 +1870,7 @@
"3. ERROR in X.java (at line 7)\n" +
" case var i, var j, var k -> System.out.println(0);\n" +
" ^^^^^\n" +
- "A switch label may not have more than one pattern case label element.\n" +
+ "A switch label may not have more than one pattern case label element\n" +
"----------\n" +
"4. ERROR in X.java (at line 7)\n" +
" case var i, var j, var k -> System.out.println(0);\n" +
@@ -1885,7 +1880,7 @@
"5. ERROR in X.java (at line 7)\n" +
" case var i, var j, var k -> System.out.println(0);\n" +
" ^^^^^\n" +
- "A switch label may not have more than one pattern case label element.\n" +
+ "A switch label may not have more than one pattern case label element\n" +
"----------\n");
}
public void testBug574564_003() {
@@ -1951,7 +1946,7 @@
"4. ERROR in X.java (at line 7)\n" +
" case var i, 10, var k -> System.out.println(0);\n" +
" ^^^^^\n" +
- "A switch label may not have more than one pattern case label element.\n" +
+ "A switch label may not have more than one pattern case label element\n" +
"----------\n");
}
public void testBug574564_005() {
@@ -1973,15 +1968,10 @@
"----------\n" +
"1. ERROR in X.java (at line 7)\n" +
" case 10, null, var k -> System.out.println(0);\n" +
- " ^^\n" +
- "The constant case label element is not compatible with switch expression type Integer\n" +
- "----------\n" +
- "2. ERROR in X.java (at line 7)\n" +
- " case 10, null, var k -> System.out.println(0);\n" +
" ^^^\n" +
"\'var\' is not allowed here\n" +
"----------\n" +
- "3. ERROR in X.java (at line 7)\n" +
+ "2. ERROR in X.java (at line 7)\n" +
" case 10, null, var k -> System.out.println(0);\n" +
" ^^^^^\n" +
"Constant case label elements and pattern case label elements cannot be present in a switch label\n" +
@@ -2012,7 +2002,7 @@
"2. ERROR in X.java (at line 7)\n" +
" case default, var k -> System.out.println(0);\n" +
" ^^^^^\n" +
- "A switch label may not have both a pattern case label element and a default case label element.\n" +
+ "A switch label may not have both a pattern case label element and a default case label element\n" +
"----------\n" +
"3. ERROR in X.java (at line 8)\n" +
" default -> System.out.println(o);\n" +
@@ -2050,7 +2040,7 @@
"3. ERROR in X.java (at line 7)\n" +
" case default, default, var k -> System.out.println(0);\n" +
" ^^^^^\n" +
- "A switch label may not have both a pattern case label element and a default case label element.\n" +
+ "A switch label may not have both a pattern case label element and a default case label element\n" +
"----------\n" +
"4. ERROR in X.java (at line 8)\n" +
" default -> System.out.println(o);\n" +
@@ -2077,18 +2067,13 @@
"----------\n" +
"1. ERROR in X.java (at line 7)\n" +
" case default, 1, var k -> System.out.println(0);\n" +
- " ^\n" +
- "The constant case label element is not compatible with switch expression type Integer\n" +
- "----------\n" +
- "2. ERROR in X.java (at line 7)\n" +
- " case default, 1, var k -> System.out.println(0);\n" +
" ^^^\n" +
"\'var\' is not allowed here\n" +
"----------\n" +
"3. ERROR in X.java (at line 7)\n" +
" case default, 1, var k -> System.out.println(0);\n" +
" ^^^^^\n" +
- "A switch label may not have both a pattern case label element and a default case label element.\n" +
+ "A switch label may not have both a pattern case label element and a default case label element\n" +
"----------\n" +
"4. ERROR in X.java (at line 7)\n" +
" case default, 1, var k -> System.out.println(0);\n" +
@@ -2117,12 +2102,12 @@
"1. ERROR in X.java (at line 4)\n" +
" case String s, default, Integer i -> System.out.println(0);\n" +
" ^\n" +
- "A switch label may not have both a pattern case label element and a default case label element.\n" +
+ "A switch label may not have both a pattern case label element and a default case label element\n" +
"----------\n" +
"2. ERROR in X.java (at line 4)\n" +
" case String s, default, Integer i -> System.out.println(0);\n" +
" ^^^^^^^^^\n" +
- "A switch label may not have more than one pattern case label element.\n" +
+ "A switch label may not have more than one pattern case label element\n" +
"----------\n");
}
public void testBug574564_010() {
@@ -2431,10 +2416,10 @@
"}",
},
"----------\n" +
- "1. ERROR in X.java (at line 4)\n" +
- " case CharSequence cs ->\n" +
- " ^^^^^^^^^^^^^^^\n" +
- "This pattern dominates one or more of the following patterns\n" +
+ "1. ERROR in X.java (at line 6)\n" +
+ " case String s && s.length() > 0 -> \n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "This case label is dominated by one of the preceding case label\n" +
"----------\n");
}
public void testBug573921_2() {
@@ -2457,10 +2442,10 @@
"}",
},
"----------\n" +
- "1. ERROR in X.java (at line 4)\n" +
- " case CharSequence cs:\n" +
- " ^^^^^^^^^^^^^^^\n" +
- "This pattern dominates one or more of the following patterns\n" +
+ "1. ERROR in X.java (at line 7)\n" +
+ " case String s:\n" +
+ " ^^^^^^^^\n" +
+ "This case label is dominated by one of the preceding case label\n" +
"----------\n");
}
public void testBug573921_3() {
@@ -2580,17 +2565,17 @@
"1. ERROR in X.java (at line 5)\n" +
" switch(o) {\n" +
" ^\n" +
- "An enhanced switch statement should be exhaustive; a default label expected \n" +
+ "An enhanced switch statement should be exhaustive; a default label expected\n" +
"----------\n" +
- "2. ERROR in X.java (at line 6)\n" +
- " case List cs:\n" +
- " ^^^^^^^\n" +
- "This pattern dominates one or more of the following patterns\n" +
+ "2. ERROR in X.java (at line 9)\n" +
+ " case List<String> s: \n" +
+ " ^^^^^^^^^^^^^^\n" +
+ "Type Object cannot be safely cast to List<String>\n" +
"----------\n" +
"3. ERROR in X.java (at line 9)\n" +
" case List<String> s: \n" +
" ^^^^^^^^^^^^^^\n" +
- "Type Object cannot be safely cast to List<String>\n" +
+ "This case label is dominated by one of the preceding case label\n" +
"----------\n");
}
public void testBug573921_8() {
@@ -3203,7 +3188,7 @@
"1. ERROR in X.java (at line 3)\n" +
" switch (o) {\n" +
" ^\n" +
- "An enhanced switch statement should be exhaustive; a default label expected \n" +
+ "An enhanced switch statement should be exhaustive; a default label expected\n" +
"----------\n");
}
public void testBug575052_003() {
@@ -3225,7 +3210,7 @@
"1. ERROR in X.java (at line 3)\n" +
" switch (o) {\n" +
" ^\n" +
- "An enhanced switch statement should be exhaustive; a default label expected \n" +
+ "An enhanced switch statement should be exhaustive; a default label expected\n" +
"----------\n");
}
public void testBug575052_004() {
@@ -3291,4 +3276,160 @@
"A switch expression should have a default case\n" +
"----------\n");
}
-}
\ No newline at end of file
+ // From 14.11.1: A switch label that has a pattern case label element p that is
+ // total for the type of the selector expression of the enclosing
+ // switch statement or switch expression dominates a switch label that has
+ // a null case label element.
+ public void testBug575047_01() {
+ runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n"+
+ " static int foo(Integer i) {\n"+
+ " return switch (i) {\n"+
+ " case Integer i1 -> 0;\n"+
+ " case null -> 2;\n"+
+ " };\n"+
+ " }\n"+
+ "}",
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 5)\n" +
+ " case null -> 2;\n" +
+ " ^^^^\n" +
+ "This case label is dominated by one of the preceding case label\n" +
+ "----------\n");
+ }
+ // A switch label that has a pattern case label element p dominates another
+ // switch label that has a constant case label element c if either of the
+ // following is true:
+ // * the type of c is a primitive type and its wrapper class (5.1.7) is a subtype of the erasure of the type of p.
+ // * the type of c is a reference type and is a subtype of the erasure of the type of p.
+ public void testBug575047_02() {
+ runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n"+
+ " static int foo(Integer i) {\n"+
+ " return switch (i) {\n"+
+ " case Integer i1 -> i1;\n"+
+ " case 0 -> 0;\n"+
+ " };\n"+
+ " }\n"+
+ "}",
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 5)\n" +
+ " case 0 -> 0;\n" +
+ " ^\n" +
+ "This case label is dominated by one of the preceding case label\n" +
+ "----------\n");
+ }
+ public void testBug575047_03() {
+ runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n"+
+ " static void foo(Color c) {\n"+
+ " switch (c) {\n" +
+ " case Color c1 : \n" +
+ " break;\n" +
+ " case Blue :\n" +
+ " break;\n" +
+ " }\n"+
+ " }\n"+
+ "enum Color { Blue, Red; }\n" +
+ "}",
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 6)\n" +
+ " case Blue :\n" +
+ " ^^^^\n" +
+ "This case label is dominated by one of the preceding case label\n" +
+ "----------\n");
+ }
+ public void testBug575047_04() {
+ runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n"+
+ " static int foo(Integer i) {\n"+
+ " return switch (i) {\n"+
+ " case null -> 2;\n"+
+ " case Integer i1 -> 0;\n"+
+ " };\n"+
+ " }\n"+
+ " public static void main(String[] args) {\n"+
+ " System.out.println(foo(null));\n"+
+ " }\n"+
+ "}",
+ },
+ "2");
+ }
+ public void testBug575047_05() {
+ runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n"+
+ " static void foo(float c) {\n"+
+ " switch (c) {\n" +
+ " case 0 : \n" +
+ " break;\n" +
+ " default :\n" +
+ " }\n"+
+ " }\n"+
+ "}",
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 4)\n" +
+ " case 0 : \n" +
+ " ^\n" +
+ "Type mismatch: cannot convert from int to float\n" +
+ "----------\n");
+ }
+ public void testBug575047_06() {
+ runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n"+
+ " static int foo(String o) {\n"+
+ " return switch (o) {\n" +
+ " case String s && s.length() > 0 -> 3;\n" +
+ " case String s1 -> 1;\n" +
+ " case String s -> -1;\n"+
+ " };\n"+
+ " }\n"+
+ "}",
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 5)\n" +
+ " case String s1 -> 1;\n" +
+ " ^^^^^^^^^^^^^^\n" +
+ "Duplicate case\n" +
+ "----------\n" +
+ "2. ERROR in X.java (at line 6)\n" +
+ " case String s -> -1;\n" +
+ " ^^^^^^^^^^^^^\n" +
+ "Duplicate case\n" +
+ "----------\n");
+ }
+ // Output expected as '3', but prints '0'
+ public void _testBug575047_07() {
+ runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n"+
+ " static int foo(Integer i) {\n"+
+ " return switch (i) {\n"+
+ " case 0 -> 0;\n"+
+ " case Integer i1 -> i1;\n"+
+ " };\n"+
+ " }\n"+
+ " public static void main(String[] args) {\n"+
+ " System.out.println(foo(3));\n"+
+ " }\n"+
+ "}",
+ },
+ "3");
+ }
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
index e44d2f2..a45895c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
@@ -2473,32 +2473,29 @@
int LocalReferencedInGuardMustBeEffectivelyFinal = PreviewRelated + 1900;
/** @since 3.27 BETA_JAVA17
* @noreference preview feature error */
- int SwitchPatternConstantCaseLabelIncompatible = PreviewRelated + 1901;
- /** @since 3.27 BETA_JAVA17
- * @noreference preview feature error */
- int SwitchPatternConstantWithPatternIncompatible = PreviewRelated + 1902;
+ int SwitchPatternConstantWithPatternIncompatible = PreviewRelated + 1901;
/**
* @since 3.27 BETA_JAVA17
* @noreference preview feature error
*/
- int IllegalFallthroughToPattern = PreviewRelated + 1903;
+ int IllegalFallthroughToPattern = PreviewRelated + 1902;
/** @since 3.27 BETA_JAVA17
* @noreference preview feature error */
- int SwitchPatternOnlyOnePatternCaseLabelAllowed = PreviewRelated + 1904;
+ int SwitchPatternOnlyOnePatternCaseLabelAllowed = PreviewRelated + 1903;
/** @since 3.27 BETA_JAVA17
* @noreference preview feature error */
- int SwitchPatternBothPatternAndDefaultCaseLabelsNotAllowed = PreviewRelated + 1905;
+ int SwitchPatternBothPatternAndDefaultCaseLabelsNotAllowed = PreviewRelated + 1904;
/** @since 3.27 BETA_JAVA17
* @noreference preview feature error */
- int SwitchPatternBothNullAndNonTypePatternNotAllowed = PreviewRelated + 1906;
+ int SwitchPatternBothNullAndNonTypePatternNotAllowed = PreviewRelated + 1905;
/** @since 3.27 BETA_JAVA17
* @noreference preview feature error */
- int PatternDominates = PreviewRelated + 1907;
+ int PatternDominated = PreviewRelated + 1906;
/** @since 3.27 BETA_JAVA17
* @noreference preview feature error */
- int IllegalTotalPatternWithDefault = PreviewRelated + 1908;
+ int IllegalTotalPatternWithDefault = PreviewRelated + 1907;
/** @since 3.27 BETA_JAVA17
* @noreference preview feature error */
- int EnhancedSwitchMissingDefaultCase = PreviewRelated + 1909;
+ int EnhancedSwitchMissingDefaultCase = PreviewRelated + 1908;
}
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 e3b93f1..fd3fb88 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
@@ -157,19 +157,35 @@
public void resolve(BlockScope scope) {
// no-op : should use resolveCase(...) instead.
}
-
+static class ResolvedCase {
+ static final ResolvedCase[] UnresolvedCase = new ResolvedCase[0];
+ public Constant c;
+ public Expression e;
+ ResolvedCase(Constant c, Expression e) {
+ this.c = c;
+ this.e = e;
+ }
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("case "); //$NON-NLS-1$
+ builder.append(this.e);
+ builder.append(" [CONSTANT="); //$NON-NLS-1$
+ builder.append(this.c);
+ builder.append("]"); //$NON-NLS-1$
+ return builder.toString();
+ }
+}
/**
* Returns the constant intValue or ordinal for enum constants. If constant is NotAConstant, then answers Float.MIN_VALUE
- * 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 ResolvedCase[] resolveCase(BlockScope scope, TypeBinding switchExpressionType, SwitchStatement switchStatement) {
if (containsPatternVariable()) {
return resolveWithPatternVariablesInScope(this.patternVarsWhenTrue, scope, switchExpressionType, switchStatement);
}
return resolveCasePrivate(scope, switchExpressionType, switchStatement);
}
-public Constant[] resolveWithPatternVariablesInScope(LocalVariableBinding[] patternVariablesInScope,
+public ResolvedCase[] resolveWithPatternVariablesInScope(LocalVariableBinding[] patternVariablesInScope,
BlockScope scope,
TypeBinding switchExpressionType,
SwitchStatement switchStatement) {
@@ -177,11 +193,11 @@
for (LocalVariableBinding binding : patternVariablesInScope) {
binding.modifiers &= ~ExtraCompilerModifiers.AccPatternVariable;
}
- Constant[] constants = resolveCasePrivate(scope, switchExpressionType, switchStatement);
+ ResolvedCase[] cases = resolveCasePrivate(scope, switchExpressionType, switchStatement);
for (LocalVariableBinding binding : patternVariablesInScope) {
binding.modifiers |= ExtraCompilerModifiers.AccPatternVariable;
}
- return constants;
+ return cases;
} else {
return resolveCasePrivate(scope, switchExpressionType, switchStatement);
}
@@ -217,8 +233,11 @@
scope.problemReporter().switchPatternBothNullAndNonTypePatternNotAllowed(e);
}
} else if (e instanceof NullLiteral) {
- if (switchStatement.nullCase == null)
+ if (switchStatement.nullCase == null) {
switchStatement.nullCase = this;
+ if ((switchStatement.switchBits & SwitchStatement.TotalPattern) != 0)
+ scope.problemReporter().patternDominatedByAnother(this.constantExpressions[0]);
+ }
if (nullCaseLabelCount++ > 0) {
// TODO: Decide whether we need to have a more fine-grain element level error flagging for null specifically
@@ -244,16 +263,16 @@
}
return ret;
}
-private Constant[] resolveCasePrivate(BlockScope scope, TypeBinding switchExpressionType, SwitchStatement switchStatement) {
+private ResolvedCase[] resolveCasePrivate(BlockScope scope, TypeBinding switchExpressionType, SwitchStatement switchStatement) {
// switchExpressionType maybe null in error case
scope.enclosingCase = this; // record entering in a switch case block
if (this.constantExpressions == null) {
flagDuplicateDefault(scope, switchStatement);
- return Constant.NotAConstantList;
+ return ResolvedCase.UnresolvedCase;
}
Expression constExpr = getFirstValidExpression(scope, switchStatement);
if (constExpr == null) {
- return Constant.NotAConstantList;
+ return ResolvedCase.UnresolvedCase;
}
// add into the collection of cases of the associated switch statement
@@ -263,10 +282,10 @@
}
TypeBinding caseType = constExpr.resolveType(scope);
- if (caseType == null || switchExpressionType == null) return Constant.NotAConstantList;
+ if (caseType == null || switchExpressionType == null) return ResolvedCase.UnresolvedCase;
// tag constant name with enum type for privileged access to its members
- List<Constant> cases = new ArrayList<>();
+ List<ResolvedCase> cases = new ArrayList<>();
for (Expression e : this.constantExpressions) {
if (e != constExpr) {
if (switchExpressionType.isEnum() && (e instanceof SingleNameReference)) {
@@ -278,15 +297,15 @@
}
Constant con = resolveConstantExpression(scope, caseType, switchExpressionType, switchStatement, e);
if (con != Constant.NotAConstant) {
- cases.add(con);
+ cases.add(new ResolvedCase(con, e));
}
}
this.resolveWithPatternVariablesInScope(this.getPatternVariablesWhenTrue(), scope);
if (cases.size() > 0) {
- return cases.toArray(new Constant[cases.size()]);
+ return cases.toArray(new ResolvedCase[cases.size()]);
}
- return Constant.NotAConstantList;
+ return ResolvedCase.UnresolvedCase;
}
private void flagDuplicateDefault(BlockScope scope, SwitchStatement switchStatement) {
@@ -317,7 +336,7 @@
}
public Constant resolveConstantExpression(BlockScope scope,
TypeBinding caseType,
- TypeBinding switchExpressionType,
+ TypeBinding switchType,
SwitchStatement switchStatement,
Expression expression) {
@@ -327,11 +346,11 @@
if (testForMixedLabelKind(CASE_PATTERN)) {
scope.problemReporter().switchPatternConstantWithPatternIncompatible(expression);
}
- return resolveConstantExpression(scope, caseType, switchExpressionType,
+ return resolveConstantExpression(scope, caseType, switchType,
switchStatement,(Pattern) expression);
} else if (expression instanceof NullLiteral) {
- if (!(switchExpressionType instanceof ReferenceBinding)) {
- scope.problemReporter().typeMismatchError(TypeBinding.NULL, switchExpressionType, expression, null);
+ if (!(switchType instanceof ReferenceBinding)) {
+ scope.problemReporter().typeMismatchError(TypeBinding.NULL, switchType, expression, null);
}
switchStatement.switchBits |= SwitchStatement.NullCase;
return IntConstant.fromValue(-1);
@@ -343,18 +362,18 @@
return Constant.NotAConstant;
}
if (switchStatement.isNonTraditional) {
- if (!expression.isConstantValueOfTypeAssignableToType(caseType, switchExpressionType)) {
- scope.problemReporter().switchPatternConstantCaseLabelIncompatible(expression, switchExpressionType);
+ if (switchType.isBaseType() && !expression.isConstantValueOfTypeAssignableToType(caseType, switchType)) {
+ scope.problemReporter().typeMismatchError(caseType, switchType, expression, null);
return Constant.NotAConstant;
}
}
}
}
boolean boxing = !patternSwitchAllowed ||
- switchStatement.isAllowedType(switchExpressionType);
+ switchStatement.isAllowedType(switchType);
- if (expression.isConstantValueOfTypeAssignableToType(caseType, switchExpressionType)
- ||(caseType.isCompatibleWith(switchExpressionType)
+ if (expression.isConstantValueOfTypeAssignableToType(caseType, switchType)
+ ||(caseType.isCompatibleWith(switchType)
&& !(expression instanceof StringLiteral))) {
if (caseType.isEnum()) {
if (((expression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) != 0) {
@@ -375,11 +394,11 @@
} else {
return expression.constant;
}
- } else if (boxing && isBoxingCompatible(caseType, switchExpressionType, expression, scope)) {
+ } else if (boxing && isBoxingCompatible(caseType, switchType, expression, scope)) {
// constantExpression.computeConversion(scope, caseType, switchExpressionType); - do not report boxing/unboxing conversion
return expression.constant;
}
- scope.problemReporter().typeMismatchError(caseType, switchExpressionType, expression, switchStatement.expression);
+ scope.problemReporter().typeMismatchError(caseType, switchType, expression, switchStatement.expression);
return Constant.NotAConstant;
}
@@ -402,7 +421,7 @@
LocalDeclaration patternVar = e.getPatternVariableIntroduced();
if (patternVar != null && !patternVar.type.isTypeNameVar(scope)) {
// The following code is copied from InstanceOfExpression#resolve()
- // But there are several differences to warranty a copy
+ // But there are enough differences to warrant a copy
if (!pb.isReifiable()) {
if (expressionType != TypeBinding.NULL) {
boolean isLegal = e.checkCastTypesCompatibility(scope, pb, expressionType, e, false);
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 d001590..efc9f68 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
@@ -50,7 +50,6 @@
import org.eclipse.jdt.internal.compiler.codegen.*;
import org.eclipse.jdt.internal.compiler.flow.*;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
-import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.lookup.*;
public abstract class Statement extends ASTNode {
@@ -545,15 +544,6 @@
}
}
/**
- * 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) {
- // statement within a switch that are not case are treated as normal statement....
- resolve(scope);
- return new Constant[] {Constant.NotAConstant};
-}
-/**
* Returns the resolved expression if any associated to this statement - used
* parameter statement has to be either a SwitchStatement or a SwitchExpression
*/
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 0234f48..9a4311f 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
@@ -27,8 +27,10 @@
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
+import java.util.function.IntPredicate;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
+import org.eclipse.jdt.internal.compiler.ast.CaseStatement.ResolvedCase;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.codegen.BranchLabel;
import org.eclipse.jdt.internal.compiler.codegen.CaseLabel;
@@ -760,9 +762,8 @@
boolean isStringSwitch = false;
TypeBinding expressionType = this.expression.resolveType(upperScope);
CompilerOptions compilerOptions = upperScope.compilerOptions();
+ boolean isEnhanced = checkAndSetEnhanced(upperScope, expressionType);
if (expressionType != null) {
- checkAndSetEnhanced(upperScope, expressionType);
- this.expression.computeConversion(upperScope, expressionType, expressionType);
checkType: {
if (!expressionType.isValidBinding()) {
expressionType = null; // fault-tolerance: ignore type mismatch from constants from hereon
@@ -824,10 +825,11 @@
}
int counter = 0;
int caseCounter = 0;
+ Pattern[] patterns = new Pattern[this.nConstants];
+ int[] caseIndex = new int[this.nConstants];
LocalVariableBinding[] patternVariables = null;
for (int i = 0; i < length; i++) {
- Constant[] constantsList;
- int[] caseIndex = new int[this.nConstants];
+ ResolvedCase[] constantsList;
final Statement statement = this.statements[i];
// Let's first collect the pattern variables if any
// so that we can resolve all statements (including case statements)
@@ -843,31 +845,57 @@
statement.resolveWithPatternVariablesInScope(patternVariables, this.scope);
continue;
}
- if ((constantsList = statement.resolveCase(this.scope, expressionType, this)) != Constant.NotAConstantList) {
- for (Constant con : constantsList) {
+ CaseStatement caseStmt = (CaseStatement) statement;
+ constantsList = caseStmt.resolveCase(this.scope, expressionType, this);
+ if (constantsList != ResolvedCase.UnresolvedCase) {
+ for (ResolvedCase c : constantsList) {
+ Constant con = c.c;
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[caseIndex[j]], length);
- }
- }
- this.constants[counter] = key;
+ if (isStringSwitch) {
+ this.stringConstants[counter] = con.stringValue();
} 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[caseIndex[j]], length);
+ this.constants[counter] = con.intValue();
+ }
+ for (int j = 0; j < counter; j++) {
+ IntPredicate check = (idx) -> {
+ if (con.typeID() == TypeIds.T_JavaLangString) {
+ return this.stringConstants[idx].equals(con.stringValue());
+ } else {
+ return this.constants[idx] == con.intValue();
+ }
+ };
+ Pattern p1 = patterns[j];
+ TypeBinding type = c.e.resolvedType;
+ if (p1 != null) {
+ if (c.e instanceof Pattern) {
+ if (check.test(j)) {
+ reportDuplicateCase(caseStmt, this.cases[caseIndex[j]], length);
+ } else if (p1.dominates((Pattern) c.e)) {
+ this.scope.problemReporter().patternDominatedByAnother(c.e);
+ }
+ } else {
+ if (type.id != TypeIds.T_null) {
+ if (type.isBaseType()) {
+ type = this.scope.environment().computeBoxingType(type);
+ }
+ if (p1.isTotalForType(type))
+ this.scope.problemReporter().patternDominatedByAnother(c.e);
+ }
+ }
+ } else {
+ if (check.test(j)) {
+ reportDuplicateCase(caseStmt, this.cases[caseIndex[j]], length);
}
}
- this.stringConstants[counter] = key;
}
+
this.constMapping[counter] = counter;
caseIndex[counter] = caseCounter;
+ // Only the pattern expressions count for dominance check
+ if (c.e instanceof Pattern) {
+ patterns[counter] = (Pattern) c.e;
+ }
counter++;
}
}
@@ -887,17 +915,6 @@
}
}
reportMixingCaseTypes();
- if (this.caseLabelElements != null) {
- for(int i = this.caseLabelElements.size() - 1; i > 0; i--) {
- Pattern p1 = this.caseLabelElements.get(i);
- for (int j = 0; j < i; j++) {
- Pattern p2 = this.caseLabelElements.get(j);
- if (p2.dominates(p1)) {
- this.scope.problemReporter().patternDominatingAnother(p2);
- }
- }
- }
- }
// check default case for all kinds of switch:
checkAndFlagDefaultSealed(upperScope, compilerOptions);
@@ -906,7 +923,7 @@
upperScope.methodScope().hasMissingSwitchDefault = true;
} else {
if (!isExhaustive()) {
- if (this.isEnhanced())
+ if (isEnhanced)
upperScope.problemReporter().enhancedSwitchMissingDefaultCase(this.expression);
else
upperScope.problemReporter().missingDefaultCase(this, isEnumSwitch, expressionType);
@@ -949,7 +966,7 @@
public boolean isEnhanced() {
return (this.switchBits & SwitchStatement.Enhanced) != 0;
}
- private void checkAndSetEnhanced(BlockScope upperScope, TypeBinding expressionType) {
+ private boolean checkAndSetEnhanced(BlockScope upperScope, TypeBinding expressionType) {
if (JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(upperScope.compilerOptions())
&& expressionType != null && !(this instanceof SwitchExpression )) {
@@ -959,17 +976,19 @@
case TypeIds.T_byte:
case TypeIds.T_short:
case TypeIds.T_int:
- case TypeIds.T_JavaLangCharacter :
- case TypeIds.T_JavaLangByte :
- case TypeIds.T_JavaLangShort :
- case TypeIds.T_JavaLangInteger :
- case TypeIds.T_JavaLangString :
+ case TypeIds.T_JavaLangCharacter:
+ case TypeIds.T_JavaLangByte:
+ case TypeIds.T_JavaLangShort:
+ case TypeIds.T_JavaLangInteger:
+ case TypeIds.T_JavaLangString:
acceptableType = false;
}
if (acceptableType || this.containsPatterns || this.containsNull) {
this.switchBits |= SwitchStatement.Enhanced;
+ return true;
}
}
+ return false;
}
private void checkAndFlagDefaultSealed(BlockScope skope, CompilerOptions compilerOptions) {
if (this.defaultCase != null) { // mark covered as a side effect (since covers is intro in 406)
@@ -1023,6 +1042,8 @@
this.switchBits |= LabeledRules;
return;
}
+ if (this.cases[0] == null)
+ return;
boolean isExpr = this.cases[0].isExpr;
if (isExpr) this.switchBits |= LabeledRules;
for (int i = 1, l = this.caseCount; i < l; ++i) {
@@ -1035,7 +1056,9 @@
this.scope.problemReporter().switchExpressionMixedCase(this.defaultCase);
}
}
- private void reportDuplicateCase(final CaseStatement duplicate, final CaseStatement original, int length) {
+ private void reportDuplicateCase(final CaseStatement duplicate,
+ final CaseStatement original,
+ int length) {
if (this.duplicateCaseStatements == null) {
this.scope.problemReporter().duplicateCase(original);
if (duplicate != original)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
index 04005d7..c9de768 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
@@ -2036,7 +2036,7 @@
location.sourceStart,
location.sourceEnd);
}
-public void duplicateCase(CaseStatement caseStatement) {
+public void duplicateCase(Statement caseStatement) {
this.handle(
IProblem.DuplicateCase,
NoArgument,
@@ -12203,15 +12203,6 @@
NoArgument, NoArgument,
sourceStart, sourceEnd);
}
-public void switchPatternConstantCaseLabelIncompatible(Expression element, TypeBinding selectorType) {
- String name = new String(selectorType.shortReadableName());
- this.handle(
- IProblem.SwitchPatternConstantCaseLabelIncompatible,
- new String[] {name},
- new String[] {name},
- element.sourceStart,
- element.sourceEnd);
-}
public void switchPatternConstantWithPatternIncompatible(Expression element) {
this.handle(
IProblem.SwitchPatternConstantWithPatternIncompatible,
@@ -12252,9 +12243,9 @@
element.sourceStart,
element.sourceEnd);
}
-public void patternDominatingAnother(Expression element) {
+public void patternDominatedByAnother(Expression element) {
this.handle(
- IProblem.PatternDominates,
+ IProblem.PatternDominated,
NoArgument,
NoArgument,
element.sourceStart,
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 2f33e84..0777d0f 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
@@ -1117,15 +1117,14 @@
# Switch Patterns - Java 17 - JEP 406 - preview
1900 = Local variable {0} referenced from a guard must be final or effectively final
-1901 = The constant case label element is not compatible with switch expression type {0}
-1902 = Constant case label elements and pattern case label elements cannot be present in a switch label
-1903 = Illegal fall-through to a pattern case label
-1904 = A switch label may not have more than one pattern case label element.
-1905 = A switch label may not have both a pattern case label element and a default case label element.
-1906 = A null case label and patterns can co-exist only if the pattern is a type pattern
-1907 = This pattern dominates one or more of the following patterns
-1908 = Switch case cannot have both a total pattern and default label
-1909 = An enhanced switch statement should be exhaustive; a default label expected
+1901 = Constant case label elements and pattern case label elements cannot be present in a switch label
+1902 = Illegal fall-through to a pattern case label
+1903 = A switch label may not have more than one pattern case label element
+1904 = A switch label may not have both a pattern case label element and a default case label element
+1905 = A null case label and patterns can co-exist only if the pattern is a type pattern
+1906 = This case label is dominated by one of the preceding case label
+1907 = Switch case cannot have both a total pattern and default label
+1908 = An enhanced switch statement should be exhaustive; a default label expected
### ELABORATIONS
## Access restrictions