Skip to content

Commit

Permalink
[Enhanced Switch] Wrong error message: Cannot switch on a value of ty…
Browse files Browse the repository at this point in the history
…pe Integer... at levels that don't support enhanced switch (#3380)

* Fixes #3379
  • Loading branch information
srikanth-sankaran authored Dec 3, 2024
1 parent 074bbd3 commit eaff460
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1029,16 +1029,12 @@ void gatherLabelExpression(LabelExpression labelExpression) {
public void resolve(BlockScope upperScope) {
try {
TypeBinding expressionType = this.expression.resolveType(upperScope);
if (expressionType != null && !expressionType.isValidBinding())
expressionType = null; // fault-tolerance: ignore further type mismatch from label expressions
CompilerOptions compilerOptions = upperScope.compilerOptions();
if (expressionType != null) {
this.expression.computeConversion(upperScope, expressionType, expressionType);
checkType: {

if (!expressionType.isValidBinding()) {
expressionType = null; // fault-tolerance: ignore type mismatch from constants from hereon
break checkType;
}

if (expressionType.isBaseType()) {
if (JavaFeature.PRIMITIVES_IN_PATTERNS.isSupported(compilerOptions))
this.isPrimitiveSwitch = true;
Expand All @@ -1047,28 +1043,25 @@ public void resolve(BlockScope upperScope) {
if (expressionType.isCompatibleWith(TypeBinding.INT))
break checkType;
}

if (expressionType.id == TypeIds.T_JavaLangString || expressionType.isEnum() || upperScope.isBoxingCompatibleWith(expressionType, TypeBinding.INT))
break checkType;

if (!JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(compilerOptions) || (expressionType.isBaseType() && expressionType.id != T_null && expressionType.id != T_void)) {
if (JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(compilerOptions) && (!expressionType.isBaseType() || expressionType.id == T_null || expressionType.id == T_void)) {
this.isNonTraditional = true;
} else {
if (!this.isPrimitiveSwitch) { // when isPrimitiveSwitch is set it is approved above
upperScope.problemReporter().incorrectSwitchType(this.expression, expressionType);
expressionType = null; // fault-tolerance: ignore type mismatch from constants from hereon
}
} else {
this.isNonTraditional = true;
}
}
}

this.scope = new BlockScope(upperScope);
if (expressionType != null)
reserveSecretVariablesSlots();
reserveSecretVariablesSlot();
else
this.switchBits |= InvalidSelector;


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

if (expressionType != null) {
if (!expressionType.isBaseType() && upperScope.isBoxingCompatibleWith(expressionType, TypeBinding.INT)) {
if (this.containsPatterns || this.containsNull) {
if (!JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(compilerOptions) || (expressionType.isBaseType() && expressionType.id != T_null && expressionType.id != T_void)) {
if (!this.isPrimitiveSwitch) { // when isPrimitiveSwitch is set it is approved above
upperScope.problemReporter().incorrectSwitchType(this.expression, expressionType);
this.switchBits |= InvalidSelector;
expressionType = null; // fault-tolerance: ignore type mismatch from constants from hereon
}
}
} else
if (!this.containsPatterns && !this.containsNull)
this.expression.computeConversion(upperScope, TypeBinding.INT, expressionType);
}
releaseUnusedSecretVariables();
releaseUnusedSecretVariable();
complainIfNotExhaustiveSwitch(upperScope, expressionType, compilerOptions);
}

Expand Down Expand Up @@ -1148,12 +1133,10 @@ private void complainIfNotExhaustiveSwitch(BlockScope upperScope, TypeBinding se
}

if (this.defaultCase == null) {
if (this instanceof SwitchExpression // complained about elsewhere, don't also bark here
|| compilerOptions.getSeverity(CompilerOptions.MissingDefaultCase) == ProblemSeverities.Ignore) {
if (this instanceof SwitchExpression || compilerOptions.getSeverity(CompilerOptions.MissingDefaultCase) == ProblemSeverities.Ignore) // complained about elsewhere, don't also bark here
upperScope.methodScope().hasMissingSwitchDefault = true;
} else {
else
upperScope.problemReporter().missingDefaultCase(this, true, selectorType);
}
}
return;
}
Expand Down Expand Up @@ -1311,21 +1294,21 @@ private boolean needPatternDispatchCopy() {
return !(eType.isPrimitiveOrBoxedPrimitiveType() || eType.isEnum() || eType.id == TypeIds.T_JavaLangString); // classic selectors
}

private void reserveSecretVariablesSlots() { // may be released later if unused.
private void reserveSecretVariablesSlot() { // may be released later if unused.
this.selector = new LocalVariableBinding(SecretSelectorVariableName, this.scope.getJavaLangObject(), ClassFileConstants.AccDefault, false);
this.scope.addLocalVariable(this.selector);
this.selector.setConstant(Constant.NotAConstant);
}

private void releaseUnusedSecretVariables() {
private void releaseUnusedSecretVariable() {
if (this.selector != null) {
if (this.expression.resolvedType.id == T_JavaLangString && !this.isNonTraditional) {
this.selector.useFlag = LocalVariableBinding.USED;
this.selector.type = this.scope.getJavaLangString();
} else if (needPatternDispatchCopy()) {
this.selector.useFlag = LocalVariableBinding.USED;
this.selector.type = this.expression.resolvedType;
}
} // else gets released by virtue of not being tagged USED.
}
}
protected void reportMissingEnumConstantCase(BlockScope upperScope, FieldBinding enumConstant) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3624,6 +3624,111 @@ String unreachableCode(String arg) {
"----------\n");
}

// https://github.com/eclipse-jdt/eclipse.jdt.core/issues/3379
// [Enhanced Switch] Wrong error message: Cannot switch on a value of type Integer... at levels that don't support enhanced switch
public void testIssue3379() throws Exception {
if (this.complianceLevel < ClassFileConstants.JDK14)
return; // uses switch rules.
String [] sources = new String[] {
"X.java",
"""
public class X {
public static void main(String[] args) {
Integer i = 42;
switch (i) {
case null -> System.out.println("Null");
default -> System.out.println("Default: " + i);
}
}
}
""",
};

if (this.complianceLevel < ClassFileConstants.JDK21) {
this.runNegativeTest(sources,
"----------\n" +
"1. ERROR in X.java (at line 5)\n" +
" case null -> System.out.println(\"Null\");\n" +
" ^^^^\n" +
"The Java feature 'Pattern Matching in Switch' is only available with source level 21 and above\n" +
"----------\n");
} else {
this.runConformTest(sources, "Default: 42");
}
}

// https://github.com/eclipse-jdt/eclipse.jdt.core/issues/3379
// [Enhanced Switch] Wrong error message: Cannot switch on a value of type Integer... at levels that don't support enhanced switch
public void testIssue3379_2() throws Exception {
if (this.complianceLevel < ClassFileConstants.JDK14)
return; // uses switch rules.
String [] sources = new String[] {
"X.java",
"""
public class X {
public static void main(String[] args) {
Long i = 42l;
switch (i) {
case null -> System.out.println("Null");
default -> System.out.println("Default: " + i);
}
}
}
""",
};

if (this.complianceLevel < ClassFileConstants.JDK21) {
this.runNegativeTest(sources,
"----------\n" +
"1. ERROR in X.java (at line 4)\n" +
" switch (i) {\n" +
" ^\n" +
"Cannot switch on a value of type Long. Only convertible int values, strings or enum variables are permitted\n" +
"----------\n" +
"2. ERROR in X.java (at line 5)\n" +
" case null -> System.out.println(\"Null\");\n" +
" ^^^^\n" +
"The Java feature 'Pattern Matching in Switch' is only available with source level 21 and above\n" +
"----------\n");
} else {
this.runConformTest(sources, "Default: 42");
}
}

// https://github.com/eclipse-jdt/eclipse.jdt.core/issues/3379
// [Enhanced Switch] Wrong error message: Cannot switch on a value of type Integer... at levels that don't support enhanced switch
public void testIssue3379_3() throws Exception {
if (this.complianceLevel < ClassFileConstants.JDK14)
return; // uses switch rules.

String [] sources = new String[] {
"X.java",
"""
public class X {
public static void main(String[] args) {
Short i = 42;
switch (i) {
case null -> System.out.println("Null");
default -> System.out.println("Default: " + i);
}
}
}
""",
};

if (this.complianceLevel < ClassFileConstants.JDK21) {
this.runNegativeTest(sources,
"----------\n" +
"1. ERROR in X.java (at line 5)\n" +
" case null -> System.out.println(\"Null\");\n" +
" ^^^^\n" +
"The Java feature 'Pattern Matching in Switch' is only available with source level 21 and above\n" +
"----------\n");
} else {
this.runConformTest(sources, "Default: 42");
}
}

public static Class testClass() {
return SwitchTest.class;
}
Expand Down

0 comments on commit eaff460

Please sign in to comment.