Ensure fresh names when merging instance fields

Bug: b/263934503
Change-Id: I56c1297bc6a89f5f4a6473254efd5c0426477f23
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInstanceFieldsMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInstanceFieldsMerger.java
index 25933dd..195a8fc 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInstanceFieldsMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInstanceFieldsMerger.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexTypeUtils;
@@ -14,6 +15,7 @@
 import com.android.tools.r8.horizontalclassmerging.policies.SameInstanceFields.InstanceFieldInfo;
 import com.android.tools.r8.utils.IterableUtils;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.LinkedHashMap;
@@ -22,6 +24,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.function.BiConsumer;
+import java.util.function.Predicate;
 
 public interface ClassInstanceFieldsMerger {
 
@@ -135,6 +138,8 @@
 
     private DexEncodedField classIdField;
 
+    private final Set<DexField> committedFields = Sets.newIdentityHashSet();
+
     private ClassInstanceFieldsMergerImpl(
         AppView<? extends AppInfoWithClassHierarchy> appView,
         HorizontalClassMergerGraphLens.Builder lensBuilder,
@@ -155,12 +160,17 @@
       List<DexEncodedField> newFields = new ArrayList<>();
       if (classIdField != null) {
         newFields.add(classIdField);
+        committedFields.add(classIdField.getReference());
       }
       group
           .getInstanceFieldMap()
           .forEachManyToOneMapping(
-              (sourceFields, targetField) ->
-                  newFields.add(mergeSourceFieldsToTargetField(targetField, sourceFields)));
+              (sourceFields, targetField) -> {
+                DexEncodedField newField =
+                    mergeSourceFieldsToTargetField(targetField, sourceFields);
+                newFields.add(newField);
+                committedFields.add(newField.getReference());
+              });
       return newFields.toArray(DexEncodedField.EMPTY_ARRAY);
     }
 
@@ -184,6 +194,19 @@
         newField = targetField;
       }
 
+      if (committedFields.contains(newField.getReference())) {
+        newField =
+            targetField.toTypeSubstitutedField(
+                appView,
+                appView
+                    .dexItemFactory()
+                    .createFreshFieldNameWithoutHolder(
+                        newField.getHolderType(),
+                        newField.getType(),
+                        newField.getName().toString(),
+                        Predicate.not(committedFields::contains)));
+      }
+
       lensBuilder.recordNewFieldSignature(
           Iterables.transform(
               IterableUtils.append(sourceFields, targetField), DexEncodedField::getReference),
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/RelaxedInstanceFieldCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/RelaxedInstanceFieldCollisionTest.java
index fa784ca..d35ce82 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/RelaxedInstanceFieldCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/RelaxedInstanceFieldCollisionTest.java
@@ -4,10 +4,6 @@
 
 package com.android.tools.r8.classmerging.horizontal;
 
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertThrows;
-
-import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -48,22 +44,16 @@
 
   @Test
   public void testR8() throws Exception {
-    assertThrows(
-        CompilationFailedException.class,
-        () ->
-            testForR8(parameters.getBackend())
-                .addProgramClasses(
-                    UnrelatedA.class, UnrelatedB.class, UnrelatedC.class, UnrelatedD.class)
-                .addProgramClassFileData(getTransformedClasses())
-                .setMinApi(parameters.getApiLevel())
-                .addKeepMainRule(Main.class)
-                .addKeepClassRules(
-                    UnrelatedA.class, UnrelatedB.class, UnrelatedC.class, UnrelatedD.class)
-                // TODO(b/263934503): We should not fail with a duplicate field message.
-                .compileWithExpectedDiagnostics(
-                    diagnostics ->
-                        diagnostics.assertErrorMessageThatMatches(
-                            containsString("Duplicate field"))));
+    testForR8(parameters.getBackend())
+        .addProgramClasses(UnrelatedA.class, UnrelatedB.class, UnrelatedC.class, UnrelatedD.class)
+        .addProgramClassFileData(getTransformedClasses())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .addKeepClassRules(UnrelatedA.class, UnrelatedB.class, UnrelatedC.class, UnrelatedD.class)
+        .addHorizontallyMergedClassesInspector(
+            inspector -> inspector.assertClassesMerged(A.class, B.class))
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines(EXPECTED);
   }
 
   private Collection<byte[]> getTransformedClasses() throws Exception {