Extend materialized rule merging to rules with members in precondition

Change-Id: Ia9dcd07127a0a48ae0befa31e5b5fd56a0faba34
diff --git a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
index 5897798..583380c 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
@@ -30,7 +30,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
-import java.util.function.Consumer;
+import java.util.function.BiPredicate;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
@@ -76,15 +76,8 @@
               ifRuleKey.relevantCandidatesForRule(
                   appView, subtypingInfo, classesWithNewlyLiveMembers, isEffectivelyLive)) {
             assert isEffectivelyLive.test(clazz);
-            evaluateRuleOnEffectivelyLiveClass(
-                ifRuleKey,
-                ifRulesInEquivalence,
-                clazz,
-                matchedIfRule -> {
-                  if (canRemoveSubsequentKeepRule(matchedIfRule)) {
-                    toRemove.add(matchedIfRule);
-                  }
-                });
+            processActiveIfRulesWithMembersAndSameClassPrecondition(
+                ifRuleKey, ifRulesInEquivalence, clazz, toRemove);
           }
           if (ifRulesInEquivalence.size() == toRemove.size()) {
             return true;
@@ -95,6 +88,38 @@
     tasks.await();
   }
 
+  private void processActiveIfRulesWithMembersAndSameClassPrecondition(
+      ProguardIfRule ifRuleKey,
+      Set<ProguardIfRule> ifRulesInEquivalence,
+      DexProgramClass clazz,
+      List<ProguardIfRule> toRemove) {
+    // Check if the class matches the if-rule.
+    if (!evaluateClassForIfRule(ifRuleKey, clazz)) {
+      return;
+    }
+    // When matching an if rule against a type, the if-rule are filled with the current
+    // capture of wildcards. Propagate this down to member rules with same class part
+    // equivalence.
+    for (ProguardIfRule ifRule : ifRulesInEquivalence) {
+      registerClassCapture(ifRule, clazz, clazz);
+      List<Pair<ProguardIfRulePreconditionMatch, ProguardKeepRule>> materializedSubsequentRules =
+          new ArrayList<>();
+      evaluateIfRuleMembersAndMaterialize(
+          ifRule,
+          clazz,
+          (ifRulePreconditionMatch, materializedSubsequentRule) -> {
+            materializedSubsequentRules.add(
+                new Pair<>(ifRulePreconditionMatch, materializedSubsequentRule));
+            if (canRemoveSubsequentKeepRule(ifRule)) {
+              toRemove.add(ifRule);
+              return true;
+            }
+            return false;
+          });
+      applyMaterializedSubsequentRules(ifRule, materializedSubsequentRules);
+    }
+  }
+
   public void processActiveIfRulesWithoutMembers(
       Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> ifRules,
       Iterable<DexProgramClass> newlyLiveClasses)
@@ -144,36 +169,10 @@
         break;
       }
     }
-    materializedSubsequentRules =
-        MaterializedSubsequentRulesOptimizer.optimize(ifRule, materializedSubsequentRules);
-    for (Pair<ProguardIfRulePreconditionMatch, ProguardKeepRule> pair :
-        materializedSubsequentRules) {
-      ProguardIfRulePreconditionMatch ifRulePreconditionMatch = pair.getFirst();
-      ProguardKeepRule materializedSubsequentRule = pair.getSecond();
-      applyMaterializedSubsequentRule(materializedSubsequentRule, ifRulePreconditionMatch);
-    }
+    applyMaterializedSubsequentRules(ifRule, materializedSubsequentRules);
     return isSubsequentRuleFullyEvaluated;
   }
 
