Compute features split for legacy synthetics.

Bug: 186523004
Change-Id: Iaf148f0bd85239b393a7cdd87fc6b44d538f1906
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index ab55c16..17f8d1b 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
+import com.android.tools.r8.features.ClassToFeatureSplitMap;
 import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.origin.Origin;
@@ -130,7 +131,8 @@
   public void addSynthesizedClass(DexProgramClass clazz, ProgramDefinition context) {
     assert checkIfObsolete();
     assert context != null;
-    syntheticItems.addLegacySyntheticClass(clazz, context);
+    syntheticItems.addLegacySyntheticClass(
+        clazz, context, ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap());
   }
 
   public void addSynthesizedClass(DexProgramClass clazz, Iterable<DexProgramClass> contexts) {
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
index c2c02ad..26b1f96 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -156,6 +156,13 @@
     return this;
   }
 
+  @Override
+  public void addSynthesizedClass(DexProgramClass clazz, ProgramDefinition context) {
+    assert checkIfObsolete();
+    assert context != null;
+    getSyntheticItems().addLegacySyntheticClass(clazz, context, classToFeatureSplitMap);
+  }
+
   /**
    * Primitive traversal over all supertypes of a given type.
    *
diff --git a/src/main/java/com/android/tools/r8/synthesis/LegacySyntheticDefinition.java b/src/main/java/com/android/tools/r8/synthesis/LegacySyntheticDefinition.java
index 47a9556..3e50bf5 100644
--- a/src/main/java/com/android/tools/r8/synthesis/LegacySyntheticDefinition.java
+++ b/src/main/java/com/android/tools/r8/synthesis/LegacySyntheticDefinition.java
@@ -3,25 +3,28 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.synthesis;
 
+import com.android.tools.r8.FeatureSplit;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramDefinition;
+import com.android.tools.r8.utils.IterableUtils;
 import com.google.common.collect.ImmutableSet;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 public class LegacySyntheticDefinition {
   private final DexProgramClass clazz;
-  private final Map<DexType, DexType> contexts = new ConcurrentHashMap<>();
+  private final Map<DexType, FeatureSplit> contexts = new ConcurrentHashMap<>();
 
   public LegacySyntheticDefinition(DexProgramClass clazz) {
     this.clazz = clazz;
   }
 
-  public void addContext(ProgramDefinition clazz) {
+  public void addContext(ProgramDefinition clazz, FeatureSplit featureSplit) {
     DexType type = clazz.getContextType();
-    contexts.put(type, type);
+    contexts.put(type, featureSplit);
   }
 
   public Set<DexType> getContexts() {
@@ -29,7 +32,22 @@
   }
 
   public LegacySyntheticReference toReference() {
-    return new LegacySyntheticReference(clazz.getType(), ImmutableSet.copyOf(contexts.keySet()));
+    return new LegacySyntheticReference(
+        clazz.getType(), ImmutableSet.copyOf(contexts.keySet()), getFeatureSplit());
+  }
+
+  public FeatureSplit getFeatureSplit() {
+    assert verifyConsistentFeatures();
+    if (contexts.isEmpty()) {
+      return FeatureSplit.BASE;
+    }
+    return IterableUtils.first(contexts.values());
+  }
+
+  private boolean verifyConsistentFeatures() {
+    HashSet<FeatureSplit> features = new HashSet<>(contexts.values());
+    assert features.size() < 2;
+    return true;
   }
 
   public DexProgramClass getDefinition() {
diff --git a/src/main/java/com/android/tools/r8/synthesis/LegacySyntheticReference.java b/src/main/java/com/android/tools/r8/synthesis/LegacySyntheticReference.java
index 06d2e2c..715e790 100644
--- a/src/main/java/com/android/tools/r8/synthesis/LegacySyntheticReference.java
+++ b/src/main/java/com/android/tools/r8/synthesis/LegacySyntheticReference.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.synthesis;
 
+import com.android.tools.r8.FeatureSplit;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
 import java.util.Set;
@@ -10,10 +11,12 @@
 public class LegacySyntheticReference implements Rewritable<LegacySyntheticReference> {
   private final DexType type;
   private final Set<DexType> contexts;
+  private final FeatureSplit featureSplit;
 
-  public LegacySyntheticReference(DexType type, Set<DexType> contexts) {
+  public LegacySyntheticReference(DexType type, Set<DexType> contexts, FeatureSplit featureSplit) {
     this.type = type;
     this.contexts = contexts;
+    this.featureSplit = featureSplit;
   }
 
   @Override
@@ -25,6 +28,10 @@
     return contexts;
   }
 
+  public FeatureSplit getFeatureSplit() {
+    return featureSplit;
+  }
+
   @Override
   public LegacySyntheticReference rewrite(NonIdentityGraphLens lens) {
     DexType rewrittenType = lens.lookupType(type);
@@ -32,6 +39,6 @@
     if (type == rewrittenType && contexts.equals(rewrittenContexts)) {
       return this;
     }
-    return new LegacySyntheticReference(rewrittenType, rewrittenContexts);
+    return new LegacySyntheticReference(rewrittenType, rewrittenContexts, featureSplit);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
index befe594..d0164d7 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -261,19 +261,32 @@
   }
 
   public FeatureSplit getContextualFeatureSplit(DexType type) {
+    if (pending.legacyClasses.containsKey(type)) {
+      LegacySyntheticDefinition definition = pending.legacyClasses.get(type);
+      return definition.getFeatureSplit();
+    }
+    if (committed.containsLegacyType(type)) {
+      List<LegacySyntheticReference> types = committed.getLegacyTypes(type);
+      if (types.isEmpty()) {
+        return null;
+      }
+      assert verifyAllHaveSameFeature(types, LegacySyntheticReference::getFeatureSplit);
+      return types.get(0).getFeatureSplit();
+    }
     List<SynthesizingContext> contexts = getSynthesizingContexts(type);
     if (contexts.isEmpty()) {
       return null;
     }
-    assert verifyAllContextsHaveSameFeature(contexts);
+    assert verifyAllHaveSameFeature(contexts, SynthesizingContext::getFeatureSplit);
     return contexts.get(0).getFeatureSplit();
   }
 
-  private boolean verifyAllContextsHaveSameFeature(List<SynthesizingContext> contexts) {
-    assert !contexts.isEmpty();
-    FeatureSplit featureSplit = contexts.get(0).getFeatureSplit();
-    for (int i = 1; i < contexts.size(); i++) {
-      assert featureSplit == contexts.get(i).getFeatureSplit();
+  private static <T> boolean verifyAllHaveSameFeature(
+      List<T> items, Function<T, FeatureSplit> getter) {
+    assert !items.isEmpty();
+    FeatureSplit featureSplit = getter.apply(items.get(0));
+    for (int i = 1; i < items.size(); i++) {
+      assert featureSplit == getter.apply(items.get(i));
     }
     return true;
   }
@@ -379,9 +392,13 @@
   }
 
   // TODO(b/158159959): Remove the usage of this direct class addition.
-  public void addLegacySyntheticClass(DexProgramClass clazz, ProgramDefinition context) {
+  public void addLegacySyntheticClass(
+      DexProgramClass clazz,
+      ProgramDefinition context,
+      ClassToFeatureSplitMap classToFeatureSplitMap) {
     LegacySyntheticDefinition legacyItem = internalAddLegacySyntheticClass(clazz);
-    legacyItem.addContext(context);
+    FeatureSplit featureSplit = classToFeatureSplitMap.getFeatureSplit(context, this);
+    legacyItem.addContext(context, featureSplit);
   }
 
   private LegacySyntheticDefinition internalAddLegacySyntheticClass(DexProgramClass clazz) {