Unify unconditional and dependent minimum keep info

Bug: 192924387
Change-Id: Icd8d0e63c3eef02ee1760a9eab6fd12bd78e85e7
diff --git a/src/main/java/com/android/tools/r8/graph/ClassDefinition.java b/src/main/java/com/android/tools/r8/graph/ClassDefinition.java
index da0f128..589dd76 100644
--- a/src/main/java/com/android/tools/r8/graph/ClassDefinition.java
+++ b/src/main/java/com/android/tools/r8/graph/ClassDefinition.java
@@ -28,11 +28,6 @@
     return true;
   }
 
-  @Override
-  default ClassDefinition asClass() {
-    return this;
-  }
-
   boolean isClasspathClass();
 
   DexClasspathClass asClasspathClass();
@@ -40,8 +35,4 @@
   boolean isLibraryClass();
 
   DexLibraryClass asLibraryClass();
-
-  boolean isProgramClass();
-
-  DexProgramClass asProgramClass();
 }
diff --git a/src/main/java/com/android/tools/r8/graph/ClasspathMember.java b/src/main/java/com/android/tools/r8/graph/ClasspathMember.java
index 8fad10f..1919491 100644
--- a/src/main/java/com/android/tools/r8/graph/ClasspathMember.java
+++ b/src/main/java/com/android/tools/r8/graph/ClasspathMember.java
@@ -7,6 +7,7 @@
 public interface ClasspathMember<D extends DexEncodedMember<D, R>, R extends DexMember<D, R>>
     extends ClasspathDefinition {
 
+  @Override
   D getDefinition();
 
   DexClasspathClass getHolder();
diff --git a/src/main/java/com/android/tools/r8/graph/Definition.java b/src/main/java/com/android/tools/r8/graph/Definition.java
index 7e42398..b3dcc3a 100644
--- a/src/main/java/com/android/tools/r8/graph/Definition.java
+++ b/src/main/java/com/android/tools/r8/graph/Definition.java
@@ -24,8 +24,12 @@
 
   ProgramDerivedContext asProgramDerivedContext(ProgramDerivedContext witness);
 
+  AccessFlags<?> getAccessFlags();
+
   DexType getContextType();
 
+  DexDefinition getDefinition();
+
   Origin getOrigin();
 
   DexReference getReference();
@@ -34,7 +38,7 @@
     return false;
   }
 
-  default ClassDefinition asClass() {
+  default DexClass asClass() {
     return null;
   }
 
@@ -46,6 +50,14 @@
     return null;
   }
 
+  default boolean isMember() {
+    return !isClass();
+  }
+
+  default DexClassAndMember<?, ?> asMember() {
+    return null;
+  }
+
   default boolean isMethod() {
     return false;
   }
@@ -54,6 +66,54 @@
     return null;
   }
 
+  default boolean isClasspathField() {
+    return false;
+  }
+
+  default ClasspathField asClasspathField() {
+    return null;
+  }
+
+  default boolean isClasspathMember() {
+    return false;
+  }
+
+  default boolean isClasspathMethod() {
+    return false;
+  }
+
+  default ClasspathMethod asClasspathMethod() {
+    return null;
+  }
+
+  default boolean isLibraryField() {
+    return false;
+  }
+
+  default LibraryField asLibraryField() {
+    return null;
+  }
+
+  default boolean isLibraryMember() {
+    return false;
+  }
+
+  default boolean isLibraryMethod() {
+    return false;
+  }
+
+  default LibraryMethod asLibraryMethod() {
+    return null;
+  }
+
+  default boolean isProgramClass() {
+    return false;
+  }
+
+  default DexProgramClass asProgramClass() {
+    return null;
+  }
+
   default boolean isProgramDefinition() {
     return false;
   }
@@ -61,4 +121,28 @@
   default ProgramDefinition asProgramDefinition() {
     return null;
   }
+
+  default boolean isProgramField() {
+    return false;
+  }
+
+  default ProgramField asProgramField() {
+    return null;
+  }
+
+  default boolean isProgramMember() {
+    return false;
+  }
+
+  default ProgramMember<?, ?> asProgramMember() {
+    return null;
+  }
+
+  default boolean isProgramMethod() {
+    return false;
+  }
+
+  default ProgramMethod asProgramMethod() {
+    return null;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 50362b0..f3937c2 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -676,6 +676,11 @@
   }
 
   @Override
+  public DexClass asClass() {
+    return this;
+  }
+
+  @Override
   public boolean isDexClass() {
     return true;
   }
@@ -737,6 +742,11 @@
   }
 
   @Override
+  public DexClass getDefinition() {
+    return this;
+  }
+
+  @Override
   public Origin getOrigin() {
     return this.origin;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndField.java b/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
index 2c78b93..30179b3 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
@@ -55,27 +55,8 @@
     return this;
   }
 
-  public boolean isClasspathField() {
-    return false;
-  }
-
-  public ClasspathField asClasspathField() {
-    return null;
-  }
-
-  public boolean isLibraryField() {
-    return false;
-  }
-
-  public LibraryField asLibraryField() {
-    return null;
-  }
-
-  public boolean isProgramField() {
-    return false;
-  }
-
-  public ProgramField asProgramField() {
-    return null;
+  @Override
+  public DexClassAndField asMember() {
+    return this;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
index 52cb7a9..f82bcbc 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
@@ -22,8 +22,6 @@
     this.definition = definition;
   }
 
-  public abstract AccessFlags<?> getAccessFlags();
-
   public final DexAnnotationSet getAnnotations() {
     return definition.annotations();
   }
@@ -41,6 +39,7 @@
     return holder.type;
   }
 
+  @Override
   public D getDefinition() {
     return definition;
   }
@@ -63,18 +62,6 @@
     return holder.origin;
   }
 
-  public boolean isClasspathMember() {
-    return false;
-  }
-
-  public boolean isLibraryMember() {
-    return false;
-  }
-
-  public boolean isProgramMember() {
-    return false;
-  }
-
   public String toSourceString() {
     return getReference().toSourceString();
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
index 2f18405..41845a0 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
@@ -98,31 +98,12 @@
   }
 
   @Override
