Ensure default interface methods while desugaring.

Bug: 183998768
Change-Id: Id8846a4b299209de0d86779ef98bee3438559d9e
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index b2fe6cf..0dc90ad 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -222,7 +222,8 @@
     assert defaultInterfaceMethodImplementation == null;
     assert implementation != null;
     assert code != null;
-    assert code == implementation.getCode();
+    // TODO(b/183998768): Once R8 desugars in the enqueuer this should always be invalid code.
+    assert InvalidCode.isInvalidCode(code) || code == implementation.getCode();
     accessFlags.setAbstract();
     removeCode();
     defaultInterfaceMethodImplementation = implementation;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
index 3381ece..9ff7d2a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -819,7 +819,7 @@
     // In desugared library, emulated interface methods can be overridden by retarget lib members.
     DexMethod forwardMethod =
         target.getHolder().isInterface()
-            ? rewriter.defaultAsMethodOfCompanionClass(target)
+            ? rewriter.ensureDefaultAsMethodOfCompanionClassStub(target).getReference()
             : appView.options().desugaredLibraryConfiguration.retargetMethod(target, appView);
     DexEncodedMethod desugaringForwardingMethod =
         DexEncodedMethod.createDesugaringForwardingMethod(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java
index 30fc05c..398d304 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java
@@ -5,7 +5,6 @@
 
 import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.emulateInterfaceLibraryMethod;
 
-import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexApplication.Builder;
 import com.android.tools.r8.graph.DexClass;
@@ -163,20 +162,20 @@
 
   private void synthesizeEmulatedInterfaceMethod(
       ProgramMethod method, DexProgramClass theInterface, SyntheticMethodBuilder methodBuilder) {
+    assert !method.getDefinition().isStatic();
     DexMethod libraryMethod =
         method
             .getReference()
             .withHolder(emulatedInterfaces.get(theInterface.type), appView.dexItemFactory());
     DexMethod companionMethod =
-        method.getAccessFlags().isStatic()
-            ? rewriter.staticAsMethodOfCompanionClass(method)
-            : rewriter.defaultAsMethodOfCompanionClass(method);
+        rewriter.ensureDefaultAsMethodOfProgramCompanionClassStub(method).getReference();
     List<Pair<DexType, DexMethod>> extraDispatchCases =
         getDispatchCases(method, theInterface, companionMethod);
     DexMethod emulatedMethod = emulateInterfaceLibraryMethod(method, appView.dexItemFactory());
     methodBuilder
         .setName(emulatedMethod.getName())
         .setProto(emulatedMethod.getProto())
+        .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
         .setCode(
             theMethod ->
                 new EmulateInterfaceSyntheticCfCodeProvider(
@@ -185,10 +184,7 @@
                         libraryMethod,
                         extraDispatchCases,
                         appView)
-                    .generateCfCode())
-        .setAccessFlags(
-            MethodAccessFlags.fromSharedAccessFlags(
-                Constants.ACC_SYNTHETIC | Constants.ACC_STATIC | Constants.ACC_PUBLIC, false));
+                    .generateCfCode());
   }
 
   private List<Pair<DexType, DexMethod>> getDispatchCases(
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 2bd6a48..1681a83 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
@@ -38,6 +38,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
 import com.android.tools.r8.graph.InvalidCode;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -744,7 +745,7 @@
                 // TODO(b/183998768): Why does this not create a stub on the class path?
                 : privateAsMethodOfCompanionClass(directTarget);
       } else {
-        companionMethod = defaultAsMethodOfCompanionClass(directTarget);
+        companionMethod = ensureDefaultAsMethodOfCompanionClassStub(directTarget).getReference();
       }
       return rewriteInvoke.apply(companionMethod);
     } else {
@@ -754,7 +755,8 @@
       if (virtualTarget != null) {
         // This is a invoke-direct call to a virtual method.
         assert invokeNeedsRewriting(invokedMethod, DIRECT);
-        return rewriteInvoke.apply(defaultAsMethodOfCompanionClass(virtualTarget));
+        return rewriteInvoke.apply(
+            ensureDefaultAsMethodOfCompanionClassStub(virtualTarget).getReference());
       } else {
         // The below assert is here because a well-type program should have a target, but we
         // cannot throw a compilation error, since we have no knowledge about the input.
@@ -925,7 +927,8 @@
           DexClass holder = target.getHolder();
           if (holder.isLibraryClass() && holder.isInterface()) {
             assert invokeNeedsRewriting(invokedMethod, SUPER);
-            return rewriteInvoke.apply(defaultAsMethodOfCompanionClass(target));
+            return rewriteInvoke.apply(
+                ensureDefaultAsMethodOfCompanionClassStub(target).getReference());
           }
         }
       }
