Relax assertions during check-cast removal
This CL relaxes the following two assertions from the check-cast removal:
assert outTypeLattice.equals(inTypeLattice);
assert outTypeLattice.equals(castTypeLattice);
These asserts are overly restrictive as they require that the two types agree on the nullability, although they don't need to. For example, it is allowed that the in-type is not nullable and the out-type is nullable. This is a loss of precision, but still sound.
For convenience and clarity, this CL introduces a simple null-lattice that can be used for the soundness checks.
Change-Id: I098eb77be2eb032a6b8533851080ee90995040eb
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java
index 94a07ea..a09039c 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java
@@ -37,6 +37,7 @@
public static final ReferenceTypeLatticeElement REFERENCE =
ReferenceTypeLatticeElement.getReferenceTypeLatticeElement();
+ // TODO(b/72693244): Switch to NullLatticeElement.
private final boolean isNullable;
TypeLatticeElement(boolean isNullable) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 02c06da..17d407b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -1661,25 +1661,30 @@
TypeLatticeElement outTypeLattice = outValue.getTypeLattice();
TypeLatticeElement castTypeLattice =
TypeLatticeElement.fromDexType(castType, appInfo, inTypeLattice.isNullable());
- // 1) Trivial cast.
- // A a = ...
- // A a' = (A) a;
- // 2) Up-cast: we already have finer type info.
- // A < B
- // A a = ...
- // B b = (B) a;
+
+ assert inTypeLattice.nullElement().lessThanOrEqual(outTypeLattice.nullElement());
+
if (TypeLatticeElement.lessThanOrEqual(appInfo, inTypeLattice, castTypeLattice)) {
- assert outTypeLattice.equals(inTypeLattice);
+ // 1) Trivial cast.
+ // A a = ...
+ // A a' = (A) a;
+ // 2) Up-cast: we already have finer type info.
+ // A < B
+ // A a = ...
+ // B b = (B) a;
+ assert inTypeLattice.isNull()
+ || outTypeLattice.asNullable().equals(inTypeLattice.asNullable());
needToRemoveTrivialPhis = needToRemoveTrivialPhis || outValue.numberOfPhiUsers() != 0;
removeOrReplaceByDebugLocalWrite(checkCast, it, inValue, outValue);
- continue;
+ } else {
+ // Otherwise, keep the checkcast to preserve verification errors. E.g., down-cast:
+ // A < B < C
+ // c = ... // Even though we know c is of type A,
+ // a' = (B) c; // (this could be removed, since chained below.)
+ // a'' = (A) a'; // this should remain for runtime verification.
+ assert !inTypeLattice.isNull();
+ assert outTypeLattice.asNullable().equals(castTypeLattice.asNullable());
}
- // Otherwise, keep the checkcast to preserve verification errors. E.g., down-cast:
- // A < B < C
- // c = ... // Even though we know c is of type A,
- // a' = (B) c; // (this could be removed, since chained below.)
- // a'' = (A) a'; // this should remain for runtime verification.
- assert outTypeLattice.equals(castTypeLattice);
}
}
// ... v1