-  public DexClassAndMethod asMethod() {
+  public DexClassAndMethod asMember() {
     return this;
   }
 
-  public boolean isClasspathMethod() {
-    return false;
-  }
-
-  public ClasspathMethod asClasspathMethod() {
-    return null;
-  }
-
-  public boolean isLibraryMethod() {
-    return false;
-  }
-
-  public LibraryMethod asLibraryMethod() {
-    return null;
-  }
-
-  public boolean isProgramMethod() {
-    return false;
-  }
-
-  public ProgramMethod asProgramMethod() {
-    return null;
+  @Override
+  public DexClassAndMethod asMethod() {
+    return this;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexDefinition.java b/src/main/java/com/android/tools/r8/graph/DexDefinition.java
index 25c339e..9b69a2f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDefinition.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDefinition.java
@@ -58,6 +58,10 @@
         annotations().rewrite(annotation -> rewriter.apply(annotation, AnnotatedKind.from(this))));
   }
 
+  public DexClass asClass() {
+    return null;
+  }
+
   public boolean isDexClass() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/LibraryMember.java b/src/main/java/com/android/tools/r8/graph/LibraryMember.java
index bf6bb03..b887324 100644
--- a/src/main/java/com/android/tools/r8/graph/LibraryMember.java
+++ b/src/main/java/com/android/tools/r8/graph/LibraryMember.java
@@ -7,6 +7,7 @@
 public interface LibraryMember<D extends DexEncodedMember<D, R>, R extends DexMember<D, R>>
     extends LibraryDefinition {
 
+  @Override
   D getDefinition();
 
   DexLibraryClass getHolder();
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java b/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
index c1dedd5..b36e87c 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
@@ -19,6 +19,16 @@
   }
 
   @Override
+  default ProgramField asField() {
+    return null;
+  }
+
+  @Override
+  default ProgramMethod asMethod() {
+    return null;
+  }
+
+  @Override
   default ProgramDerivedContext asProgramDerivedContext(ProgramDerivedContext witness) {
     return this;
   }
@@ -34,18 +44,6 @@
 
   DexProgramClass getContextClass();
 
-  AccessFlags<?> getAccessFlags();
-
-  DexDefinition getDefinition();
-
-  default boolean isProgramClass() {
-    return false;
-  }
-
-  default DexProgramClass asProgramClass() {
-    return null;
-  }
-
   @Override
   default boolean isProgramDefinition() {
     return true;
@@ -55,28 +53,4 @@
   default ProgramDefinition asProgramDefinition() {
     return this;
   }
-
-  default boolean isProgramField() {
-    return false;
-  }
-
-  default ProgramField asProgramField() {
-    return null;
-  }
-
-  default boolean isProgramMember() {
-    return false;
-  }
-
-  default ProgramMember<?, ?> asProgramMember() {
-    return null;
-  }
-
-  default boolean isProgramMethod() {
-    return false;
-  }
-
-  default ProgramMethod asProgramMethod() {
-    return null;
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramField.java b/src/main/java/com/android/tools/r8/graph/ProgramField.java
index aec6be0..d53cb1c 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramField.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramField.java
@@ -38,6 +38,11 @@
   }
 
   @Override
+  public ProgramField asField() {
+    return this;
+  }
+
+  @Override
   public ProgramField asProgramField() {
     return this;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
index 5faf268..a34b49d 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -83,6 +83,11 @@
   }
 
   @Override
+  public ProgramMethod asMethod() {
+    return this;
+  }
+
+  @Override
   public ProgramMethod asProgramMethod() {
     return this;
   }
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 822a7dc..d0ffde6 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -116,6 +116,7 @@
 import com.android.tools.r8.shaking.EnqueuerEvent.ClassEnqueuerEvent;
 import com.android.tools.r8.shaking.EnqueuerEvent.InstantiatedClassEnqueuerEvent;
 import com.android.tools.r8.shaking.EnqueuerEvent.LiveClassEnqueuerEvent;
+import com.android.tools.r8.shaking.EnqueuerEvent.UnconditionalKeepInfoEvent;
 import com.android.tools.r8.shaking.EnqueuerWorklist.EnqueuerAction;
 import com.android.tools.r8.shaking.GraphReporter.KeepReasonWitness;
 import com.android.tools.r8.shaking.KeepInfoCollection.MutableKeepInfoCollection;
@@ -387,18 +388,6 @@
   private final MutableKeepInfoCollection keepInfo = new MutableKeepInfoCollection();
 
   /**
-   * The minimum keep info for classes, fields, and methods. The minimum keep info for a program
-   * item should be applied to the {@link KeepInfo} of that item when the item becomes live.
-   */
-  private final Map<DexProgramClass, KeepClassInfo.Joiner> minimumKeepClassInfo =
-      new IdentityHashMap<>();
-
-  private final ProgramFieldMap<KeepFieldInfo.Joiner> minimumKeepFieldInfo =
-      ProgramFieldMap.create();
-  private final ProgramMethodMap<KeepMethodInfo.Joiner> minimumKeepMethodInfo =
-      ProgramMethodMap.create();
-
-  /**
    * Conditional minimum keep info for classes, fields, and methods, which should only be applied if
    * the outermost {@link EnqueuerEvent} is triggered during tracing (e.g., class X becomes live).
    */
@@ -2290,9 +2279,9 @@
     }
   }
 
-  private void shouldNotBeMinified(DexReference reference) {
+  private void shouldNotBeMinified(ProgramDefinition definition) {
     if (options.isMinificationEnabled()) {
-      rootSet.shouldNotBeMinified(reference);
+      rootSet.shouldNotBeMinified(definition);
     }
   }
 
@@ -2300,17 +2289,17 @@
     KeepReasonWitness keepReasonWitness = graphReporter.registerClass(clazz, keepReason);
     markClassAsInstantiatedWithCompatRule(clazz.asProgramClass(), () -> keepReasonWitness);
     keepInfo.keepClass(clazz);
-    shouldNotBeMinified(clazz.getReference());
+    shouldNotBeMinified(clazz);
     clazz.forEachProgramField(
         field -> {
           keepInfo.keepField(field);
-          shouldNotBeMinified(field.getReference());
+          shouldNotBeMinified(field);
           markFieldAsKept(field, keepReasonWitness);
         });
     clazz.forEachProgramMethod(
         method -> {
           keepInfo.keepMethod(method);
-          shouldNotBeMinified(method.getReference());
+          shouldNotBeMinified(method);
           markMethodAsKept(method, keepReasonWitness);
         });
   }