@@ -938,25 +941,23 @@
     DexClassAndMethod superTarget =
         appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context);
     if (superTarget != null && superTarget.isLibraryMethod()) {
+      assert invokeNeedsRewriting(invokedMethod, SUPER);
       // Rewriting is required because the super invoke resolves into a missing
       // method (method is on desugared library). Find out if it needs to be
-      // retarget or if it just calls a companion class method and rewrite.
+      // retargeted or if it just calls a companion class method and rewrite.
       DexMethod retargetMethod =
           options.desugaredLibraryConfiguration.retargetMethod(superTarget, appView);
-      if (retargetMethod == null) {
-        DexMethod originalCompanionMethod = defaultAsMethodOfCompanionClass(superTarget);
-        DexMethod companionMethod =
-            factory.createMethod(
-                getCompanionClassType(emulatedItf),
-                factory.protoWithDifferentFirstParameter(
-                    originalCompanionMethod.proto, emulatedItf),
-                originalCompanionMethod.name);
-        assert invokeNeedsRewriting(invokedMethod, SUPER);
-        return rewriteInvoke.apply(companionMethod);
-      } else {
-        assert invokeNeedsRewriting(invokedMethod, SUPER);
+      if (retargetMethod != null) {
         return rewriteInvoke.apply(retargetMethod);
       }
+      DexClassAndMethod emulatedMethod =
+          superTarget.getReference().lookupMemberOnClass(appView.definitionFor(emulatedItf));
+      if (emulatedMethod == null) {
+        assert false;
+        return null;
+      }
+      DexClassAndMethod companionMethod = ensureDefaultAsMethodOfCompanionClassStub(emulatedMethod);
+      return rewriteInvoke.apply(companionMethod.getReference());
     }
     return null;
   }
@@ -1194,6 +1195,16 @@
     return factory.createType(interfaceTypeDescriptor);
   }
 
+  DexClassAndMethod ensureDefaultAsMethodOfCompanionClassStub(DexClassAndMethod method) {
+    if (method.isProgramMethod()) {
+      return ensureDefaultAsMethodOfProgramCompanionClassStub(method.asProgramMethod());
+    }
+    ClasspathOrLibraryClass context = method.getHolder().asClasspathOrLibraryClass();
+    DexMethod companionMethodReference =
+        defaultAsMethodOfCompanionClass(method.getReference(), appView.dexItemFactory());
+    return ensureMethodOfClasspathCompanionClassStub(companionMethodReference, context, appView);
+  }
+
   DexClassAndMethod ensureStaticAsMethodOfCompanionClassStub(DexClassAndMethod method) {
     if (method.isProgramMethod()) {
       return ensureStaticAsMethodOfProgramCompanionClassStub(method.asProgramMethod());
@@ -1204,6 +1215,37 @@
     }
   }
 
