Skip to content

Commit

Permalink
[Switch][Record Patterns] Unchecked conversion error missing from ECJ
Browse files Browse the repository at this point in the history
+ try to balance responsibility about type checking between
  - Pattern.isApplicable() - don't yet report in nested position
  - RecordPattern.resolveType() - failed to check isApplicable()
  - InstanceOfExpression.resolveType() - avoid pattern-agnostic checks

+ added the 1st(!) test for inapplicable record pattern in switch
  • Loading branch information
stephan-herrmann committed Oct 10, 2024
1 parent 09766de commit df50953
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,9 @@ public TypeBinding resolveType(BlockScope scope) {
if (expressionType == null || checkedType == null)
return null;

if (this.pattern instanceof RecordPattern) // subsequent tests are not relevant for RecordPatterns
return this.resolvedType = TypeBinding.BOOLEAN;

if (!checkedType.isReifiable()) {
CompilerOptions options = scope.compilerOptions();
// Report same as before for older compliances
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,18 +148,27 @@ protected boolean isApplicable(TypeBinding other, BlockScope scope) {
scope.problemReporter().incompatiblePatternType(this, other, patternType);
return false;
}
boolean applicable = true;
if (patternType.isBaseType()) {
PrimitiveConversionRoute route = Pattern.findPrimitiveConversionRoute(this.resolvedType, this.outerExpressionType, scope);
if (!TypeBinding.equalsEquals(other, patternType)
&& route == PrimitiveConversionRoute.NO_CONVERSION_ROUTE) {
scope.problemReporter().incompatiblePatternType(this, other, patternType);
return false;
}
} else if (!checkCastTypesCompatibility(scope, other, patternType, null, true)) {
scope.problemReporter().incompatiblePatternType(this, other, patternType);
return false;
} else {
if (!checkCastTypesCompatibility(scope, patternType, other, null, true)) {
if (this.enclosingPattern != null) {
scope.problemReporter().incompatiblePatternType(this, other, patternType);
return false;
}
applicable = false;
}
if ((this.bits & ASTNode.UnsafeCast) != 0) {
scope.problemReporter().unsafeCastInInstanceof(this, this.outerExpressionType, patternType);
}
}
return true;
return applicable;
}

public abstract boolean dominates(Pattern p);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,18 @@ public TypeBinding resolveType(BlockScope scope) {
return this.resolvedType = null;
}

if (this.resolvedType.isRawType()) {
if (this.outerExpressionType instanceof ReferenceBinding) {
if (this.outerExpressionType instanceof ReferenceBinding) {
if (this.resolvedType.isRawType()) {
ReferenceBinding binding = inferRecordParameterization(scope, (ReferenceBinding) this.outerExpressionType);
if (binding == null || !binding.isValidBinding()) {
scope.problemReporter().cannotInferRecordPatternTypes(this);
return this.resolvedType = null;
}
this.resolvedType = binding.capture(scope, this.sourceStart, this.sourceEnd);
} else {
if (!this.isApplicable(this.outerExpressionType, scope)) {
scope.problemReporter().typeMismatchError(this.outerExpressionType, this.resolvedType, this, null);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1568,8 +1568,8 @@ public void test47() {
"----------\n" +
"1. ERROR in X.java (at line 4)\n" +
" if (objectBox instanceof Box<String>(String s)) {\n" +
" ^^^^^^^^^\n" +
"Type Box<Object> cannot be safely cast to Box<String>\n" +
" ^^^^^^^^^^^^^^^^^^^^^\n" +
"Type mismatch: cannot convert from Box<Object> to Box<String>\n" +
"----------\n");
}
public void test48() {
Expand Down Expand Up @@ -2008,8 +2008,8 @@ public void testRecordPatternTypeInference_011() {
"----------\n" +
"1. ERROR in X.java (at line 10)\n" +
" if (p instanceof R<>(String a)) {\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Incompatible conditional operand types R<capture#1-of ? extends I> and R\n" +
" ^^^^^^^^^^^^^\n" +
"Type mismatch: cannot convert from R<capture#1-of ? extends I> to R\n" +
"----------\n");
}
public void testIssue900_1() {
Expand Down Expand Up @@ -4686,4 +4686,54 @@ static void foo(Object o) {
"Syntax error on tokens, delete these tokens\n" +
"----------\n");
}

public void testIssue3066() {
runNegativeTest(new String[] {
"X.java",
"""
public record X<T>(int x) {
public static void main(String[] args) {
Object o = new Object();
switch (o) {
case X<String>(int x):
default:
}
}
}
"""
},
"""
----------
1. ERROR in X.java (at line 5)
case X<String>(int x):
^^^^^^^^^^^^^^^^
Type X<String> cannot be safely cast to Object
----------
""");
}

public void testIssue3066_notApplicable() {
runNegativeTest(new String[] {
"X.java",
"""
public record X(int x) {
public static void main(String[] args) {
java.io.Serializable o = "";
switch (o) {
case X(int x):
default:
}
}
}
"""
},
"""
----------
1. ERROR in X.java (at line 5)
case X(int x):
^^^^^^^^
Type mismatch: cannot convert from Serializable to X
----------
""");
}
}

0 comments on commit df50953

Please sign in to comment.