Skip to content

Commit

Permalink
Fix contravariant casts, primarily in lambdas
Browse files Browse the repository at this point in the history
  • Loading branch information
jaskarth committed Sep 11, 2023
1 parent 5e8dd19 commit 392a8f6
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1089,16 +1089,19 @@ public static boolean doGenericTypesCast(Exprent ex, VarType left, VarType right

private static boolean shouldGenericTypesCast(Map<VarType, List<VarType>> named, VarType leftType, VarType rightType) {
if (leftType.isGeneric()) {
GenericType genLeft = (GenericType) leftType;
if (rightType.isGeneric()) {
GenericType genRight = (GenericType) rightType;

if (leftType.isSuperset(rightType)) {
// Casting Clazz<?> to Clazz<T> or Clazz<Concrete>
if ((((GenericType) leftType).getWildcard() == GenericType.WILDCARD_NO || ((GenericType) leftType).getWildcard() == GenericType.WILDCARD_EXTENDS) &&
((GenericType) rightType).getWildcard() == GenericType.WILDCARD_SUPER) {
if ((genLeft.getWildcard() == GenericType.WILDCARD_NO || genLeft.getWildcard() == GenericType.WILDCARD_EXTENDS) &&
genRight.getWildcard() == GenericType.WILDCARD_SUPER) {

boolean ok = true;
if (((GenericType) leftType).getWildcard() == GenericType.WILDCARD_EXTENDS) {
if (genLeft.getWildcard() == GenericType.WILDCARD_EXTENDS) {
// Equals, ignoring wildcards
if (!((GenericType) leftType).getArguments().isEmpty() && !((GenericType) rightType).getArguments().isEmpty() &&
if (!genLeft.getArguments().isEmpty() && !genRight.getArguments().isEmpty() &&
leftType.equals(rightType)) {
ok = false;
}
Expand All @@ -1109,26 +1112,29 @@ private static boolean shouldGenericTypesCast(Map<VarType, List<VarType>> named,
}
}
} else {
if (genLeft.getWildcard() == GenericType.WILDCARD_EXTENDS && genRight.getWildcard() == GenericType.WILDCARD_SUPER) {
return true;
}
// Trying to cast two independent generics to each other? Check if they're both the base generic type (i.e. Object)
// and force a cast if so.
if (leftType.type == CodeConstants.TYPE_GENVAR && rightType.type == CodeConstants.TYPE_GENVAR
&& ((GenericType) leftType).getWildcard() == GenericType.WILDCARD_NO && ((GenericType) leftType).getWildcard() == GenericType.WILDCARD_NO) {
&& genLeft.getWildcard() == GenericType.WILDCARD_NO && genLeft.getWildcard() == GenericType.WILDCARD_NO) {

if (named.containsKey(leftType) && named.containsKey(rightType) && named.get(leftType).contains(VarType.VARTYPE_OBJECT) && named.get(rightType).contains(VarType.VARTYPE_OBJECT)) {
return true;
}
}
}

if ((((GenericType) leftType).getWildcard() == GenericType.WILDCARD_NO || ((GenericType) leftType).getWildcard() == GenericType.WILDCARD_SUPER) &&
((GenericType) rightType).getWildcard() == GenericType.WILDCARD_EXTENDS) {
if ((genLeft.getWildcard() == GenericType.WILDCARD_NO || genLeft.getWildcard() == GenericType.WILDCARD_SUPER) &&
genRight.getWildcard() == GenericType.WILDCARD_EXTENDS) {
return true;
}
} else {
// Right is not generic
// Check for casting a concrete rightType to a specific left generic
// e.g. (List<T>)list where 'list' is List<Object>
if (((GenericType) leftType).getWildcard() == GenericType.WILDCARD_NO && ((GenericType) leftType).getArguments().isEmpty()) {
if (genLeft.getWildcard() == GenericType.WILDCARD_NO && genLeft.getArguments().isEmpty()) {
return true;
}
}
Expand Down
1 change: 0 additions & 1 deletion test/org/jetbrains/java/decompiler/SingleClassesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -763,7 +763,6 @@ private void registerJavaRuntime() {
// TODO: otherGenericUnmapped loses mapping when it shouldn't
register(JAVA_8, "TestGenericWildcard");
register(JAVA_8, "TestGenericObjectType");
// TODO: lambda is missing cast
register(JAVA_8, "TestGenericSubclassTypes");
// TODO: wrong variable name
register(JAVA_16_NODEBUG, "TestRecordCanonicalConstructor");
Expand Down
2 changes: 1 addition & 1 deletion testData/results/pkg/TestGenericSubclassTypes.dec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public interface TestGenericSubclassTypes<T> {
Stream<TestGenericSubclassTypes.Constant<T>> cons();

default Iterator<TestGenericSubclassTypes.Numerical<T>> get() {
return this.cons().map(c -> c).iterator();// 23
return this.cons().map(c -> (TestGenericSubclassTypes.Numerical<T>)c).iterator();// 23
}

default Function<? super TestGenericSubclassTypes.Constant<T>, ? extends TestGenericSubclassTypes.Constant<T>> func() {
Expand Down

0 comments on commit 392a8f6

Please sign in to comment.