Include synthetic kind in the structure of synthetics.

Bug: 188076699
Change-Id: I3c4b52ca9eb1207fa75f6dea95e3f5ce70c39e07
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinition.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinition.java
index 3c91d68..d868dfc 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinition.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinition.java
@@ -71,6 +71,7 @@
       ClassToFeatureSplitMap classToFeatureSplitMap,
       SyntheticItems syntheticItems) {
     Hasher hasher = Hashing.murmur3_128().newHasher();
+    hasher.putInt(kind.id);
     if (getKind().isFixedSuffixSynthetic) {
       // Fixed synthetics are non-shareable. Its unique type is used as the hash key.
       getHolder().getType().hash(hasher);
@@ -103,6 +104,12 @@
       GraphLens graphLens,
       ClassToFeatureSplitMap classToFeatureSplitMap,
       SyntheticItems syntheticItems) {
+    {
+      int order = kind.compareTo(other.getKind());
+      if (order != 0) {
+        return order;
+      }
+    }
     DexType thisType = getHolder().getType();
     DexType otherType = other.getHolder().getType();
     if (getKind().isFixedSuffixSynthetic) {
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
index 46bb432..f0fc2e7 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
@@ -41,6 +41,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.IdentityHashMap;
 import java.util.List;
@@ -553,10 +554,11 @@
         (externalSyntheticTypePrefix, groups) -> {
           // Sort the equivalence groups that go into 'context' including the context type of the
           // representative which is equal to 'context' here (see assert below).
-          groups.sort(
+          Comparator<EquivalenceGroup<T>> comparator =
               (a, b) ->
                   a.compareToIncludingContext(
-                      b, appView.graphLens(), classToFeatureSplitMap, synthetics));
+                      b, appView.graphLens(), classToFeatureSplitMap, synthetics);
+          ListUtils.destructiveSort(groups, comparator);
           for (int i = 0; i < groups.size(); i++) {
             EquivalenceGroup<T> group = groups.get(i);
             assert group
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 e7c8e46..3966fd0 100644
--- a/src/main/java/com/android/tools/r8/utils/ListUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ListUtils.java
@@ -7,6 +7,7 @@
 import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Optional;
 import java.util.function.BiFunction;
@@ -181,4 +182,36 @@
   public interface ReferenceAndIntConsumer<T> {
     void accept(T item, int index);
   }
+
+  public static <T> void destructiveSort(List<T> items, Comparator<T> comparator) {
+    items.sort(comparator);
+  }
+
+  // Utility to add a slow verification of a comparator as part of sorting. Note that this
+  // should not generally be used in asserts unless the quadratic behavior can be tolerated.
+  public static <T> void destructiveSortAndVerify(List<T> items, Comparator<T> comparator) {
+    destructiveSort(items, comparator);
+    assert verifyComparatorOnSortedList(items, comparator);
+  }
+
+  private static <T> boolean verifyComparatorOnSortedList(List<T> items, Comparator<T> comparator) {
+    for (int i = 0; i < items.size(); i++) {
+      boolean allowEqual = true;
+      for (int j = i; j < items.size(); j++) {
+        T a = items.get(i);
+        T b = items.get(j);
+        int result1 = comparator.compare(a, b);
+        int result2 = comparator.compare(b, a);
+        boolean isEqual = result1 == 0 && result2 == 0;
+        if (i == j) {
+          assert isEqual;
+        } else if (!allowEqual || !isEqual) {
+          allowEqual = false;
+          assert result1 < 0;
+          assert result2 > 0;
+        }
+      }
+    }
+    return true;
+  }
 }