+  ProgramMethod ensureDefaultAsMethodOfProgramCompanionClassStub(ProgramMethod method) {
+    DexEncodedMethod virtual = method.getDefinition();
+    DexMethod companionMethod =
+        defaultAsMethodOfCompanionClass(method.getReference(), appView.dexItemFactory());
+    return InterfaceProcessor.ensureCompanionMethod(
+        method.getHolder(),
+        companionMethod.getName(),
+        companionMethod.getProto(),
+        appView,
+        methodBuilder -> {
+          MethodAccessFlags newFlags = method.getAccessFlags().copy();
+          newFlags.promoteToStatic();
+          methodBuilder
+              .setAccessFlags(newFlags)
+              .setGenericSignature(MethodTypeSignature.noSignature())
+              .setAnnotations(
+                  virtual
+                      .annotations()
+                      .methodParametersWithFakeThisArguments(appView.dexItemFactory()))
+              .setParameterAnnotationsList(
+                  virtual.getParameterAnnotations().withFakeThisParameter())
+              // TODO(b/183998768): Once R8 desugars in the enqueuer this should set an invalid
+              //  code to ensure it is never used before desugared and installed.
+              .setCode(
+                  ignored ->
+                      appView.enableWholeProgramOptimizations()
+                          ? virtual.getCode()
+                          : InvalidCode.getInstance());
+        });
+  }
+
   ProgramMethod ensurePrivateAsMethodOfProgramCompanionClassStub(ProgramMethod method) {
     DexMethod companionMethod =
         privateAsMethodOfCompanionClass(method.getReference(), appView.dexItemFactory());
@@ -1222,6 +1264,7 @@
               .setAccessFlags(newFlags)
               .setGenericSignature(definition.getGenericSignature())
               .setAnnotations(definition.annotations())
+              // TODO(b/183998768): Should this not also be updating with a fake 'this'
               .setParameterAnnotationsList(definition.getParameterAnnotations())
               // TODO(b/183998768): Once R8 desugars in the enqueuer this should set an invalid
               //  code to ensure it is never used before desugared and installed.
@@ -1272,13 +1315,6 @@
     return instanceAsMethodOfCompanionClass(method, DEFAULT_METHOD_PREFIX, factory);
   }
 
-  public final DexMethod defaultAsMethodOfCompanionClass(DexClassAndMethod method) {
-    DexItemFactory dexItemFactory = appView.dexItemFactory();
-    DexMethod rewritten = defaultAsMethodOfCompanionClass(method.getReference(), dexItemFactory);
-    recordCompanionClassReference(appView, method, rewritten);
-    return rewritten;
-  }
-
   // Represent a private instance interface method as a method of companion class.
   static DexMethod privateAsMethodOfCompanionClass(DexMethod method, DexItemFactory factory) {
     // Add an implicit argument to represent the receiver.
@@ -1289,17 +1325,6 @@
     return privateAsMethodOfCompanionClass(method.getReference(), factory);
   }
 
-  private static DexClassAndMethod recordCompanionClassReference(
-      AppView<?> appView, DexClassAndMethod method, DexMethod rewritten) {
-    ClasspathOrLibraryClass context = method.getHolder().asClasspathOrLibraryClass();
-    // If the interface class is a program class, we shouldn't need to synthesize the companion
-    // class on the classpath.
-    if (context == null) {
-      return null;
-    }
-    return ensureMethodOfClasspathCompanionClassStub(rewritten, context, appView);
-  }
-
   private static DexClassAndMethod ensureMethodOfClasspathCompanionClassStub(
       DexMethod companionMethodReference, ClasspathOrLibraryClass context, AppView<?> appView) {
     return appView
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
index cd4e9cb..64775fb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -34,7 +34,6 @@
 import com.android.tools.r8.graph.FieldAccessFlags;
 import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
 import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.InvalidCode;
 import com.android.tools.r8.graph.MethodAccessFlags;
@@ -232,44 +231,19 @@
                   + method.toSourceString(),
               iface.origin);
         }
-
-        // Create a new method in a companion class to represent default method implementation.
-        DexMethod companionMethod = rewriter.defaultAsMethodOfCompanionClass(method);
-
         Code code = virtual.getCode();
         if (code == null) {
           throw new CompilationError(
               "Code is missing for default " + "interface method: " + method.toSourceString(),
               iface.origin);
         }
