Skip to content

Commit 7688c53

Browse files
[Enhanced Switch] Wrong error message: Cannot switch on a value of type Integer... at levels that don't support enhanced switch (eclipse-jdt#3380)
* Fixes eclipse-jdt#3379
1 parent fa7853f commit 7688c53

File tree

2 files changed

+118
-30
lines changed
  • org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast
  • org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression

2 files changed

+118
-30
lines changed

org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,16 +1029,12 @@ void gatherLabelExpression(LabelExpression labelExpression) {
10291029
public void resolve(BlockScope upperScope) {
10301030
try {
10311031
TypeBinding expressionType = this.expression.resolveType(upperScope);
1032+
if (expressionType != null && !expressionType.isValidBinding())
1033+
expressionType = null; // fault-tolerance: ignore further type mismatch from label expressions
10321034
CompilerOptions compilerOptions = upperScope.compilerOptions();
10331035
if (expressionType != null) {
10341036
this.expression.computeConversion(upperScope, expressionType, expressionType);
10351037
checkType: {
1036-
1037-
if (!expressionType.isValidBinding()) {
1038-
expressionType = null; // fault-tolerance: ignore type mismatch from constants from hereon
1039-
break checkType;
1040-
}
1041-
10421038
if (expressionType.isBaseType()) {
10431039
if (JavaFeature.PRIMITIVES_IN_PATTERNS.isSupported(compilerOptions))
10441040
this.isPrimitiveSwitch = true;
@@ -1047,28 +1043,25 @@ public void resolve(BlockScope upperScope) {
10471043
if (expressionType.isCompatibleWith(TypeBinding.INT))
10481044
break checkType;
10491045
}
1050-
10511046
if (expressionType.id == TypeIds.T_JavaLangString || expressionType.isEnum() || upperScope.isBoxingCompatibleWith(expressionType, TypeBinding.INT))
10521047
break checkType;
1053-
1054-
if (!JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(compilerOptions) || (expressionType.isBaseType() && expressionType.id != T_null && expressionType.id != T_void)) {
1048+
if (JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(compilerOptions) && (!expressionType.isBaseType() || expressionType.id == T_null || expressionType.id == T_void)) {
1049+
this.isNonTraditional = true;
1050+
} else {
10551051
if (!this.isPrimitiveSwitch) { // when isPrimitiveSwitch is set it is approved above
10561052
upperScope.problemReporter().incorrectSwitchType(this.expression, expressionType);
10571053
expressionType = null; // fault-tolerance: ignore type mismatch from constants from hereon
10581054
}
1059-
} else {
1060-
this.isNonTraditional = true;
10611055
}
10621056
}
10631057
}
10641058

10651059
this.scope = new BlockScope(upperScope);
10661060
if (expressionType != null)
1067-
reserveSecretVariablesSlots();
1061+
reserveSecretVariablesSlot();
10681062
else
10691063
this.switchBits |= InvalidSelector;
10701064

1071-
10721065
if (this.statements != null) {
10731066
preprocess(); // make a pass over the switch block and allocate vectors.
10741067
LocalVariableBinding[] patternVariables = NO_VARIABLES;
@@ -1096,18 +1089,10 @@ public void resolve(BlockScope upperScope) {
10961089

10971090
if (expressionType != null) {
10981091
if (!expressionType.isBaseType() && upperScope.isBoxingCompatibleWith(expressionType, TypeBinding.INT)) {
1099-
if (this.containsPatterns || this.containsNull) {
1100-
if (!JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(compilerOptions) || (expressionType.isBaseType() && expressionType.id != T_null && expressionType.id != T_void)) {
1101-
if (!this.isPrimitiveSwitch) { // when isPrimitiveSwitch is set it is approved above
1102-
upperScope.problemReporter().incorrectSwitchType(this.expression, expressionType);
1103-
this.switchBits |= InvalidSelector;
1104-
expressionType = null; // fault-tolerance: ignore type mismatch from constants from hereon
1105-
}
1106-
}
1107-
} else
1092+
if (!this.containsPatterns && !this.containsNull)
11081093
this.expression.computeConversion(upperScope, TypeBinding.INT, expressionType);
11091094
}
1110-
releaseUnusedSecretVariables();
1095+
releaseUnusedSecretVariable();
11111096
complainIfNotExhaustiveSwitch(upperScope, expressionType, compilerOptions);
11121097
}
11131098

@@ -1148,12 +1133,10 @@ private void complainIfNotExhaustiveSwitch(BlockScope upperScope, TypeBinding se
11481133
}
11491134

11501135
if (this.defaultCase == null) {
1151-
if (this instanceof SwitchExpression // complained about elsewhere, don't also bark here
1152-
|| compilerOptions.getSeverity(CompilerOptions.MissingDefaultCase) == ProblemSeverities.Ignore) {
1136+
if (this instanceof SwitchExpression || compilerOptions.getSeverity(CompilerOptions.MissingDefaultCase) == ProblemSeverities.Ignore) // complained about elsewhere, don't also bark here
11531137
upperScope.methodScope().hasMissingSwitchDefault = true;
1154-
} else {
1138+
else
11551139
upperScope.problemReporter().missingDefaultCase(this, true, selectorType);
1156-
}
11571140
}
11581141
return;
11591142
}
@@ -1311,21 +1294,21 @@ private boolean needPatternDispatchCopy() {
13111294
return !(eType.isPrimitiveOrBoxedPrimitiveType() || eType.isEnum() || eType.id == TypeIds.T_JavaLangString); // classic selectors
13121295
}
13131296

1314-
private void reserveSecretVariablesSlots() { // may be released later if unused.
1297+
private void reserveSecretVariablesSlot() { // may be released later if unused.
13151298
this.selector = new LocalVariableBinding(SecretSelectorVariableName, this.scope.getJavaLangObject(), ClassFileConstants.AccDefault, false);
13161299
this.scope.addLocalVariable(this.selector);
13171300
this.selector.setConstant(Constant.NotAConstant);
13181301
}
13191302

1320-
private void releaseUnusedSecretVariables() {
1303+
private void releaseUnusedSecretVariable() {
13211304
if (this.selector != null) {
13221305
if (this.expression.resolvedType.id == T_JavaLangString && !this.isNonTraditional) {
13231306
this.selector.useFlag = LocalVariableBinding.USED;
13241307
this.selector.type = this.scope.getJavaLangString();
13251308
} else if (needPatternDispatchCopy()) {
13261309
this.selector.useFlag = LocalVariableBinding.USED;
13271310
this.selector.type = this.expression.resolvedType;
1328-
}
1311+
} // else gets released by virtue of not being tagged USED.
13291312
}
13301313
}
13311314
protected void reportMissingEnumConstantCase(BlockScope upperScope, FieldBinding enumConstant) {

org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchTest.java

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3624,6 +3624,111 @@ String unreachableCode(String arg) {
36243624
"----------\n");
36253625
}
36263626

3627+
// https://github.com/eclipse-jdt/eclipse.jdt.core/issues/3379
3628+
// [Enhanced Switch] Wrong error message: Cannot switch on a value of type Integer... at levels that don't support enhanced switch
3629+
public void testIssue3379() throws Exception {
3630+
if (this.complianceLevel < ClassFileConstants.JDK14)
3631+
return; // uses switch rules.
3632+
String [] sources = new String[] {
3633+
"X.java",
3634+
"""
3635+
public class X {
3636+
public static void main(String[] args) {
3637+
Integer i = 42;
3638+
switch (i) {
3639+
case null -> System.out.println("Null");
3640+
default -> System.out.println("Default: " + i);
3641+
}
3642+
}
3643+
}
3644+
""",
3645+
};
3646+
3647+
if (this.complianceLevel < ClassFileConstants.JDK21) {
3648+
this.runNegativeTest(sources,
3649+
"----------\n" +
3650+
"1. ERROR in X.java (at line 5)\n" +
3651+
" case null -> System.out.println(\"Null\");\n" +
3652+
" ^^^^\n" +
3653+
"The Java feature 'Pattern Matching in Switch' is only available with source level 21 and above\n" +
3654+
"----------\n");
3655+
} else {
3656+
this.runConformTest(sources, "Default: 42");
3657+
}
3658+
}
3659+
3660+
// https://github.com/eclipse-jdt/eclipse.jdt.core/issues/3379
3661+
// [Enhanced Switch] Wrong error message: Cannot switch on a value of type Integer... at levels that don't support enhanced switch
3662+
public void testIssue3379_2() throws Exception {
3663+
if (this.complianceLevel < ClassFileConstants.JDK14)
3664+
return; // uses switch rules.
3665+
String [] sources = new String[] {
3666+
"X.java",
3667+
"""
3668+
public class X {
3669+
public static void main(String[] args) {
3670+
Long i = 42l;
3671+
switch (i) {
3672+
case null -> System.out.println("Null");
3673+
default -> System.out.println("Default: " + i);
3674+
}
3675+
}
3676+
}
3677+
""",
3678+
};
3679+
3680+
if (this.complianceLevel < ClassFileConstants.JDK21) {
3681+
this.runNegativeTest(sources,
3682+
"----------\n" +
3683+
"1. ERROR in X.java (at line 4)\n" +
3684+
" switch (i) {\n" +
3685+
" ^\n" +
3686+
"Cannot switch on a value of type Long. Only convertible int values, strings or enum variables are permitted\n" +
3687+
"----------\n" +
3688+
"2. ERROR in X.java (at line 5)\n" +
3689+
" case null -> System.out.println(\"Null\");\n" +
3690+
" ^^^^\n" +
3691+
"The Java feature 'Pattern Matching in Switch' is only available with source level 21 and above\n" +
3692+
"----------\n");
3693+
} else {
3694+
this.runConformTest(sources, "Default: 42");
3695+
}
3696+
}
3697+
3698+
// https://github.com/eclipse-jdt/eclipse.jdt.core/issues/3379
3699+
// [Enhanced Switch] Wrong error message: Cannot switch on a value of type Integer... at levels that don't support enhanced switch
3700+
public void testIssue3379_3() throws Exception {
3701+
if (this.complianceLevel < ClassFileConstants.JDK14)
3702+
return; // uses switch rules.
3703+
3704+
String [] sources = new String[] {
3705+
"X.java",
3706+
"""
3707+
public class X {
3708+
public static void main(String[] args) {
3709+
Short i = 42;
3710+
switch (i) {
3711+
case null -> System.out.println("Null");
3712+
default -> System.out.println("Default: " + i);
3713+
}
3714+
}
3715+
}
3716+
""",
3717+
};
3718+
3719+
if (this.complianceLevel < ClassFileConstants.JDK21) {
3720+
this.runNegativeTest(sources,
3721+
"----------\n" +
3722+
"1. ERROR in X.java (at line 5)\n" +
3723+
" case null -> System.out.println(\"Null\");\n" +
3724+
" ^^^^\n" +
3725+
"The Java feature 'Pattern Matching in Switch' is only available with source level 21 and above\n" +
3726+
"----------\n");
3727+
} else {
3728+
this.runConformTest(sources, "Default: 42");
3729+
}
3730+
}
3731+
36273732
public static Class testClass() {
36283733
return SwitchTest.class;
36293734
}

0 commit comments

Comments
 (0)