R8 support for Record

Bug:197081367
Change-Id: Iaf9ca3d3128815684332e9df6e8a4ccc109d0de6
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 22308ef..91f6172 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -46,6 +46,8 @@
 import com.android.tools.r8.inspector.internal.InspectorImpl;
 import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
+import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringCollection;
+import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterLibraryTypeSynthesizor;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.ir.desugar.records.RecordRewriter;
@@ -322,6 +324,19 @@
       CfUtilityMethodsForCodeOptimizations.registerSynthesizedCodeReferences(
           appView.dexItemFactory());
 
+      // Upfront desugaring generation: Generates new program classes to be added in the app.
+      CfClassSynthesizerDesugaringEventConsumer classSynthesizerEventConsumer =
+          new CfClassSynthesizerDesugaringEventConsumer();
+      CfClassSynthesizerDesugaringCollection.create(appView, null)
+          .synthesizeClasses(executorService, classSynthesizerEventConsumer);
+      if (appView.getSyntheticItems().hasPendingSyntheticClasses()) {
+        appView.setAppInfo(
+            appView
+                .appInfo()
+                .rebuildWithClassHierarchy(
+                    appView.getSyntheticItems().commit(appView.appInfo().app())));
+      }
+
       List<ProguardConfigurationRule> synthesizedProguardRules = new ArrayList<>();
       timing.begin("Strip unused code");
       RuntimeTypeCheckInfo.Builder classMergingEnqueuerExtensionBuilder =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
index afd0856..4f6dd6c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
@@ -349,13 +349,13 @@
 
     @Override
     public void acceptRecordClass(DexProgramClass recordClass) {
-      // This is called each time an instruction or a class is found to require the record class.
-      assert false : "TODO(b/179146128): To be implemented";
+      // Intentionally empty. The class will be hit by tracing if required.
     }
 
     @Override
     public void acceptRecordMethod(ProgramMethod method) {
-      assert false : "TODO(b/179146128): To be implemented";
+      // Intentionally empty. The method will be hit by the tracing in R8 as if it was
+      // present in the input code, and thus nothing needs to be done.
     }
 
     @Override
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 c4ce73e..b117828 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
@@ -114,7 +114,6 @@
     }
     this.recordRewriter = RecordRewriter.create(appView);
     if (recordRewriter != null) {
-      assert !appView.enableWholeProgramOptimizations() : "To be implemented";
       desugarings.add(recordRewriter);
     }
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
index 3f0992a..389744e 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
@@ -13,7 +13,6 @@
 import com.android.tools.r8.utils.StringUtils;
 import java.nio.file.Path;
 import java.util.List;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -63,23 +62,35 @@
   }
 
   @Test
-  public void testR8Cf() throws Exception {
-    Assume.assumeTrue(parameters.isCfRuntime());
-    Path output =
-        testForR8(parameters.getBackend())
-            .addProgramClassFileData(PROGRAM_DATA)
-            .setMinApi(parameters.getApiLevel())
-            .addKeepRules(RECORD_KEEP_RULE)
-            .addKeepMainRule(MAIN_TYPE)
-            .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
-            .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-            .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
-            .compile()
-            .writeToZip();
-    RecordTestUtils.assertRecordsAreRecords(output);
-    testForJvm()
-        .addRunClasspathFiles(output)
-        .enablePreview()
+  public void testR8() throws Exception {
+    if (parameters.isCfRuntime()) {
+      Path output =
+          testForR8(parameters.getBackend())
+              .addProgramClassFileData(PROGRAM_DATA)
+              .setMinApi(parameters.getApiLevel())
+              .addKeepRules(RECORD_KEEP_RULE)
+              .addKeepMainRule(MAIN_TYPE)
+              .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+              .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+              .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
+              .compile()
+              .writeToZip();
+      RecordTestUtils.assertRecordsAreRecords(output);
+      testForJvm()
+          .addRunClasspathFiles(output)
+          .enablePreview()
+          .run(parameters.getRuntime(), MAIN_TYPE)
+          .assertSuccessWithOutput(EXPECTED_RESULT);
+      return;
+    }
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(PROGRAM_DATA)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepRules(RECORD_KEEP_RULE)
+        .addKeepMainRule(MAIN_TYPE)
+        .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+        .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
+        .compile()
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java b/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
index 51596a1..08c9468 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
@@ -13,7 +13,6 @@
 import com.android.tools.r8.utils.StringUtils;
 import java.nio.file.Path;
 import java.util.List;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -64,23 +63,35 @@
   }
 
   @Test
-  public void testR8Cf() throws Exception {
-    Assume.assumeTrue(parameters.isCfRuntime());
-    Path output =
-        testForR8(parameters.getBackend())
-            .addProgramClassFileData(PROGRAM_DATA)
-            .setMinApi(parameters.getApiLevel())
-            .addKeepRules(RECORD_KEEP_RULE)
-            .addKeepMainRule(MAIN_TYPE)
-            .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
-            .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-            .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
-            .compile()
-            .writeToZip();
-    RecordTestUtils.assertRecordsAreRecords(output);
-    testForJvm()
-        .addRunClasspathFiles(output)
-        .enablePreview()
+  public void testR8() throws Exception {
+    if (parameters.isCfRuntime()) {
+      Path output =
+          testForR8(parameters.getBackend())
+              .addProgramClassFileData(PROGRAM_DATA)
+              .setMinApi(parameters.getApiLevel())
+              .addKeepRules(RECORD_KEEP_RULE)
+              .addKeepMainRule(MAIN_TYPE)
+              .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+              .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+              .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
+              .compile()
+              .writeToZip();
+      RecordTestUtils.assertRecordsAreRecords(output);
+      testForJvm()
+          .addRunClasspathFiles(output)
+          .enablePreview()
+          .run(parameters.getRuntime(), MAIN_TYPE)
+          .assertSuccessWithOutput(EXPECTED_RESULT);
+      return;
+    }
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(PROGRAM_DATA)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepRules(RECORD_KEEP_RULE)
+        .addKeepMainRule(MAIN_TYPE)
+        .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+        .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
+        .compile()
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
   }