Merge in intermediate mode due to external sharding.

The choice of shards does not ensure synthetics are in the same
compilation unit as the context giving rise to them. The output must
thus remain in intermediate mode as deduplicating them would be
unsound.

Bug: b/241351268
Change-Id: I041ec1f274aa64220e8a136f463bb822aafa45b3
diff --git a/src/main/java/com/android/tools/r8/DexFileMergerHelper.java b/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
index 163e476..b46e8f5 100644
--- a/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
+++ b/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
@@ -47,6 +47,9 @@
       throws CompilationFailedException {
     InternalOptions options = command.getInternalOptions();
 
+    // TODO(b/241351268): Don't compile in intermediate mode as the output is a final "shard".
+    options.intermediate = true;
+
     // TODO(b/241063980): Move this to D8Command.Builder.setDisableDesugaring(true) in bazel.
     options.desugarState = DesugarState.OFF;
 
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/BackportDuplicationTest.java b/src/test/java/com/android/tools/r8/desugar/backports/BackportDuplicationTest.java
index f6f59e8..7d13c36 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/BackportDuplicationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/BackportDuplicationTest.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.ByteDataView;
 import com.android.tools.r8.ClassFileConsumer;
 import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.DexFilePerClassFileConsumer;
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.OutputMode;
 import com.android.tools.r8.TestBase;
@@ -204,7 +205,7 @@
 
   @Test
   public void testPerFileIntermediate() throws Exception {
-    ProcessResult result = runDoublePerFileCompilation(true);
+    ProcessResult result = runDoublePerFileCompilation(Backend.CF, true);
     assertEquals(result.toString(), 0, result.exitCode);
     assertEquals(EXPECTED, result.stdout);
   }
@@ -212,7 +213,7 @@
   @Test
   public void testPerFileNonIntermediate() throws Exception {
     try {
-      runDoublePerFileCompilation(false);
+      runDoublePerFileCompilation(Backend.CF, false);
       fail("Should expect the compilation to fail.");
     } catch (CompilationFailedException e) {
       assertThat(
@@ -221,26 +222,60 @@
     }
   }
 
-  public ProcessResult runDoublePerFileCompilation(boolean intermediate) throws Exception {
+  @Test
+  public void testPerFileNonIntermediateDex() throws Exception {
+    assumeTrue(parameters.isDexRuntime());
+    try {
+      runDoublePerFileCompilation(Backend.DEX, false);
+      fail("Should expect the compilation to fail.");
+    } catch (CompilationFailedException e) {
+      assertThat(
+          e.getCause().getMessage(),
+          containsString("Attempt at compiling intermediate artifact without its context"));
+    }
+  }
+
+  public ProcessResult runDoublePerFileCompilation(Backend firstRoundOutput, boolean intermediate)
+      throws Exception {
     List<byte[]> outputsRoundOne = new ArrayList<>();
-    testForD8(Backend.CF)
+    testForD8(firstRoundOutput)
         .addProgramClasses(CLASSES)
         .setMinApi(parameters.getApiLevel())
         .setIntermediate(true /* First round is always intermediate. */)
         .setProgramConsumer(
-            new ClassFileConsumer.ForwardingConsumer(null) {
-              @Override
-              public void accept(ByteDataView data, String descriptor, DiagnosticsHandler handler) {
-                outputsRoundOne.add(data.copyByteData());
-              }
-            })
+            firstRoundOutput.isCf()
+                ? new ClassFileConsumer.ForwardingConsumer(null) {
+                  @Override
+                  public void accept(
+                      ByteDataView data, String descriptor, DiagnosticsHandler handler) {
+                    outputsRoundOne.add(data.copyByteData());
+                  }
+                }
+                : new DexFilePerClassFileConsumer.ForwardingConsumer(null) {
+                  @Override
+                  public void accept(
+                      String primaryClassDescriptor,
+                      ByteDataView data,
+                      Set<String> descriptors,
+                      DiagnosticsHandler handler) {
+                    outputsRoundOne.add(data.copyByteData());
+                  }
+
+                  @Override
+                  public boolean combineSyntheticClassesWithPrimaryClass() {
+                    return false;
+                  }
+                })
         .compile();
 
     List<Path> outputsRoundTwo = new ArrayList<>();
     for (byte[] bytes : outputsRoundOne) {
       outputsRoundTwo.add(
           testForD8(parameters.getBackend())
-              .addProgramClassFileData(bytes)
+              .applyIf(
+                  firstRoundOutput.isCf(),
+                  b -> b.addProgramClassFileData(bytes),
+                  b -> b.addProgramDexFileData(bytes))
               .setMinApi(parameters.getApiLevel())
               .setIntermediate(intermediate)
               .compile()
diff --git a/tools/r8_release.py b/tools/r8_release.py
index c00c15c..56828c0 100755
--- a/tools/r8_release.py
+++ b/tools/r8_release.py
@@ -392,7 +392,7 @@
       if match_count != 3:
         print(("Could not find the previous -dev release string to replace in " +
             "METADATA. Expected to find is mentioned 3 times. Please update %s " +
-            "manually and run again with options --google " +
+            "manually and run again with options --google3 " +
             "--use-existing-work-branch.") % metadata_path)
         sys.exit(1)
       sed(version_match_regexp, options.version, metadata_path)