@@ -2836,7 +2825,7 @@
   }
 
   public boolean isPreconditionForMinimumKeepInfoSatisfied(EnqueuerEvent preconditionEvent) {
-    if (preconditionEvent == null) {
+    if (preconditionEvent == null || preconditionEvent.isUnconditionalKeepInfoEvent()) {
       return true;
     }
     if (preconditionEvent.isClassEvent()) {
@@ -3039,7 +3028,7 @@
       // marking for not renaming it is in the root set.
       workList.enqueueMarkMethodKeptAction(valuesMethod, reason);
       keepInfo.joinMethod(valuesMethod, joiner -> joiner.pin().disallowMinification());
-      shouldNotBeMinified(valuesMethod.getReference());
+      shouldNotBeMinified(valuesMethod);
     }
   }
 
@@ -3187,9 +3176,13 @@
   }
 
   private void applyMinimumKeepInfo(DexProgramClass clazz) {
-    KeepClassInfo.Joiner minimumKeepInfoForClass = minimumKeepClassInfo.remove(clazz);
-    if (minimumKeepInfoForClass != null) {
-      keepInfo.joinClass(clazz, info -> info.merge(minimumKeepInfoForClass));
+    Map<DexProgramClass, KeepClassInfo.Joiner> minimumKeepClassInfo =
+        dependentMinimumKeepClassInfo.get(UnconditionalKeepInfoEvent.get());
+    if (minimumKeepClassInfo != null) {
+      KeepClassInfo.Joiner minimumKeepInfoForClass = minimumKeepClassInfo.remove(clazz);
+      if (minimumKeepInfoForClass != null) {
+        keepInfo.joinClass(clazz, info -> info.merge(minimumKeepInfoForClass));
+      }
     }
   }
 
@@ -3198,7 +3191,8 @@
     if (liveTypes.contains(clazz)) {
       keepInfo.joinClass(clazz, info -> info.merge(minimumKeepInfo));
     } else {
-      minimumKeepClassInfo
+      dependentMinimumKeepClassInfo
+          .computeIfAbsent(UnconditionalKeepInfoEvent.get(), ignoreKey(IdentityHashMap::new))
           .computeIfAbsent(clazz, ignoreKey(KeepClassInfo::newEmptyJoiner))
           .merge(minimumKeepInfo);
     }
@@ -3219,9 +3213,13 @@
   }
 
   private void applyMinimumKeepInfo(ProgramField field) {
-    KeepFieldInfo.Joiner minimumKeepInfoForField = minimumKeepFieldInfo.remove(field);
-    if (minimumKeepInfoForField != null) {
-      keepInfo.joinField(field, info -> info.merge(minimumKeepInfoForField));
+    ProgramFieldMap<KeepFieldInfo.Joiner> minimumKeepFieldInfo =
+        dependentMinimumKeepFieldInfo.get(UnconditionalKeepInfoEvent.get());
+    if (minimumKeepFieldInfo != null) {
+      KeepFieldInfo.Joiner minimumKeepInfoForField = minimumKeepFieldInfo.remove(field);
+      if (minimumKeepInfoForField != null) {
+        keepInfo.joinField(field, info -> info.merge(minimumKeepInfoForField));
+      }
     }
   }
 
@@ -3230,7 +3228,8 @@
     if (liveFields.contains(field)) {
       keepInfo.joinField(field, info -> info.merge(minimumKeepInfo));
     } else {
-      minimumKeepFieldInfo
+      dependentMinimumKeepFieldInfo
+          .computeIfAbsent(UnconditionalKeepInfoEvent.get(), ignoreKey(ProgramFieldMap::create))
           .computeIfAbsent(field, ignoreKey(KeepFieldInfo::newEmptyJoiner))
           .merge(minimumKeepInfo);
     }
@@ -3249,9 +3248,13 @@
   }
 
   private void applyMinimumKeepInfo(ProgramMethod method) {
-    KeepMethodInfo.Joiner minimumKeepInfoForMethod = minimumKeepMethodInfo.remove(method);
-    if (minimumKeepInfoForMethod != null) {
-      keepInfo.joinMethod(method, info -> info.merge(minimumKeepInfoForMethod));
+    ProgramMethodMap<KeepMethodInfo.Joiner> minimumKeepMethodInfo =
+        dependentMinimumKeepMethodInfo.get(UnconditionalKeepInfoEvent.get());
+    if (minimumKeepMethodInfo != null) {
+      KeepMethodInfo.Joiner minimumKeepInfoForMethod = minimumKeepMethodInfo.remove(method);
+      if (minimumKeepInfoForMethod != null) {
+        keepInfo.joinMethod(method, info -> info.merge(minimumKeepInfoForMethod));
+      }
     }
   }
 
@@ -3260,7 +3263,8 @@
     if (liveMethods.contains(method) || targetedMethods.contains(method)) {
       keepInfo.joinMethod(method, info -> info.merge(minimumKeepInfo));
     } else {
-      minimumKeepMethodInfo
+      dependentMinimumKeepMethodInfo
+          .computeIfAbsent(UnconditionalKeepInfoEvent.get(), ignoreKey(ProgramMethodMap::create))
           .computeIfAbsent(method, ignoreKey(KeepMethodInfo::newEmptyJoiner))
           .merge(minimumKeepInfo);
     }
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java
index 6f68a59..ba7ee40 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java
@@ -33,6 +33,10 @@
     return null;
   }
 
+  public boolean isUnconditionalKeepInfoEvent() {
+    return false;
+  }
+
   public abstract static class ClassEnqueuerEvent extends EnqueuerEvent {
 
     private final DexType clazz;
@@ -123,4 +127,20 @@
       return (getType().hashCode() << 1) | 1;
     }
   }
