Skip to content

Commit

Permalink
[23] VerifyError during conversion between T extends Short and short
Browse files Browse the repository at this point in the history
when checking primitive conversions involving a type variable, always
use the superclass to find a boxing type, knowing that all boxing types
are classes, so other bounds are irrelevant.

fixes eclipse-jdt#2937
  • Loading branch information
stephan-herrmann committed Sep 15, 2024
1 parent afaf517 commit 60fdc52
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.VoidTypeBinding;

public abstract class Pattern extends Expression {
Expand Down Expand Up @@ -83,6 +84,8 @@ public boolean coversType(TypeBinding type, Scope scope) {
return false;
if (type == null || this.resolvedType == null)
return false;
if (type instanceof TypeVariableBinding && type.superclass().isBoxedPrimitiveType())
type = type.superclass(); // when a boxing type is in supers it must be superclass, because all boxing types are classes
if (type.isPrimitiveOrBoxedPrimitiveType()) {
PrimitiveConversionRoute route = Pattern.findPrimitiveConversionRoute(this.resolvedType, type, scope);
switch (route) {
Expand Down Expand Up @@ -235,23 +238,24 @@ public static PrimitiveConversionRoute findPrimitiveConversionRoute(TypeBinding

} else if (expressionType.isBoxedPrimitiveType() && destinationIsBaseType) {
TypeBinding unboxedExpressionType = scope.environment().computeBoxingType(expressionType);
//TODO: a narrowing reference conversion that is checked followed by an unboxing conversion
//an unboxing conversion (5.1.8)
if (TypeBinding.equalsEquals(destinationType, unboxedExpressionType))
return PrimitiveConversionRoute.UNBOXING_CONVERSION;
//an unboxing conversion followed by a widening primitive conversion
if (BaseTypeBinding.isWidening(destinationType.id, unboxedExpressionType.id))
return PrimitiveConversionRoute.UNBOXING_AND_WIDENING_PRIMITIVE_CONVERSION;
} else if (destinationIsBaseType) {
if (expressionType.erasure().isBoxedPrimitiveType()) { // <T extends Integer> / <? extends Short> ...
int boxId = expressionType.erasure().id;
if (expressionType instanceof TypeVariableBinding && expressionType.superclass().isBoxedPrimitiveType()) { // <T extends Integer> / <? extends Short> ...
int boxId = expressionType.superclass().id;
int exprPrimId = TypeIds.box2primitive(boxId);
if (exprPrimId == destinationType.id)
return PrimitiveConversionRoute.WIDENING_REFERENCE_AND_UNBOXING_COVERSION;
if (BaseTypeBinding.isWidening(destinationType.id, exprPrimId))
return PrimitiveConversionRoute.WIDENING_REFERENCE_AND_UNBOXING_COVERSION_AND_WIDENING_PRIMITIVE_CONVERSION;
}
TypeBinding boxedDestinationType = scope.environment().computeBoxingType(destinationType);
// a narrowing reference conversion that is checked followed by an unboxing conversion
// TODO: check relevance of 'checked', as well as use of erasure() below
if (boxedDestinationType.isCompatibleWith(expressionType.erasure()))
return PrimitiveConversionRoute.NARROWING_AND_UNBOXING_CONVERSION;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7042,6 +7042,46 @@ public static void main(String argv[]) {
"1.0\n" +
"100.0");
}
public void testIssue2937_1() {
runConformTest(new String[] {
"X.java",
"""
record Record<T extends Short>(T t) {}
public class X {
public static <T extends Short> short foo(Record<T> s) {
return switch (s) {
case Record(short s1) -> s1;
default -> 0;
};
}
public static void main(String[] args) {
System.out.print(foo(new Record((short) 2)));
}
}
"""
},
"2");
}
public void testIssue2937_2() {
runConformTest(new String[] {
"X.java",
"""
record Record<T extends Short>(T t) {}
public class X {
public static short foo(Record<?> s) {
return switch (s) {
case Record(short s1) -> s1;
default -> 0;
};
}
public static void main(String[] args) {
System.out.print(foo(new Record((short) 2)));
}
}
"""
},
"2");
}
// test from spec
public void _testSpec001() {
runConformTest(new String[] {
Expand Down

0 comments on commit 60fdc52

Please sign in to comment.