Handle collisions in rewriting of AppInfoWithLiveness

Change-Id: I7ecff6c821e6d0f85a51b9f997bd0372b077533c
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLens.java b/src/main/java/com/android/tools/r8/graph/GraphLens.java
index 5a28054..a07a380 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLens.java
@@ -14,6 +14,7 @@
 import com.android.tools.r8.shaking.KeepInfoCollection;
 import com.android.tools.r8.utils.Action;
 import com.android.tools.r8.utils.IterableUtils;
+import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.SetUtils;
 import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeHashMap;
 import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap;
@@ -559,10 +560,34 @@
     return result;
   }
 
-  public <R extends DexReference, T> ImmutableMap<R, T> rewriteReferenceKeys(Map<R, T> map) {
-    ImmutableMap.Builder<R, T> builder = ImmutableMap.builder();
-    map.forEach((reference, value) -> builder.put(rewriteReference(reference), value));
-    return builder.build();
+  public <R extends DexReference, T> Map<R, T> rewriteReferenceKeys(
+      Map<R, T> map, Function<List<T>, T> merge) {
+    Map<R, T> result = new IdentityHashMap<>();
+    Map<R, List<T>> needsMerge = new IdentityHashMap<>();
+    map.forEach(
+        (reference, value) -> {
+          R rewrittenReference = rewriteReference(reference);
+          List<T> unmergedValues = needsMerge.get(rewrittenReference);
+          if (unmergedValues != null) {
+            unmergedValues.add(value);
+          } else {
+            T existingValue = result.put(rewrittenReference, value);
+            if (existingValue != null) {
+              // Remove this for now and let the merge function decide when all colliding values are
+              // known.
+              needsMerge.put(rewrittenReference, ListUtils.newArrayList(existingValue, value));
+              result.remove(rewrittenReference);
+            }
+          }
+        });
+    needsMerge.forEach(
+        (rewrittenReference, unmergedValues) -> {
+          T mergedValue = merge.apply(unmergedValues);
+          if (mergedValue != null) {
+            result.put(rewrittenReference, mergedValue);
+          }
+        });
+    return result;
   }
 
   public Object2BooleanMap<DexReference> rewriteReferenceKeys(Object2BooleanMap<DexReference> map) {
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index c4ebfe7..239c0da 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -1072,9 +1072,11 @@
         objectAllocationInfoCollection.rewrittenWithLens(definitionSupplier, lens),
         lens.rewriteCallSites(callSites, definitionSupplier),
         keepInfo.rewrite(lens, application.options),
-        lens.rewriteReferenceKeys(mayHaveSideEffects),
-        lens.rewriteReferenceKeys(noSideEffects),
-        lens.rewriteReferenceKeys(assumedValues),
+        // Take any rule in case of collisions.
+        lens.rewriteReferenceKeys(mayHaveSideEffects, ListUtils::first),
+        // Drop assume rules in case of collisions.
+        lens.rewriteReferenceKeys(noSideEffects, rules -> null),
+        lens.rewriteReferenceKeys(assumedValues, rules -> null),
         lens.rewriteMethods(alwaysInline),
         lens.rewriteMethods(forceInline),
         lens.rewriteMethods(neverInline),
diff --git a/src/main/java/com/android/tools/r8/utils/ListUtils.java b/src/main/java/com/android/tools/r8/utils/ListUtils.java
index eb6e610..5781f91 100644
--- a/src/main/java/com/android/tools/r8/utils/ListUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ListUtils.java
@@ -148,6 +148,13 @@
     return list;
   }
 
+  public static <T> ArrayList<T> newArrayList(T element, T other) {
+    ArrayList<T> list = new ArrayList<>();
+    list.add(element);
+    list.add(other);
+    return list;
+  }
+
   public static <T> ArrayList<T> newArrayList(ForEachable<T> forEachable) {
     ArrayList<T> list = new ArrayList<>();
     forEachable.forEach(list::add);