+
+  public static class UnconditionalKeepInfoEvent extends EnqueuerEvent {
+
+    private static final UnconditionalKeepInfoEvent INSTANCE = new UnconditionalKeepInfoEvent();
+
+    private UnconditionalKeepInfoEvent() {}
+
+    public static UnconditionalKeepInfoEvent get() {
+      return INSTANCE;
+    }
+
+    @Override
+    public boolean isUnconditionalKeepInfoEvent() {
+      return true;
+    }
+  }
 }
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 28094a1..03e9de3 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -36,6 +36,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMember;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -51,6 +52,7 @@
 import com.android.tools.r8.shaking.DelayedRootSetActionItem.InterfaceMethodSyntheticBridgeAction;
 import com.android.tools.r8.shaking.EnqueuerEvent.InstantiatedClassEnqueuerEvent;
 import com.android.tools.r8.shaking.EnqueuerEvent.LiveClassEnqueuerEvent;
+import com.android.tools.r8.shaking.EnqueuerEvent.UnconditionalKeepInfoEvent;
 import com.android.tools.r8.shaking.KeepInfo.Joiner;
 import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.Consumer3;
@@ -96,37 +98,23 @@
 
 public class RootSetUtils {
 
-  static void modifyMinimumKeepInfo(
-      Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo,
-      DexDefinition definition,
-      Consumer<Joiner<?, ?, ?>> consumer) {
-    modifyMinimumKeepInfo(minimumKeepInfo, definition.getReference(), consumer);
-  }
-
-  static void modifyMinimumKeepInfo(
-      Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo,
-      DexReference reference,
-      Consumer<Joiner<?, ?, ?>> consumer) {
-    Joiner<?, ?, ?> joiner =
-        minimumKeepInfo.computeIfAbsent(
-            reference,
-            key ->
-                key.apply(
-                    clazz -> KeepClassInfo.newEmptyJoiner(),
-                    field -> KeepFieldInfo.newEmptyJoiner(),
-                    method -> KeepMethodInfo.newEmptyJoiner()));
-    consumer.accept(joiner);
-    assert !joiner.isBottom();
-  }
-
   static void modifyDependentMinimumKeepInfo(
       Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>> dependentMinimumKeepInfo,
       EnqueuerEvent event,
-      DexDefinition dependent,
+      ProgramDefinition dependent,
       Consumer<Joiner<?, ?, ?>> consumer) {
-    Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfoForDependants =
-        dependentMinimumKeepInfo.computeIfAbsent(event, ignoreKey(IdentityHashMap::new));
-    modifyMinimumKeepInfo(minimumKeepInfoForDependants, dependent, consumer);
+    Joiner<?, ?, ?> joiner =
+        dependentMinimumKeepInfo
+            .computeIfAbsent(event, ignoreKey(IdentityHashMap::new))
+            .computeIfAbsent(
+                dependent.getReference(),
+                key ->
+                    key.apply(
+                        clazz -> KeepClassInfo.newEmptyJoiner(),
+                        field -> KeepFieldInfo.newEmptyJoiner(),
+                        method -> KeepMethodInfo.newEmptyJoiner()));
+    consumer.accept(joiner);
+    assert !joiner.isBottom();
   }
 
   public static class RootSetBuilder {
@@ -136,8 +124,6 @@
     private final DirectMappedDexApplication application;
     private final Iterable<? extends ProguardConfigurationRule> rules;
     private final MutableItemsWithRules noShrinking = new MutableItemsWithRules();
-    private final Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo =
-        new IdentityHashMap<>();
     private final Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>>
         dependentMinimumKeepInfo = new HashMap<>();
     private final LinkedHashMap<DexReference, DexReference> reasonAsked = new LinkedHashMap<>();
@@ -401,7 +387,6 @@
           : "A method cannot be marked as both -neverinline and -forceinline/-alwaysinline.";
       return new RootSet(
           noShrinking,
-          minimumKeepInfo,
           dependentMinimumKeepInfo,
           ImmutableList.copyOf(reasonAsked.values()),
           ImmutableList.copyOf(checkDiscarded.values()),
@@ -497,7 +482,6 @@
           neverInlineDueToSingleCaller,
           neverClassInline,
           noShrinking,
-          minimumKeepInfo,
           dependentMinimumKeepInfo,
           dependentNoShrinking,
           dependentKeepClassCompatRule,
@@ -686,8 +670,7 @@
                   }
                   DexProgramClass precondition =
                       testAndGetPrecondition(methodToKeep.getDefinition(), preconditionSupplier);
-                  rootSetBuilder.addItemToSets(
-                      methodToKeep.getDefinition(), context, rule, precondition, ifRule);
+                  rootSetBuilder.addItemToSets(methodToKeep, context, rule, precondition, ifRule);
                 }));
       }
     }
@@ -1094,7 +1077,7 @@
           if (methodsMarked != null) {
             methodsMarked.add(MethodSignatureEquivalence.get().wrap(method.getReference()));
           }
-          addItemToSets(method.getDefinition(), context, rule, precondition, ifRule);
+          addItemToSets(method, context, rule, precondition, ifRule);
         }
       }
     }
@@ -1110,7 +1093,7 @@
           if (Log.ENABLED) {
             Log.verbose(getClass(), "Marking field `%s` due to `%s { %s }`.", field, context, rule);
           }
-          addItemToSets(field.getDefinition(), context, rule, precondition, ifRule);
+          addItemToSets(field, context, rule, precondition, ifRule);
         }
       }
     }