-
-        MethodAccessFlags newFlags = method.getAccessFlags().copy();
-        newFlags.promoteToStatic();
+        // Create a new method in a companion class to represent default method implementation.
+        ProgramMethod companion = rewriter.ensureDefaultAsMethodOfProgramCompanionClassStub(method);
         DexEncodedMethod.setDebugInfoWithFakeThisParameter(
-            code, companionMethod.getArity(), appView);
-
-        ensureCompanionMethod(
-            iface,
-            companionMethod.getName(),
-            companionMethod.getProto(),
-            appView,
-            methodBuilder ->
-                methodBuilder
-                    .setAccessFlags(newFlags)
-                    .setGenericSignature(MethodTypeSignature.noSignature())
-                    .setAnnotations(
-                        virtual
-                            .annotations()
-                            .methodParametersWithFakeThisArguments(appView.dexItemFactory()))
-                    .setParameterAnnotationsList(
-                        virtual.getParameterAnnotations().withFakeThisParameter())
-                    .setCode(ignored -> virtual.getCode())
-                    .setOnBuildConsumer(
-                        implMethod -> {
-                          implMethod.copyMetadata(virtual);
-                          getPostProcessingInterfaceInfo(iface)
-                              .mapDefaultMethodToCompanionMethod(virtual, implMethod);
-                        }));
+            code, companion.getReference().getArity(), appView);
+        finalizeMoveToCompanionMethod(method, companion);
+        getPostProcessingInterfaceInfo(iface)
+            .mapDefaultMethodToCompanionMethod(virtual, companion.getDefinition());
       }
     }
   }
@@ -300,7 +274,6 @@
         companion = rewriter.ensureStaticAsMethodOfProgramCompanionClassStub(method);
       } else {
         assert definition.isPrivate();
-        companion = rewriter.ensurePrivateAsMethodOfProgramCompanionClassStub(method);
         Code code = definition.getCode();
         if (code == null) {
           throw new CompilationError(
@@ -309,24 +282,31 @@
                   + method.getReference().toSourceString(),
               iface.origin);
         }
+        companion = rewriter.ensurePrivateAsMethodOfProgramCompanionClassStub(method);
         DexEncodedMethod.setDebugInfoWithFakeThisParameter(
             code, companion.getReference().getArity(), appView);
       }
 
-      // TODO(b/183998768): R8 should also install an "invalid code" object until the actual code
-      //  moves.
-      assert appView.enableWholeProgramOptimizations()
-          || InvalidCode.isInvalidCode(companion.getDefinition().getCode());
-      if (definition.hasClassFileVersion()) {
-        companion.getDefinition().downgradeClassFileVersion(definition.getClassFileVersion());
-      }
-      companion.getDefinition().setCode(definition.getCode(), appView);
+      finalizeMoveToCompanionMethod(method, companion);
       getPostProcessingInterfaceInfo(iface)
           .moveMethod(method.getReference(), companion.getReference());
-      definition.setCode(InvalidCode.getInstance(), appView);
     }
   }
 
+  private void finalizeMoveToCompanionMethod(ProgramMethod method, ProgramMethod companion) {
+    // TODO(b/183998768): R8 should also install an "invalid code" object until the actual code
+    //  moves.
+    assert appView.enableWholeProgramOptimizations()
+        || InvalidCode.isInvalidCode(companion.getDefinition().getCode());
+    DexProgramClass iface = method.getHolder();
+    DexEncodedMethod definition = method.getDefinition();
+    if (definition.hasClassFileVersion()) {
+      companion.getDefinition().downgradeClassFileVersion(definition.getClassFileVersion());
+    }
+    companion.getDefinition().setCode(definition.getCode(), appView);
+    definition.setCode(InvalidCode.getInstance(), appView);
+  }
+
   private void clearDirectMethods(DexProgramClass iface) {
     DexEncodedMethod clinit = iface.getClassInitializer();
     MethodCollection methodCollection = iface.getMethodCollection();