-  private void evaluateRuleOnEffectivelyLiveClass(
-      ProguardIfRule ifRuleKey,
-      Set<ProguardIfRule> ifRulesInEquivalence,
-      DexProgramClass clazz,
-      Consumer<ProguardIfRule> matchedConsumer)
-      throws ExecutionException {
-    // Check if the class matches the if-rule.
-    if (!evaluateClassForIfRule(ifRuleKey, clazz)) {
-      return;
-    }
-    // When matching an if rule against a type, the if-rule are filled with the current
-    // capture of wildcards. Propagate this down to member rules with same class part
-    // equivalence.
-    for (ProguardIfRule ifRule : ifRulesInEquivalence) {
-      registerClassCapture(ifRule, clazz, clazz);
-      evaluateIfRuleMembersAndMaterialize(ifRule, clazz, matchedConsumer);
-    }
-  }
-
   private void incrementNumberOfProguardIfRuleClassEvaluations() {
     if (appView.testing().measureProguardIfRuleEvaluations) {
       appView.testing().proguardIfRuleEvaluationData.numberOfProguardIfRuleClassEvaluations++;
@@ -232,8 +231,9 @@
   }
 
   private void evaluateIfRuleMembersAndMaterialize(
-      ProguardIfRule rule, DexProgramClass clazz, Consumer<ProguardIfRule> matchedConsumer)
-      throws ExecutionException {
+      ProguardIfRule rule,
+      DexProgramClass clazz,
+      BiPredicate<ProguardIfRulePreconditionMatch, ProguardKeepRule> materializedIfRuleConsumer) {
     incrementNumberOfProguardIfRuleMemberEvaluations();
     Collection<ProguardMemberRule> memberKeepRules = rule.getMemberRules();
     assert !memberKeepRules.isEmpty();
@@ -332,9 +332,7 @@
             new ProguardIfRulePreconditionMatch(rule, clazz, methodsSatisfyingRule);
         ifRulePreconditionMatch.disallowOptimizationsForReevaluation(enqueuer, rootSetBuilder);
         ProguardKeepRule materializedSubsequentRule = rule.materialize(factory);
-        applyMaterializedSubsequentRule(materializedSubsequentRule, ifRulePreconditionMatch);
-        if (canRemoveSubsequentKeepRule(rule)) {
-          matchedConsumer.accept(rule);
+        if (materializedIfRuleConsumer.test(ifRulePreconditionMatch, materializedSubsequentRule)) {
           return;
         }
       }
@@ -350,6 +348,19 @@
     return field.getOrComputeIsInlinableByJavaC(factory);
   }
 
+  private void applyMaterializedSubsequentRules(
+      ProguardIfRule ifRule,
+      List<Pair<ProguardIfRulePreconditionMatch, ProguardKeepRule>> materializedSubsequentRules) {
+    materializedSubsequentRules =
+        MaterializedSubsequentRulesOptimizer.optimize(ifRule, materializedSubsequentRules);
+    for (Pair<ProguardIfRulePreconditionMatch, ProguardKeepRule> pair :
+        materializedSubsequentRules) {
+      ProguardIfRulePreconditionMatch ifRulePreconditionMatch = pair.getFirst();
+      ProguardKeepRule materializedSubsequentRule = pair.getSecond();
+      applyMaterializedSubsequentRule(materializedSubsequentRule, ifRulePreconditionMatch);
+    }
+  }
+
   private void applyMaterializedSubsequentRule(
       ProguardKeepRule materializedSubsequentRule,
       ProguardIfRulePreconditionMatch ifRulePreconditionMatch) {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java b/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
index 63e6b5a..98f41cd 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
@@ -253,7 +253,7 @@
   }
 
   public boolean hasMemberRules() {
-    return memberRules != null && !memberRules.isEmpty();
+    return !memberRules.isEmpty();
   }
 
   public ProguardMemberRule getMemberRule(int index) {
diff --git a/src/main/java/com/android/tools/r8/shaking/ifrules/MaterializedSubsequentRulesOptimizer.java b/src/main/java/com/android/tools/r8/shaking/ifrules/MaterializedSubsequentRulesOptimizer.java
index 3cbb5a0..adb78d5 100644
--- a/src/main/java/com/android/tools/r8/shaking/ifrules/MaterializedSubsequentRulesOptimizer.java
+++ b/src/main/java/com/android/tools/r8/shaking/ifrules/MaterializedSubsequentRulesOptimizer.java
@@ -17,6 +17,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 
@@ -100,7 +101,7 @@
       memberRules = new ArrayList<>(representativeKeepRule.getMemberRules());
       memberRules.set(memberRuleWithBackReferenceIndex, replacementMemberRule);
     } else {
-      memberRules = null;
+      memberRules = Collections.emptyList();
     }
     ProguardKeepRule replacementKeepRule =
         new ProguardKeepRule(