@@ -1124,7 +1107,7 @@
 
     // TODO(b/192636793): This needs to use the precondition.
     private void includeDescriptor(
-        DexDefinition item,
+        ProgramDefinition item,
         DexType type,
         ProguardKeepRuleBase context,
         DexProgramClass precondition) {
@@ -1149,187 +1132,58 @@
 
       // Disable minification for the type.
       if (appView.options().isMinificationEnabled()) {
-        modifyMinimumKeepInfo(minimumKeepInfo, clazz, Joiner::disallowMinification);
+        modifyDependentMinimumKeepInfo(
+            dependentMinimumKeepInfo,
+            UnconditionalKeepInfoEvent.get(),
+            clazz,
+            Joiner::disallowMinification);
       }
     }
 
     private void includeDescriptorClasses(
-        DexDefinition item, ProguardKeepRuleBase context, DexProgramClass precondition) {
-      if (item.isDexEncodedMethod()) {
-        DexEncodedMethod method = item.asDexEncodedMethod();
-        includeDescriptor(item, method.getReturnType(), context, precondition);
+        ProgramDefinition item, ProguardKeepRuleBase context, DexProgramClass precondition) {
+      if (item.isMethod()) {
+        ProgramMethod method = item.asProgramMethod();
+        includeDescriptor(method, method.getReturnType(), context, precondition);
         for (DexType value : method.getParameters()) {
-          includeDescriptor(item, value, context, precondition);
+          includeDescriptor(method, value, context, precondition);
         }
-      } else if (item.isDexEncodedField()) {
-        DexEncodedField field = item.asDexEncodedField();
-        includeDescriptor(item, field.getType(), context, precondition);
+      } else if (item.isField()) {
+        ProgramField field = item.asProgramField();
+        includeDescriptor(field, field.getType(), context, precondition);
       } else {
-        assert item.isDexClass();
+        assert item.isClass();
       }
     }
 
     private synchronized void addItemToSets(
-        DexDefinition item,
+        Definition item,
         ProguardConfigurationRule context,
         ProguardMemberRule rule,
         DexProgramClass precondition,
         ProguardIfRule ifRule) {
       if (context instanceof ProguardKeepRule) {
-        if (item.isDexEncodedField()) {
-          DexEncodedField encodedField = item.asDexEncodedField();
-          if (encodedField.getOptimizationInfo().cannotBeKept()) {
-            // We should only ever get here with if rules.
-            assert ifRule != null;
-            return;
-          }
-        } else if (item.isDexEncodedMethod()) {
-          DexEncodedMethod encodedMethod = item.asDexEncodedMethod();
-          if (encodedMethod.isClassInitializer() && !options.debug) {
-            // Don't keep class initializers.
-            return;
-          }
-          if (encodedMethod.getOptimizationInfo().cannotBeKept()) {
-            // We should only ever get here with if rules.
-            assert ifRule != null;
-            return;
-          }
-          if (options.isGeneratingDex()
-              && encodedMethod.getReference().isLambdaDeserializeMethod(appView.dexItemFactory())) {
-            // Don't keep lambda deserialization methods.
-            return;
-          }
-          // If desugaring is enabled, private and static interface methods will be moved to a
-          // companion class. So we don't need to add them to the root set in the beginning.
-          if (options.isInterfaceMethodDesugaringEnabled()
-              && encodedMethod.hasCode()
-              && (encodedMethod.isPrivateMethod() || encodedMethod.isStaticMember())) {
-            DexClass holder = appView.definitionFor(encodedMethod.getHolderType());
-            if (holder != null && holder.isInterface()) {
-              if (rule.isSpecific()) {
-                options.reporter.warning(
-                    new StringDiagnostic(
-                        "The rule `"
-                            + rule
-                            + "` is ignored because the targeting interface method `"
-                            + encodedMethod.getReference().toSourceString()
-                            + "` will be desugared."));
-              }
-              return;
-            }
-          }
-        }
-
-        // The reason for keeping should link to the conditional rule as a whole, if present.
-        ProguardKeepRuleBase keepRule = ifRule != null ? ifRule : (ProguardKeepRuleBase) context;
-
-        // The modifiers are specified on the actual keep rule (ie, the consequent/context).
-        ProguardKeepRuleModifiers modifiers = ((ProguardKeepRule) context).getModifiers();
-        if (modifiers.isBottom()) {
-          // This rule is a no-op.
+        if (!item.isProgramDefinition()) {
+          // Keep rules do not apply to non-program items.
           return;
         }
-
-        // In compatibility mode, for a match on instance members a referenced class becomes live.
-        if (options.forceProguardCompatibility
-            && !modifiers.allowsShrinking
-            && precondition != null
-            && precondition.isDexClass()) {
-          if (!item.isDexClass() && !item.isStaticMember()) {
-            dependentKeepClassCompatRule
-                .computeIfAbsent(precondition.asDexClass().getType(), i -> new HashSet<>())
-                .add(keepRule);
-            context.markAsUsed();
-          }
-        }
-
-        // TODO(b/192636793): Remove the noShrinking and dependentNoShrinking collections. A
-        //  prerequisite for this is that the ProguardKeepRule instances are added to the KeepInfo,
-        //  since this is needed for the -whyareyoukeeping graph.
-        if (!modifiers.allowsShrinking) {
-          if (precondition != null) {
-            dependentNoShrinking
-                .computeIfAbsent(precondition.getReference(), x -> new MutableItemsWithRules())
-                .addReferenceWithRule(item.getReference(), keepRule);
-          } else {
-            noShrinking.addReferenceWithRule(item.getReference(), keepRule);
-          }
-          context.markAsUsed();
-        }
-
-        EnqueuerEvent preconditionEvent;
-        if (precondition != null) {
-          preconditionEvent =
-              item.getAccessFlags().isStatic()
-                  ? new LiveClassEnqueuerEvent(precondition)
-                  : new InstantiatedClassEnqueuerEvent(precondition);
-        } else {
-          preconditionEvent = null;
-        }
-
-        if (appView.options().isAnnotationRemovalEnabled() && !modifiers.allowsAnnotationRemoval) {
-          if (precondition != null) {
-            modifyDependentMinimumKeepInfo(
-                dependentMinimumKeepInfo,
-                preconditionEvent,
-                item,
-                Joiner::disallowAnnotationRemoval);
-          } else {
-            modifyMinimumKeepInfo(minimumKeepInfo, item, Joiner::disallowAnnotationRemoval);
-          }
-          context.markAsUsed();
-        }
-
-        if (appView.options().isMinificationEnabled() && !modifiers.allowsObfuscation) {
-          if (precondition != null) {
-            modifyDependentMinimumKeepInfo(
-                dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowMinification);
-          } else {
-            modifyMinimumKeepInfo(minimumKeepInfo, item, Joiner::disallowMinification);
-          }
-          context.markAsUsed();
-        }
-
-        if (appView.options().isOptimizationEnabled() && !modifiers.allowsOptimization) {
-          if (precondition != null) {
-            modifyDependentMinimumKeepInfo(
-                dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowOptimization);
-          } else {
-            modifyMinimumKeepInfo(minimumKeepInfo, item, Joiner::disallowOptimization);
-          }
-          context.markAsUsed();
-        }
-
-        if (appView.options().isShrinking() && !modifiers.allowsShrinking) {
-          if (precondition != null) {
-            modifyDependentMinimumKeepInfo(
-                dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowShrinking);
-          } else {
-            modifyMinimumKeepInfo(minimumKeepInfo, item, Joiner::disallowShrinking);
-          }
-          context.markAsUsed();
-        }
-
-        if (modifiers.includeDescriptorClasses) {
-          includeDescriptorClasses(item, keepRule, precondition);
-          context.markAsUsed();
-        }
+        evaluateKeepRule(item.asProgramDefinition(), context, rule, precondition, ifRule);
       } else if (context instanceof ProguardAssumeMayHaveSideEffectsRule) {
         mayHaveSideEffects.put(item.getReference(), rule);
         context.markAsUsed();
       } else if (context instanceof ProguardAssumeNoSideEffectRule) {
-        if (item.isDexEncodedMember()) {
-          DexEncodedMember<?, ?> member = item.asDexEncodedMember();
+        if (item.isMember()) {
+          DexClassAndMember<?, ?> member = item.asMember();
           if (member.getHolderType() == appView.dexItemFactory().objectType) {
-            assert member.isDexEncodedMethod();
+            assert member.isMethod();
             reportAssumeNoSideEffectsWarningForJavaLangClassMethod(
-                member.asDexEncodedMethod(), (ProguardAssumeNoSideEffectRule) context);
+                member.asMethod(), (ProguardAssumeNoSideEffectRule) context);
           } else {
             noSideEffects.put(member.getReference(), rule);
-            if (member.isDexEncodedMethod()) {
-              DexEncodedMethod method = member.asDexEncodedMethod();
-              if (method.isClassInitializer()) {
-                feedback.classInitializerMayBePostponed(method);
+            if (member.isMethod()) {
+              DexClassAndMethod method = member.asMethod();
+              if (method.getDefinition().isClassInitializer()) {
+                feedback.classInitializerMayBePostponed(method.getDefinition());
               }
             }
           }
@@ -1339,16 +1193,16 @@
         reasonAsked.computeIfAbsent(item.getReference(), i -> i);
         context.markAsUsed();
       } else if (context instanceof ProguardAssumeValuesRule) {
-        if (item.isDexEncodedMember()) {
-          assumedValues.put(item.asDexEncodedMember().getReference(), rule);
+        if (item.isMember()) {
+          assumedValues.put(item.asMember().getReference(), rule);
           context.markAsUsed();
         }
       } else if (context instanceof ProguardCheckDiscardRule) {
         checkDiscarded.computeIfAbsent(item.getReference(), i -> i);
         context.markAsUsed();
       } else if (context instanceof InlineRule) {
-        if (item.isDexEncodedMethod()) {
-          DexMethod reference = item.asDexEncodedMethod().getReference();
+        if (item.isMethod()) {
+          DexMethod reference = item.asMethod().getReference();
           switch (((InlineRule) context).getType()) {
             case ALWAYS:
               alwaysInline.add(reference);
@@ -1368,14 +1222,14 @@
           context.markAsUsed();
         }
       } else if (context instanceof WhyAreYouNotInliningRule) {
-        if (!item.isDexEncodedMethod()) {
+        if (!item.isMethod()) {
           throw new Unreachable();
         }
-        whyAreYouNotInlining.add(item.asDexEncodedMethod().getReference());
+        whyAreYouNotInlining.add(item.asMethod().getReference());
         context.markAsUsed();
       } else if (context.isClassInlineRule()) {
         ClassInlineRule classInlineRule = context.asClassInlineRule();
-        DexClass clazz = item.asDexClass();
+        DexClass clazz = item.asClass();
         if (clazz == null) {
           throw new IllegalStateException(
               "Unexpected -"
@@ -1386,39 +1240,39 @@
         }
         switch (classInlineRule.getType()) {
           case ALWAYS:
-            alwaysClassInline.addElement(item.asDexClass().type);
+            alwaysClassInline.addElement(item.asClass().getType());
             break;
           case NEVER:
-            neverClassInline.add(item.asDexClass().type);
+            neverClassInline.add(item.asClass().getType());
             break;
           default:
             throw new Unreachable();
         }
         context.markAsUsed();
       } else if (context instanceof NoUnusedInterfaceRemovalRule) {
-        noUnusedInterfaceRemoval.add(item.asDexClass().type);
+        noUnusedInterfaceRemoval.add(item.asClass().type);
         context.markAsUsed();
       } else if (context instanceof NoVerticalClassMergingRule) {
-        noVerticalClassMerging.add(item.asDexClass().type);
+        noVerticalClassMerging.add(item.asClass().type);
         context.markAsUsed();
       } else if (context instanceof NoHorizontalClassMergingRule) {
-        noHorizontalClassMerging.add(item.asDexClass().type);
+        noHorizontalClassMerging.add(item.asClass().type);
         context.markAsUsed();
       } else if (context instanceof MemberValuePropagationRule) {
         switch (((MemberValuePropagationRule) context).getType()) {
           case NEVER:
             // Only add members from propgram classes to `neverPropagateValue` since class member
             // values from library types are not propagated by default.
-            if (item.isDexEncodedField()) {
-              DexEncodedField field = item.asDexEncodedField();
-              if (field.isProgramField(appView)) {
-                neverPropagateValue.add(item.asDexEncodedField().getReference());
+            if (item.isField()) {
+              DexClassAndField field = item.asField();
+              if (field.isProgramField()) {
+                neverPropagateValue.add(field.getReference());
                 context.markAsUsed();
               }
-            } else if (item.isDexEncodedMethod()) {
-              DexEncodedMethod method = item.asDexEncodedMethod();
-              if (method.isProgramMethod(appView)) {
-                neverPropagateValue.add(item.asDexEncodedMethod().getReference());
+            } else if (item.isMethod()) {
+              DexClassAndMethod method = item.asMethod();
+              if (method.isProgramMethod()) {
+                neverPropagateValue.add(method.getReference());
                 context.markAsUsed();
               }
             }
@@ -1427,16 +1281,16 @@
             throw new Unreachable();
         }
       } else if (context instanceof ProguardIdentifierNameStringRule) {
-        if (item.isDexEncodedField()) {
-          identifierNameStrings.add(item.asDexEncodedField().getReference());
+        if (item.isField()) {
+          identifierNameStrings.add(item.asField().getReference());
           context.markAsUsed();
-        } else if (item.isDexEncodedMethod()) {
-          identifierNameStrings.add(item.asDexEncodedMethod().getReference());
+        } else if (item.isMethod()) {
+          identifierNameStrings.add(item.asMethod().getReference());
           context.markAsUsed();
         }
       } else if (context instanceof ConstantArgumentRule) {
-        if (item.isDexEncodedMethod()) {
-          keepParametersWithConstantValue.add(item.asDexEncodedMethod().getReference());
+        if (item.isMethod()) {
+          keepParametersWithConstantValue.add(item.asMethod().getReference());
           context.markAsUsed();
         }
       } else if (context instanceof ReprocessClassInitializerRule) {
@@ -1455,8 +1309,8 @@
           context.markAsUsed();
         }
       } else if (context.isReprocessMethodRule()) {
-        if (item.isDexEncodedMethod()) {
-          DexEncodedMethod method = item.asDexEncodedMethod();
+        if (item.isMethod()) {
+          DexClassAndMethod method = item.asMethod();
           switch (context.asReprocessMethodRule().getType()) {
             case ALWAYS:
               reprocess.add(method.getReference());
@@ -1470,8 +1324,8 @@
           context.markAsUsed();
         }
       } else if (context instanceof UnusedArgumentRule) {
-        if (item.isDexEncodedMethod()) {
-          keepUnusedArguments.add(item.asDexEncodedMethod().getReference());
+        if (item.isMethod()) {
+          keepUnusedArguments.add(item.asMethod().getReference());
           context.markAsUsed();
         }
       } else {
@@ -1479,8 +1333,135 @@
       }
     }
 
+    private synchronized void evaluateKeepRule(
+        ProgramDefinition item,
+        ProguardConfigurationRule context,
+        ProguardMemberRule rule,
+        DexProgramClass precondition,
+        ProguardIfRule ifRule) {
+      if (item.isField()) {
+        ProgramField field = item.asProgramField();
+        if (field.getOptimizationInfo().cannotBeKept()) {
+          // We should only ever get here with if rules.
+          assert ifRule != null;
+          return;
+        }
+      } else if (item.isMethod()) {
+        ProgramMethod method = item.asProgramMethod();
+        if (method.getDefinition().isClassInitializer() && !options.debug) {
+          // Don't keep class initializers.
+          return;
+        }
+        if (method.getOptimizationInfo().cannotBeKept()) {
+          // We should only ever get here with if rules.
+          assert ifRule != null;
+          return;
+        }
+        if (options.isGeneratingDex()
+            && method.getReference().isLambdaDeserializeMethod(appView.dexItemFactory())) {
+          // Don't keep lambda deserialization methods.
+          return;
+        }
+        // If desugaring is enabled, private and static interface methods will be moved to a
+        // companion class. So we don't need to add them to the root set in the beginning.
+        if (options.isInterfaceMethodDesugaringEnabled()
+            && method.getDefinition().hasCode()
+            && (method.getAccessFlags().isPrivate() || method.getAccessFlags().isStatic())) {
+          DexClass holder = appView.definitionFor(method.getHolderType());
+          if (holder != null && holder.isInterface()) {
+            if (rule.isSpecific()) {
+              options.reporter.warning(
+                  new StringDiagnostic(
+                      "The rule `"
+                          + rule
+                          + "` is ignored because the targeting interface method `"
+                          + method.getReference().toSourceString()
+                          + "` will be desugared."));
+            }
+            return;
+          }
+        }
+      }
+
+      // The reason for keeping should link to the conditional rule as a whole, if present.
+      ProguardKeepRuleBase keepRule = ifRule != null ? ifRule : (ProguardKeepRuleBase) context;
+
+      // The modifiers are specified on the actual keep rule (ie, the consequent/context).
+      ProguardKeepRuleModifiers modifiers = ((ProguardKeepRule) context).getModifiers();
+      if (modifiers.isBottom()) {
+        // This rule is a no-op.
+        return;
+      }
+
+      // In compatibility mode, for a match on instance members a referenced class becomes live.
+      if (options.forceProguardCompatibility
+          && !modifiers.allowsShrinking
+          && precondition != null
+          && precondition.isDexClass()) {
+        if (!item.isClass() && !item.getAccessFlags().isStatic()) {
+          dependentKeepClassCompatRule
+              .computeIfAbsent(precondition.asDexClass().getType(), i -> new HashSet<>())
+              .add(keepRule);
+          context.markAsUsed();
+        }
+      }
+
+      // TODO(b/192636793): Remove the noShrinking and dependentNoShrinking collections. A
+      //  prerequisite for this is that the ProguardKeepRule instances are added to the KeepInfo,
+      //  since this is needed for the -whyareyoukeeping graph.
+      if (!modifiers.allowsShrinking) {
+        if (precondition != null) {
+          dependentNoShrinking
+              .computeIfAbsent(precondition.getReference(), x -> new MutableItemsWithRules())
+              .addReferenceWithRule(item.getReference(), keepRule);
+        } else {
+          noShrinking.addReferenceWithRule(item.getReference(), keepRule);
+        }
+        context.markAsUsed();
+      }
+
+      EnqueuerEvent preconditionEvent;
+      if (precondition != null) {
+        preconditionEvent =
+            item.getAccessFlags().isStatic()
+                ? new LiveClassEnqueuerEvent(precondition)
+                : new InstantiatedClassEnqueuerEvent(precondition);
+      } else {
+        preconditionEvent = UnconditionalKeepInfoEvent.get();
+      }
+
+      if (appView.options().isAnnotationRemovalEnabled() && !modifiers.allowsAnnotationRemoval) {
+        modifyDependentMinimumKeepInfo(
+            dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowAnnotationRemoval);
+        context.markAsUsed();
+      }
+
+      if (appView.options().isMinificationEnabled() && !modifiers.allowsObfuscation) {
+        modifyDependentMinimumKeepInfo(
+            dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowMinification);
+        context.markAsUsed();
+      }
+
+      if (appView.options().isOptimizationEnabled() && !modifiers.allowsOptimization) {
+        modifyDependentMinimumKeepInfo(
+            dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowOptimization);
+        context.markAsUsed();
+      }
+
+      if (appView.options().isShrinking() && !modifiers.allowsShrinking) {
+        modifyDependentMinimumKeepInfo(
+            dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowShrinking);
+        context.markAsUsed();
+      }
+
+      if (modifiers.includeDescriptorClasses) {
+        includeDescriptorClasses(item, keepRule, precondition);
+        context.markAsUsed();
+      }
+    }
+
     private void reportAssumeNoSideEffectsWarningForJavaLangClassMethod(
-        DexEncodedMethod method, ProguardAssumeNoSideEffectRule context) {
+        DexClassAndMethod method, ProguardAssumeNoSideEffectRule context) {
       assert method.getHolderType() == options.dexItemFactory().objectType;
       OriginWithPosition key = new OriginWithPosition(context.getOrigin(), context.getPosition());
       assumeNoSideEffectsWarnings
@@ -1527,7 +1508,6 @@
     final Set<DexMethod> neverInlineDueToSingleCaller;
     final Set<DexType> neverClassInline;
     final MutableItemsWithRules noShrinking;
-    final Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo;
     final Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>> dependentMinimumKeepInfo;
     final Map<DexReference, MutableItemsWithRules> dependentNoShrinking;
     final Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule;
@@ -1538,7 +1518,6 @@
         Set<DexMethod> neverInlineDueToSingleCaller,
         Set<DexType> neverClassInline,
         MutableItemsWithRules noShrinking,
-        Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo,
         Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>> dependentMinimumKeepInfo,
         Map<DexReference, MutableItemsWithRules> dependentNoShrinking,
         Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule,
@@ -1547,7 +1526,6 @@
       this.neverInlineDueToSingleCaller = neverInlineDueToSingleCaller;
       this.neverClassInline = neverClassInline;
       this.noShrinking = noShrinking;
-      this.minimumKeepInfo = minimumKeepInfo;
       this.dependentMinimumKeepInfo = dependentMinimumKeepInfo;
       this.dependentNoShrinking = dependentNoShrinking;
       this.dependentKeepClassCompatRule = dependentKeepClassCompatRule;
@@ -1664,8 +1642,6 @@
         TriConsumer<EnqueuerEvent, DexProgramClass, KeepClassInfo.Joiner> classConsumer,
         TriConsumer<EnqueuerEvent, ProgramField, KeepFieldInfo.Joiner> fieldConsumer,
         TriConsumer<EnqueuerEvent, ProgramMethod, KeepMethodInfo.Joiner> methodConsumer) {
-      internalForEachMinimumKeepInfo(
-          appView, minimumKeepInfo, null, classConsumer, fieldConsumer, methodConsumer);
       dependentMinimumKeepInfo.forEach(
           (precondition, minimumKeepInfoForDependents) ->
               internalForEachMinimumKeepInfo(
@@ -1996,7 +1972,6 @@
 
     private RootSet(
         MutableItemsWithRules noShrinking,
-        Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo,
         Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>> dependentMinimumKeepInfo,
         ImmutableList<DexReference> reasonAsked,
         ImmutableList<DexReference> checkDiscarded,
@@ -2029,7 +2004,6 @@
           neverInlineDueToSingleCaller,
           neverClassInline,
           noShrinking,
-          minimumKeepInfo,
           dependentMinimumKeepInfo,
           dependentNoShrinking,
           dependentKeepClassCompatRule,
@@ -2139,8 +2113,12 @@
           });
     }
 
-    void shouldNotBeMinified(DexReference reference) {
-      modifyMinimumKeepInfo(minimumKeepInfo, reference, Joiner::disallowMinification);
+    void shouldNotBeMinified(ProgramDefinition definition) {
+      modifyDependentMinimumKeepInfo(
+          dependentMinimumKeepInfo,
+          UnconditionalKeepInfoEvent.get(),
+          definition,
+          Joiner::disallowMinification);
     }
 
     public boolean verifyKeptFieldsAreAccessedAndLive(AppInfoWithLiveness appInfo) {
@@ -2335,7 +2313,6 @@
         Set<DexMethod> neverInlineDueToSingleCaller,
         Set<DexType> neverClassInline,
         MutableItemsWithRules noShrinking,
-        Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo,
         Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>> dependentMinimumKeepInfo,
         Map<DexReference, MutableItemsWithRules> dependentNoShrinking,
         Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule,
@@ -2345,7 +2322,6 @@
           neverInlineDueToSingleCaller,
           neverClassInline,
           noShrinking,
-          minimumKeepInfo,
           dependentMinimumKeepInfo,
           dependentNoShrinking,
           dependentKeepClassCompatRule,
@@ -2400,7 +2376,6 @@
       super(
           noShrinking,
           emptyMap(),
-          emptyMap(),
           reasonAsked,
           checkDiscarded,
           Collections.emptySet(),
@@ -2450,7 +2425,7 @@
     }
 
     @Override
-    void shouldNotBeMinified(DexReference reference) {
+    void shouldNotBeMinified(ProgramDefinition definition) {
       // Do nothing.
     }