Fix subtyping queries for synthesized classes
Change-Id: Ide408a08aa3030e962dada9ff2bcb0f6a3d0d2a7
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index 047c498..e2ad67e 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -26,8 +26,7 @@
new ConcurrentHashMap<>();
// For some optimizations, e.g. optimizing synthetic classes, we may need to resolve the current
// class being optimized.
- private final ConcurrentHashMap<DexType, DexProgramClass> synthesizedClasses =
- new ConcurrentHashMap<>();
+ final ConcurrentHashMap<DexType, DexProgramClass> synthesizedClasses = new ConcurrentHashMap<>();
// Set when a new AppInfo replaces a previous one. All public methods should verify that the
// current instance is not obsolete, to ensure that we almost use the most recent AppInfo.
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
index 82dbe10..2e37930 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.ir.desugar.LambdaDescriptor;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.SetUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@@ -19,6 +20,7 @@
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -114,6 +116,10 @@
// Map from types to their subtypes.
private final Map<DexType, ImmutableSet<DexType>> subtypeMap = new IdentityHashMap<>();
+ // Map from synthesized classes to their supertypes.
+ private final Map<DexType, ImmutableSet<DexType>> supertypesForSynthesizedClasses =
+ new ConcurrentHashMap<>();
+
// Map from types to their subtyping information.
private final Map<DexType, TypeInfo> typeInfo;
@@ -132,6 +138,39 @@
assert app() instanceof DirectMappedDexApplication;
}
+ @Override
+ public void addSynthesizedClass(DexProgramClass synthesizedClass) {
+ super.addSynthesizedClass(synthesizedClass);
+
+ // TODO(b/129458850): Remove when we no longer synthesize classes on-the-fly.
+ Set<DexType> visited = SetUtils.newIdentityHashSet(synthesizedClass.allImmediateSupertypes());
+ Deque<DexType> worklist = new ArrayDeque<>(visited);
+ while (!worklist.isEmpty()) {
+ DexType type = worklist.removeFirst();
+ assert visited.contains(type);
+
+ DexClass clazz = definitionFor(type);
+ if (clazz == null) {
+ continue;
+ }
+
+ for (DexType supertype : clazz.allImmediateSupertypes()) {
+ if (visited.add(supertype)) {
+ worklist.addLast(supertype);
+ }
+ }
+ }
+ if (!visited.isEmpty()) {
+ supertypesForSynthesizedClasses.put(synthesizedClass.type, ImmutableSet.copyOf(visited));
+ }
+ }
+
+ private boolean isSynthesizedClassStrictSubtypeOf(DexType synthesizedClass, DexType supertype) {
+ Set<DexType> supertypesOfSynthesizedClass =
+ supertypesForSynthesizedClasses.get(synthesizedClass);
+ return supertypesOfSynthesizedClass != null && supertypesOfSynthesizedClass.contains(supertype);
+ }
+
private DirectMappedDexApplication getDirectApplication() {
// TODO(herhut): Remove need for cast.
return (DirectMappedDexApplication) app();
@@ -426,12 +465,24 @@
@Override
public boolean isSubtype(DexType subtype, DexType supertype) {
- return subtype == supertype || isStrictSubtypeOf(subtype, supertype);
+ if (subtype == supertype || isStrictSubtypeOf(subtype, supertype)) {
+ return true;
+ }
+ if (synthesizedClasses.containsKey(subtype)) {
+ return isSynthesizedClassStrictSubtypeOf(subtype, supertype);
+ }
+ return false;
}
public boolean isStrictSubtypeOf(DexType subtype, DexType supertype) {
// For all erroneous cases, saying `no`---not a strict subtype---is conservative.
- return isStrictSubtypeOf(subtype, supertype, false);
+ if (isStrictSubtypeOf(subtype, supertype, false)) {
+ return true;
+ }
+ if (synthesizedClasses.containsKey(subtype)) {
+ return isSynthesizedClassStrictSubtypeOf(subtype, supertype);
+ }
+ return false;
}
// Depending on optimizations, conservative answer of subtype relation may vary.