Collect missing class references from D8 part of R8 partial

The missing class references are only collected when assertions are enabled.

Bug: b/391572031
Change-Id: Idf4af12bf2702b21d8f6501ac6ce1ff10fe063a7
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java b/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java
index a5cd867..5ea8d60 100644
--- a/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java
@@ -24,7 +24,6 @@
 import com.android.tools.r8.profile.art.ArtProfileCollection;
 import com.android.tools.r8.profile.art.ArtProfileMethodRule;
 import com.android.tools.r8.profile.startup.profile.StartupProfile;
-import com.android.tools.r8.shaking.MissingClasses;
 import com.android.tools.r8.synthesis.SyntheticItems;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.MapUtils;
@@ -36,6 +35,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 public abstract class R8PartialSubCompilationConfiguration {
 
@@ -187,6 +187,14 @@
     private List<KeepDeclaration> keepDeclarations;
     private StartupProfile startupProfile;
 
+    // Stores the missing class references from the D8 compilation unit in R8 partial.
+    // We use this to ensure that calling AppInfoWithLiveness#definitionFor does not fail
+    // when looking up a missing class type from the D8 part (which happens during library
+    // desugaring).
+    //
+    // Always empty when assertions are disabled.
+    public final Set<DexType> d8MissingClasses = ConcurrentHashMap.newKeySet();
+
     public R8PartialR8SubCompilationConfiguration(
         ArtProfileCollection artProfiles,
         ClassToFeatureSplitMap classToFeatureSplitMap,
@@ -255,7 +263,6 @@
               .addProgramClasses(dexingOutputClasses.values())
               .build();
       appView.rebuildAppInfo(newApp);
-      assert amendMissingClasses(appView);
     }
 
     public void uncommitDexingOutputClasses(AppView<? extends AppInfoWithClassHierarchy> appView) {
@@ -272,7 +279,6 @@
               .addClasspathClasses(newClasspathClasses)
               .build();
       appView.rebuildAppInfo(newApp);
-      assert amendMissingClasses(appView);
     }
 
     public boolean hasD8DefinitionFor(DexReference reference) {
@@ -289,24 +295,6 @@
       return hasD8DefinitionFor(definition.getReference());
     }
 
-    private boolean amendMissingClasses(AppView<? extends AppInfoWithClassHierarchy> appView) {
-      if (appView.hasLiveness()) {
-        MissingClasses.Builder missingClassesBuilder =
-            appView.appInfo().getMissingClasses().builder();
-        for (DexProgramClass clazz : dexingOutputClasses.values()) {
-          clazz.forEachImmediateSuperClassMatching(
-              appView.app(),
-              (supertype, superclass) -> superclass == null,
-              (supertype, superclass) ->
-                  missingClassesBuilder.addNewMissingClass(supertype, clazz));
-        }
-        appView
-            .appInfoWithLiveness()
-            .setMissingClasses(missingClassesBuilder.ignoreMissingClasses());
-      }
-      return true;
-    }
-
     @Override
     public boolean isR8() {
       return true;
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialUseCollector.java b/src/main/java/com/android/tools/r8/partial/R8PartialUseCollector.java
index bb8af7d..a871664 100644
--- a/src/main/java/com/android/tools/r8/partial/R8PartialUseCollector.java
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialUseCollector.java
@@ -116,7 +116,7 @@
 
     @Override
     public void acceptType(TracedClass tracedClass, DiagnosticsHandler handler) {
-      assert tracedClass.isMissingDefinition();
+      assert false;
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index d98e17f..110abf1 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -56,6 +56,7 @@
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
 import com.android.tools.r8.naming.SeedMapper;
+import com.android.tools.r8.partial.R8PartialSubCompilationConfiguration;
 import com.android.tools.r8.repackaging.RepackagingUtils;
 import com.android.tools.r8.shaking.KeepInfo.Joiner;
 import com.android.tools.r8.synthesis.CommittedItems;
@@ -523,11 +524,15 @@
   @Override
   public DexClass definitionFor(DexType type) {
     DexClass definition = super.definitionFor(type);
+    R8PartialSubCompilationConfiguration subCompilationConfiguration =
+        options().partialSubCompilationConfiguration;
     assert definition != null
             || deadProtoTypes.contains(type)
             || getMissingClasses().contains(type)
             // TODO(b/150736225): Not sure how to remove these.
             || isVivifiedType(type)
+            || (subCompilationConfiguration != null
+                && subCompilationConfiguration.asR8().d8MissingClasses.contains(type))
         : "Failed lookup of non-missing type: " + type;
     return definition;
   }
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index 6eec044..5eab51c 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -9,6 +9,7 @@
 import static java.util.Collections.emptyMap;
 
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.diagnostic.DefinitionContext;
 import com.android.tools.r8.errors.AssumeNoSideEffectsRuleForObjectMembersDiagnostic;
 import com.android.tools.r8.errors.AssumeValuesMissingStaticFieldDiagnostic;
 import com.android.tools.r8.errors.InlinableStaticFinalFieldPreconditionDiagnostic;
@@ -258,6 +259,20 @@
                 rootLibraryTypes.add(definition.getContextType());
               }
             }
+
+            @Override
+            protected void notifyMissingClass(DexType type, DefinitionContext referencedFrom) {
+              assert recordMissingClassWhenAssertionsEnabled(type);
+            }
+
+            private boolean recordMissingClassWhenAssertionsEnabled(DexType type) {
+              // Record missing class references from the D8 compilation unit in R8 partial.
+              // We use this to ensure that calling AppInfoWithLiveness#definitionFor does not fail
+              // when looking up a missing class type from the D8 part (which happens during library
+              // desugaring).
+              options.partialSubCompilationConfiguration.asR8().d8MissingClasses.add(type);
+              return true;
+            }
           };
       useCollector.run(executorService);
 
diff --git a/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java b/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java
index 6bcaf98..257ff73 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java
@@ -113,6 +113,12 @@
     consumer.acceptType(tracedClass, diagnostics);
   }
 
+  protected void notifyMissingClass(DexType type, DefinitionContext referencedFrom) {
+    TracedClassImpl missingClass = new TracedClassImpl(type, referencedFrom);
+    collectMissingClass(missingClass);
+    consumer.acceptType(missingClass, diagnostics);
+  }
+
   protected void notifyPresentField(DexClassAndField field, DefinitionContext referencedFrom) {
     TracedFieldImpl tracedField = new TracedFieldImpl(field, referencedFrom);
     consumer.acceptField(tracedField, diagnostics);
@@ -176,9 +182,7 @@
     if (result.hasClassResolutionResult()) {
       result.forEachClassResolutionResult(resolvedClassesConsumer);
     } else {
-      TracedClassImpl missingClass = new TracedClassImpl(type, referencedFrom);
-      collectMissingClass(missingClass);
-      consumer.acceptType(missingClass, diagnostics);
+      notifyMissingClass(type, referencedFrom);
     }
   }
 
@@ -630,9 +634,7 @@
                   }
                 });
           } else {
-            TracedClassImpl missingClass = new TracedClassImpl(interfaceType, referencedFrom);
-            collectMissingClass(missingClass);
-            consumer.acceptType(missingClass, diagnostics);
+            notifyMissingClass(interfaceType, referencedFrom);
           }
         }
       }