Merge "Compute local info at exceptional blocks based on its predecessor."
diff --git a/src/main/java/com/android/tools/r8/dex/DexFile.java b/src/main/java/com/android/tools/r8/dex/DexFile.java
index a2c65d3..3441346 100644
--- a/src/main/java/com/android/tools/r8/dex/DexFile.java
+++ b/src/main/java/com/android/tools/r8/dex/DexFile.java
@@ -62,13 +62,13 @@
     int version;
     switch (versionByte) {
       case '8':
-        version = 38;
+        version = Constants.ANDROID_O_DEX_VERSION;
         break;
       case '7':
-        version = 37;
+        version = Constants.ANDROID_N_DEX_VERSION;
         break;
       case '5':
-        version = 35;
+        version = Constants.ANDROID_PRE_N_DEX_VERSION;
         break;
       default:
         throw new CompilationError("Dex file has invalid version number: " + name);
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
index f336a3d..f309670 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -174,6 +174,35 @@
     return isFull(transaction.getNumberOfMethods(), transaction.getNumberOfFields(), MAX_ENTRIES);
   }
 
+  void throwIfFull(boolean multiDexEnabled) {
+    if (!isFull()) {
+      return;
+    }
+    StringBuilder messageBuilder = new StringBuilder();
+    // General message: Cannot fit.
+    messageBuilder.append("Cannot fit requested classes in ");
+    messageBuilder.append(multiDexEnabled ? "the main-" : "a single ");
+    messageBuilder.append("dex file.\n");
+    // Suggest supplying the main-dex list or explicitly mention that main-dex list is too large.
+    if (multiDexEnabled) {
+      messageBuilder.append("The list of classes for the main-dex list is too large.\n");
+    } else {
+      messageBuilder.append("Try supplying a main-dex list.\n");
+    }
+    // Show the numbers of methods and/or fields that exceed the limit.
+    if (transaction.getNumberOfMethods() > MAX_ENTRIES) {
+      messageBuilder.append("# methods: ");
+      messageBuilder.append(transaction.getNumberOfMethods());
+      messageBuilder.append(" > ").append(MAX_ENTRIES).append('\n');
+    }
+    if (transaction.getNumberOfFields() > MAX_ENTRIES) {
+      messageBuilder.append("# fields: ");
+      messageBuilder.append(transaction.getNumberOfFields());
+      messageBuilder.append(" > ").append(MAX_ENTRIES).append('\n');
+    }
+    throw new CompilationError(messageBuilder.toString());
+  }
+
   private boolean isFilledEnough(FillStrategy fillStrategy) {
     return isFull(
         transaction.getNumberOfMethods(),
@@ -202,7 +231,7 @@
     protected final ApplicationWriter writer;
     protected final Map<Integer, VirtualFile> nameToFileMap = new HashMap<>();
 
-    public Distributor(ApplicationWriter writer) {
+    Distributor(ApplicationWriter writer) {
       this.application = writer.application;
       this.writer = writer;
     }
@@ -212,7 +241,7 @@
 
   public static class FilePerClassDistributor extends Distributor {
 
-    public FilePerClassDistributor(ApplicationWriter writer) {
+    FilePerClassDistributor(ApplicationWriter writer) {
       super(writer);
     }
 
@@ -232,7 +261,7 @@
     protected Set<DexProgramClass> classes;
     protected Map<DexProgramClass, String> originalNames;
 
-    public DistributorBase(ApplicationWriter writer) {
+    DistributorBase(ApplicationWriter writer) {
       super(writer);
 
       classes = Sets.newHashSet(application.classes());
@@ -247,9 +276,7 @@
           if (clazz != null && clazz.isProgramClass()) {
             DexProgramClass programClass = (DexProgramClass) clazz;
             mainDexFile.addClass(programClass);
-            if (mainDexFile.isFull()) {
-              throw new CompilationError("Cannot fit requested classes in main-dex file.");
-            }
+            mainDexFile.throwIfFull(true);
             classes.remove(programClass);
           } else {
             System.out.println(
@@ -298,7 +325,7 @@
   public static class FillFilesDistributor extends DistributorBase {
     private final FillStrategy fillStrategy;
 
-    public FillFilesDistributor(ApplicationWriter writer, boolean minimalMainDex) {
+    FillFilesDistributor(ApplicationWriter writer, boolean minimalMainDex) {
       super(writer);
       this.fillStrategy = minimalMainDex ? FillStrategy.MINIMAL_MAIN_DEX : FillStrategy.FILL_MAX;
     }
@@ -326,7 +353,7 @@
   }
 
   public static class MonoDexDistributor extends DistributorBase {
-    public MonoDexDistributor(ApplicationWriter writer) {
+    MonoDexDistributor(ApplicationWriter writer) {
       super(writer);
     }
 
@@ -337,9 +364,7 @@
 
       for (DexProgramClass programClass : classes) {
         mainDexFile.addClass(programClass);
-        if (mainDexFile.isFull()) {
-          throw new CompilationError("Cannot fit all classes in a single dex file.");
-        }
+        mainDexFile.throwIfFull(false);
       }
       mainDexFile.commitTransaction();
       return nameToFileMap;
@@ -350,7 +375,7 @@
     private final PackageDistribution packageDistribution;
     private final ExecutorService executorService;
 
-    public PackageMapDistributor(
+    PackageMapDistributor(
         ApplicationWriter writer,
         PackageDistribution packageDistribution,
         ExecutorService executorService) {
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 3619b9c..3601ee9 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -226,17 +226,44 @@
         ((DexEncodedMethod) dexItem).getCode() != null;
   }
 
-  private void checkIfMethodIsAmbiguous(DexItem previousResult, DexItem newResult) {
+  /** Returns if <code>interface1</code> is a super interface of <code>interface2</code> */
+  private boolean isSuperInterfaceOf(DexType interface1, DexType interface2) {
+    assert definitionFor(interface1).isInterface();
+    DexClass holder = definitionFor(interface2);
+    assert holder.isInterface();
+    for (DexType iface : holder.interfaces.values) {
+      if (iface == interface1 || isSuperInterfaceOf(interface1, iface)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private <S extends DexItem> S resolveAmbiguousResult(S previousResult, S newResult) {
+    // For default methods return the item found lowest in the interface hierarchy. Different
+    // implementations can come from different paths in a diamond.
+    // See §9.4.1 in The Java® Language Specification, Java SE 8 Edition.
     if (previousResult != null
         && previousResult != newResult
         && isDefaultMethod(previousResult)
         && isDefaultMethod(newResult)) {
+      DexEncodedMethod previousMethod = (DexEncodedMethod) previousResult;
+      DexEncodedMethod newMethod = (DexEncodedMethod) newResult;
+      if (isSuperInterfaceOf(previousMethod.method.getHolder(), newMethod.method.getHolder())) {
+        return newResult;
+      }
+      if (isSuperInterfaceOf(newMethod.method.getHolder(), previousMethod.method.getHolder())) {
+        return previousResult;
+      }
       throw new CompilationError("Duplicate default methods named "
           + previousResult.toSourceString()
           + " are inherited from the types "
-          + ((DexEncodedMethod) previousResult).method.holder.getName()
+          + previousMethod.method.holder.getName()
           + " and "
-          + ((DexEncodedMethod) newResult).method.holder.getName());
+          + newMethod.method.holder.getName());
+    } else {
+      // Return the first item found for everything except default methods.
+      return previousResult != null ? previousResult : newResult;
     }
   }
 
@@ -256,21 +283,13 @@
     for (DexType iface : holder.interfaces.values) {
       S localResult = lookupTargetAlongSuperAndInterfaceChain(iface, desc, lookup);
       if (localResult != null) {
-        checkIfMethodIsAmbiguous(result, localResult);
-        // Return the first item found, we only continue to detect ambiguous method call.
-        if (result == null) {
-          result = localResult;
-        }
+        result = resolveAmbiguousResult(result, localResult);
       }
     }
     if (holder.superType != null) {
       S localResult = lookupTargetAlongInterfaceChain(holder.superType, desc, lookup);
       if (localResult != null) {
-        checkIfMethodIsAmbiguous(result, localResult);
-        // Return the first item found, we only continue to detect ambiguous method call.
-        if (result == null) {
-          result = localResult;
-        }
+        result = resolveAmbiguousResult(result, localResult);
       }
     }
     return result;
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
index 0b8d876..065d3df 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
@@ -41,11 +41,13 @@
     return field;
   }
 
+  abstract DexEncodedField lookupTarget(DexType type, AppInfo appInfo);
+
   @Override
   public Constraint inliningConstraint(AppInfo info, DexType holder) {
     // Resolve the field if possible and decide whether the instruction can inlined.
     DexType fieldHolder = field.getHolder();
-    DexEncodedField target = info.lookupInstanceTarget(fieldHolder, field);
+    DexEncodedField target = lookupTarget(fieldHolder, info);
     DexClass fieldClass = info.definitionFor(fieldHolder);
     if ((target != null) && (fieldClass != null) && !fieldClass.isLibraryClass()) {
       DexAccessFlags flags = target.accessFlags;
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
index f38614f..1d9e853 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
@@ -13,7 +13,10 @@
 import com.android.tools.r8.code.IgetWide;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.DexBuilder;
 
 public class InstanceGet extends FieldInstruction {
@@ -95,6 +98,11 @@
   }
 
   @Override
+  DexEncodedField lookupTarget(DexType type, AppInfo appInfo) {
+    return appInfo.lookupInstanceTarget(type, field);
+  }
+
+  @Override
   public boolean isInstanceGet() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
index 7ec8eaf..2642de1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
@@ -13,7 +13,10 @@
 import com.android.tools.r8.code.IputWide;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.DexBuilder;
 import java.util.List;
 
@@ -96,6 +99,11 @@
   }
 
   @Override
+  DexEncodedField lookupTarget(DexType type, AppInfo appInfo) {
+    return appInfo.lookupInstanceTarget(type, field);
+  }
+
+  @Override
   public boolean isInstancePut() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
index ad340c2..bb79d5e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
@@ -12,7 +12,10 @@
 import com.android.tools.r8.code.SgetWide;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.DexBuilder;
 
 public class StaticGet extends FieldInstruction {
@@ -91,6 +94,11 @@
   }
 
   @Override
+  DexEncodedField lookupTarget(DexType type, AppInfo appInfo) {
+    return appInfo.lookupStaticTarget(type, field);
+  }
+
+  @Override
   public String toString() {
     return super.toString() + "; field: " + field.toSourceString();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
index e8a1fed..6736d7e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
@@ -12,7 +12,10 @@
 import com.android.tools.r8.code.SputWide;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.DexBuilder;
 
 public class StaticPut extends FieldInstruction {
@@ -93,6 +96,11 @@
   }
 
   @Override
+  DexEncodedField lookupTarget(DexType type, AppInfo appInfo) {
+    return appInfo.lookupStaticTarget(type, field);
+  }
+
+  @Override
   public String toString() {
     return super.toString() + "; field: " + field.toSourceString();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index 4ede5a8..a2b3ba2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -302,9 +302,9 @@
                 continue;
               }
               // Ensure the container is compatible with the target.
-             if (!forceInline
-                 && !result.target.isPublicInlining()
-                 && (method.method.getHolder() != result.target.method.getHolder())) {
+              if (!forceInline
+                  && !result.target.isPublicInlining()
+                  && (method.method.getHolder() != result.target.method.getHolder())) {
                 continue;
               }
               DexType downcast = null;
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index 3a77a52..6f1a9b2 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -1732,14 +1732,8 @@
         for (Phi phi : successor.getPhis()) {
           LiveIntervals toIntervals = phi.getLiveIntervals().getSplitCovering(toInstruction);
           Value operand = phi.getOperand(predIndex);
-          LiveIntervals fromIntervals = operand.getLiveIntervals();
-          if (operand.isPhi() && operand != phi && successor.getPhis().contains(operand)) {
-            // If the input to this phi is another phi in this block we want the value after
-            // merging which is the value for that phi at the from instruction.
-            fromIntervals = fromIntervals.getSplitCovering(fromInstruction);
-          } else {
-            fromIntervals = fromIntervals.getSplitCovering(fromInstruction);
-          }
+          LiveIntervals fromIntervals =
+              operand.getLiveIntervals().getSplitCovering(fromInstruction);
           if (fromIntervals != toIntervals && !toIntervals.isArgumentInterval()) {
             assert block.getSuccessors().size() == 1;
             spillMoves.addPhiMove(fromInstruction - 1, toIntervals, fromIntervals);
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 69fdd65..a5e2309 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -150,8 +150,15 @@
 
   @Test
   public void cannotFitBothIntoMainDex() throws Throwable {
-    thrown.expect(CompilationError.class);
-    verifyMainDexContains(TWO_LARGE_CLASSES, getTwoLargeClassesAppPath(), false);
+    try {
+      verifyMainDexContains(TWO_LARGE_CLASSES, getTwoLargeClassesAppPath(), false);
+      fail("Expect to fail, for there are too many classes for the main-dex list.");
+    } catch (CompilationError e) {
+      // Make sure {@link MonoDexDistributor} was _not_ used.
+      assertFalse(e.getMessage().contains("single dex file"));
+      // Make sure what exceeds the limit is the number of methods.
+      assertTrue(e.getMessage().contains("# methods"));
+    }
   }
 
   @Test
@@ -183,8 +190,15 @@
 
   @Test
   public void cannotFitAllIntoMainDex() throws Throwable {
-    thrown.expect(CompilationError.class);
-    verifyMainDexContains(MANY_CLASSES, getManyClassesMultiDexAppPath(), false);
+    try {
+      verifyMainDexContains(MANY_CLASSES, getManyClassesMultiDexAppPath(), false);
+      fail("Expect to fail, for there are too many classes for the main-dex list.");
+    } catch (CompilationError e) {
+      // Make sure {@link MonoDexDistributor} was _not_ used.
+      assertFalse(e.getMessage().contains("single dex file"));
+      // Make sure what exceeds the limit is the number of methods.
+      assertTrue(e.getMessage().contains("# methods"));
+    }
   }
 
   @Test
@@ -334,7 +348,10 @@
           MANY_CLASSES, Constants.ANDROID_K_API, false, MANY_CLASSES_MULTI_DEX_METHODS_PER_CLASS);
       fail("Expect to fail, for there are many classes while multidex is not enabled.");
     } catch (CompilationError e) {
-      assertTrue(e.getMessage().contains("Cannot fit all classes in a single dex file."));
+      // Make sure {@link MonoDexDistributor} was used.
+      assertTrue(e.getMessage().contains("single dex file"));
+      // Make sure what exceeds the limit is the number of methods.
+      assertTrue(e.getMessage().contains("# methods"));
     }
   }
 
@@ -476,8 +493,8 @@
     }
     DexApplication application = builder.build();
     AppInfoWithSubtyping appInfo = new AppInfoWithSubtyping(application);
-    ApplicationWriter writer =
-        new ApplicationWriter(application, appInfo, options, null, NamingLens.getIdentityLens(), null);
+    ApplicationWriter writer = new ApplicationWriter(
+        application, appInfo, options, null, NamingLens.getIdentityLens(), null);
     ExecutorService executor = ThreadUtils.getExecutorService(options);
     try {
       return writer.write(null, executor);
diff --git a/src/test/java/com/android/tools/r8/regress/b63935662/Regress63935662.java b/src/test/java/com/android/tools/r8/regress/b63935662/Regress63935662.java
new file mode 100644
index 0000000..70d4efc
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/regress/b63935662/Regress63935662.java
@@ -0,0 +1,54 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.regress.b63935662;
+
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.utils.AndroidApp;
+import java.nio.file.Path;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class Regress63935662 extends TestBase {
+
+  void run(AndroidApp app, Class mainClass) throws Exception {
+    if (!ToolHelper.getDexVm().isNewerThan(DexVm.ART_6_0_1)) {
+      return;
+    }
+    Path proguardConfig = writeTextToTempFile(keepMainProguardConfiguration(mainClass, true, false));
+    R8Command command =
+        ToolHelper.prepareR8CommandBuilder(app)
+            .addProguardConfigurationFiles(proguardConfig)
+            .setMinApiLevel(Constants.ANDROID_N_API)
+            .build();
+    String resultFromJava = runOnJava(mainClass);
+    app = ToolHelper.runR8(command);
+    String resultFromArt = runOnArt(app, mainClass);
+    Assert.assertEquals(resultFromJava, resultFromArt);
+  }
+
+  @Test
+  public void test() throws Exception {
+    Class mainClass = TestClass.class;
+    AndroidApp app = readClasses(
+        TestClass.Top.class, TestClass.Left.class, TestClass.Right.class, TestClass.Bottom.class,
+        TestClass.X1.class, TestClass.X2.class, TestClass.X3.class, TestClass.X4.class, TestClass.X5.class,
+        mainClass);
+    run(app, mainClass);
+  }
+
+  @Test
+  public void test2() throws Exception {
+    Class mainClass = TestFromBug.class;
+    AndroidApp app = readClasses(
+        TestFromBug.Map.class, TestFromBug.AbstractMap.class,
+        TestFromBug.ConcurrentMap.class, TestFromBug.ConcurrentHashMap.class,
+        mainClass);
+    run(app, mainClass);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/regress/b63935662/TestClass.java b/src/test/java/com/android/tools/r8/regress/b63935662/TestClass.java
new file mode 100644
index 0000000..878fcff
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/regress/b63935662/TestClass.java
@@ -0,0 +1,60 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.regress.b63935662;
+
+public class TestClass {
+
+  interface Top {
+    default String name() { return "unnamed"; }
+  }
+
+  interface Left extends Top {
+    default String name() { return getClass().getName(); }
+  }
+
+  interface Right extends Top {
+    /* No override of default String name() */
+  }
+
+  interface Bottom extends Left, Right {}
+
+  static class X1 implements Bottom {
+    void test() {
+      System.out.println(name());
+    }
+  }
+
+  static class X2 implements Left, Right  {
+    void test() {
+      System.out.println(name());
+    }
+  }
+
+  static class X3 implements Right, Left   {
+    void test() {
+      System.out.println(name());
+    }
+  }
+
+  static class X4 implements Left, Right, Top  {
+    void test() {
+      System.out.println(name());
+    }
+  }
+
+  static class X5 implements Right, Left, Top   {
+    void test() {
+      System.out.println(name());
+    }
+  }
+
+  public static void main(String[] args) {
+    new X1().test();
+    new X2().test();
+    new X3().test();
+    new X4().test();
+    new X5().test();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/regress/b63935662/TestFromBug.java b/src/test/java/com/android/tools/r8/regress/b63935662/TestFromBug.java
new file mode 100644
index 0000000..9d3efc6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/regress/b63935662/TestFromBug.java
@@ -0,0 +1,30 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.regress.b63935662;
+
+import java.util.function.BiConsumer;
+
+public class TestFromBug {
+
+  public interface Map<K, V> {
+    default void forEach(BiConsumer<? super K, ? super V> action) {
+      System.out.println("Map.forEach");
+    }
+  }
+
+  public interface ConcurrentMap<K, V> extends Map<K,V> {
+    @Override
+    default void forEach(BiConsumer<? super K, ? super V> action) {
+      System.out.println("ConcurrentMap.forEach");
+    }
+  }
+
+  public static abstract class AbstractMap<K,V> implements Map<K, V> {}
+  public static class ConcurrentHashMap<K,V> extends AbstractMap<K,V> implements ConcurrentMap<K,V> {}
+
+  public static void main(String[] args) {
+    new ConcurrentHashMap<String, String>().forEach(null);
+  }
+}
\ No newline at end of file