Introduce desugaring precedence sets

Bug: 191656218
Change-Id: I2db490640965c4c99eca518b64b93b181e419b23
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index b4da192..7a3dd75 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -29,8 +29,10 @@
 import com.android.tools.r8.ir.desugar.twr.TwrInstructionDesugaring;
 import com.android.tools.r8.utils.IntBox;
 import com.android.tools.r8.utils.ListUtils;
+import com.android.tools.r8.utils.SetUtils;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.ThrowingConsumer;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -75,14 +77,15 @@
     if (appView.options().enableBackportedMethodRewriting()) {
       backportedMethodRewriter = new BackportedMethodRewriter(appView);
     }
-    // Place TWR before Interface desugaring to eliminate potential $closeResource interface calls.
     if (appView.options().enableTryWithResourcesDesugaring()) {
       desugarings.add(new TwrInstructionDesugaring(appView));
     }
     if (appView.options().isInterfaceMethodDesugaringEnabled()) {
       interfaceMethodRewriter =
           new InterfaceMethodRewriter(
-              appView, backportedMethodRewriter, desugaredLibraryRetargeter);
+              appView,
+              SetUtils.newImmutableSetExcludingNullItems(
+                  backportedMethodRewriter, desugaredLibraryRetargeter));
       desugarings.add(interfaceMethodRewriter);
     } else {
       interfaceMethodRewriter = null;
@@ -91,9 +94,11 @@
         appView.rewritePrefix.isRewriting()
             ? new DesugaredLibraryAPIConverter(
                 appView,
-                interfaceMethodRewriter,
-                desugaredLibraryRetargeter,
-                backportedMethodRewriter)
+                SetUtils.newImmutableSetExcludingNullItems(
+                    interfaceMethodRewriter, desugaredLibraryRetargeter, backportedMethodRewriter),
+                interfaceMethodRewriter != null
+                    ? interfaceMethodRewriter.getEmulatedMethods()
+                    : ImmutableSet.of())
             : null;
     if (desugaredLibraryAPIConverter != null) {
       desugarings.add(desugaredLibraryAPIConverter);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
index 828e70c..4634977 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
@@ -23,22 +23,22 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.FreshLocalProvider;
 import com.android.tools.r8.ir.desugar.LocalStackAllocator;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
-import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConversionCfCodeProvider;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.StringDiagnostic;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -67,31 +67,24 @@
 
   private final AppView<?> appView;
   private final DexItemFactory factory;
-  // This is used to filter out double desugaring on backported methods.
-  private final BackportedMethodRewriter backportedMethodRewriter;
-  private final InterfaceMethodRewriter interfaceMethodRewriter;
-  private final DesugaredLibraryRetargeter retargeter;
+  private final Set<CfInstructionDesugaring> precedingDesugarings;
+  private final Set<DexString> emulatedMethods;
 
   private final DesugaredLibraryWrapperSynthesizer wrapperSynthesizor;
-  private final Set<DexMethod> trackedCallBackAPIs;
   private final Set<DexMethod> trackedAPIs;
 
   public DesugaredLibraryAPIConverter(
       AppView<?> appView,
-      InterfaceMethodRewriter interfaceMethodRewriter,
-      DesugaredLibraryRetargeter retargeter,
-      BackportedMethodRewriter backportedMethodRewriter) {
+      Set<CfInstructionDesugaring> precedingDesugarings,
+      Set<DexString> emulatedMethods) {
     this.appView = appView;
     this.factory = appView.dexItemFactory();
-    this.interfaceMethodRewriter = interfaceMethodRewriter;
-    this.retargeter = retargeter;
-    this.backportedMethodRewriter = backportedMethodRewriter;
+    this.precedingDesugarings = precedingDesugarings;
+    this.emulatedMethods = emulatedMethods;
     this.wrapperSynthesizor = new DesugaredLibraryWrapperSynthesizer(appView);
     if (appView.options().testing.trackDesugaredAPIConversions) {
-      trackedCallBackAPIs = Sets.newConcurrentHashSet();
       trackedAPIs = Sets.newConcurrentHashSet();
     } else {
-      trackedCallBackAPIs = null;
       trackedAPIs = null;
     }
   }
@@ -176,10 +169,7 @@
   // The problem is that a method can resolve into a library method which is not present at runtime,
   // the code relies in that case on emulated interface dispatch. We should not convert such API.
   private boolean isEmulatedInterfaceOverride(DexClassAndMethod invokedMethod) {
-    if (interfaceMethodRewriter == null) {
-      return false;
-    }
-    if (!interfaceMethodRewriter.getEmulatedMethods().contains(invokedMethod.getName())) {
+    if (!emulatedMethods.contains(invokedMethod.getName())) {
       return false;
     }
     DexClassAndMethod interfaceResult =
@@ -195,18 +185,8 @@
   }
 
   private boolean isAlreadyDesugared(CfInvoke invoke, ProgramMethod context) {
-    if (interfaceMethodRewriter != null
-        && interfaceMethodRewriter.needsDesugaring(invoke, context)) {
-      return true;
-    }
-    if (retargeter != null && retargeter.needsDesugaring(invoke, context)) {
-      return true;
-    }
-    if (backportedMethodRewriter != null
-        && backportedMethodRewriter.needsDesugaring(invoke, context)) {
-      return true;
-    }
-    return false;
+    return Iterables.any(
+        precedingDesugarings, desugaring -> desugaring.needsDesugaring(invoke, context));
   }
 
   public static DexMethod methodWithVivifiedTypeInSignature(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index 9ee3f54..09c13c0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -34,15 +34,12 @@
 import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.DesugarDescription;
 import com.android.tools.r8.ir.desugar.FreshLocalProvider;
 import com.android.tools.r8.ir.desugar.LocalStackAllocator;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeter;
 import com.android.tools.r8.ir.desugar.lambda.LambdaInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.stringconcat.StringConcatInstructionDesugaring;
 import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations;
@@ -56,6 +53,7 @@
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
 import com.android.tools.r8.utils.structural.Ordered;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -108,8 +106,7 @@
   private final Map<DexType, DefaultMethodsHelper.Collection> cache = new ConcurrentHashMap<>();
 
   // This is used to filter out double desugaring on backported methods.
-  private final BackportedMethodRewriter backportedMethodRewriter;
-  private final DesugaredLibraryRetargeter desugaredLibraryRetargeter;
+  private final Set<CfInstructionDesugaring> precedingDesugarings;
 
   /** Defines a minor variation in desugaring. */
   public enum Flavor {
@@ -119,26 +116,10 @@
     ExcludeDexResources
   }
 
-  // Constructor for cf to cf desugaring.
   public InterfaceMethodRewriter(
-      AppView<?> appView,
-      BackportedMethodRewriter rewriter,
-      DesugaredLibraryRetargeter desugaredLibraryRetargeter) {
+      AppView<?> appView, Set<CfInstructionDesugaring> precedingDesugarings) {
     this.appView = appView;
-    this.backportedMethodRewriter = rewriter;
-    this.desugaredLibraryRetargeter = desugaredLibraryRetargeter;
-    this.options = appView.options();
-    this.factory = appView.dexItemFactory();
-    this.helper = new InterfaceDesugaringSyntheticHelper(appView);
-    initializeEmulatedInterfaceVariables();
-  }
-
-  // Constructor for IR desugaring.
-  public InterfaceMethodRewriter(AppView<?> appView, IRConverter converter) {
-    assert converter != null;
-    this.appView = appView;
-    this.backportedMethodRewriter = null;
-    this.desugaredLibraryRetargeter = null;
+    this.precedingDesugarings = precedingDesugarings;
     this.options = appView.options();
     this.factory = appView.dexItemFactory();
     this.helper = new InterfaceDesugaringSyntheticHelper(appView);
@@ -228,13 +209,8 @@
   }
 
   private boolean isAlreadyDesugared(CfInvoke invoke, ProgramMethod context) {
-    // In Cf to Cf it is forbidden to desugar twice the same instruction, if the backported
-    // method rewriter or the desugared library retargeter already desugar the instruction, they
-    // take precedence and nothing has to be done here.
-    return (backportedMethodRewriter != null
-            && backportedMethodRewriter.needsDesugaring(invoke, context))
-        || (desugaredLibraryRetargeter != null
-            && desugaredLibraryRetargeter.needsDesugaring(invoke, context));
+    return Iterables.any(
+        precedingDesugarings, desugaring -> desugaring.needsDesugaring(invoke, context));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/utils/SetUtils.java b/src/main/java/com/android/tools/r8/utils/SetUtils.java
index 04b399d..0a53f60 100644
--- a/src/main/java/com/android/tools/r8/utils/SetUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/SetUtils.java
@@ -89,6 +89,16 @@
     return builder.build();
   }
 
+  public static <T> ImmutableSet<T> newImmutableSetExcludingNullItems(T... items) {
+    ImmutableSet.Builder<T> builder = ImmutableSet.builder();
+    for (T item : items) {
+      if (item != null) {
+        builder.add(item);
+      }
+    }
+    return builder.build();
+  }
+
   public static <T, S> Set<T> mapIdentityHashSet(Set<S> set, Function<S, T> fn) {
     Set<T> out = newIdentityHashSet(set.size());
     for (S element : set) {