Move interface method desugarings to the R8 enqueuer.

Bug: 183998768
Bug: 197613376
Fixes: 167345026
Fixes: 167535447
Fixes: 187377562
Fixes: 168697955
Fixes: 159987443
Fixes: 196345511
Fixes: 197851381

Change-Id: I5e605297e24aa20dbc04547a60807a93f646a630
diff --git a/src/test/examplesAndroidO/invokecustom/TestGenerator.java b/src/test/examplesAndroidO/invokecustom/TestGenerator.java
index 9964ed0..a4cd89a 100644
--- a/src/test/examplesAndroidO/invokecustom/TestGenerator.java
+++ b/src/test/examplesAndroidO/invokecustom/TestGenerator.java
@@ -21,6 +21,8 @@
 import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 
+// TODO(b/167145686): Migrate these tests to the new setup ala
+//  InvokeDynamicVirtualDispatchToDefaultInterfaceMethodTest
 public class TestGenerator {
 
   private final Path classNamePath;
@@ -52,7 +54,6 @@
               generateMethodTest6(cw);
               generateMethodTest7(cw);
               generateMethodTest8(cw);
-              generateMethodTest9(cw);
               generateMethodTest10(cw);
               generateMethodTest11(cw);
               generateMethodTest12(cw);
@@ -89,8 +90,6 @@
     mv.visitMethodInsn(
         Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test8", "()V", false);
     mv.visitMethodInsn(
-        Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test9", "()V", false);
-    mv.visitMethodInsn(
         Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test10", "()V", false);
     mv.visitMethodInsn(
         Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test11", "()V", false);
@@ -280,29 +279,6 @@
 
   /**
    *  Generate test with an invokedynamic, a static bootstrap method with an extra arg that is a
-   *  MethodHandle of kind invoke virtual. The target method is a method into a class implementing
-   *  an abstract method and that shadows a default method from an interface.
-   */
-  private void generateMethodTest9(ClassVisitor cv) {
-    MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test9", "()V",
-        null, null);
-    MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class,
-        MethodType.class, MethodHandle.class);
-    Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class),
-        "bsmCreateCallSite", mt.toMethodDescriptorString(), false);
-    mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(InvokeCustom.class));
-    mv.visitInsn(Opcodes.DUP);
-    mv.visitMethodInsn(
-        Opcodes.INVOKESPECIAL, Type.getInternalName(InvokeCustom.class), "<init>", "()V", false);
-    mv.visitInvokeDynamicInsn("targetMethodTest10", "(Linvokecustom/InvokeCustom;)V", bootstrap,
-        new Handle(Opcodes.H_INVOKEVIRTUAL, Type.getInternalName(InvokeCustom.class),
-            "targetMethodTest10", "()V", false));
-    mv.visitInsn(Opcodes.RETURN);
-    mv.visitMaxs(-1, -1);
-  }
-
-  /**
-   *  Generate test with an invokedynamic, a static bootstrap method with an extra arg that is a
    *  MethodHandle of kind get static. The method handle read a static field from a class.
    */
   private void generateMethodTest10(ClassVisitor cv) {
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
index a92437f..11b41cc 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
@@ -200,7 +200,7 @@
             b ->
                 b.addProguardConfiguration(
                     getProguardOptionsNPlus(enableProguardCompatibilityMode), Origin.unknown()))
-        .withDexCheck(inspector -> checkLambdaCount(inspector, 3, "lambdadesugaringnplus"))
+        .withDexCheck(inspector -> checkLambdaCount(inspector, 2, "lambdadesugaringnplus"))
         .run();
   }
 
diff --git a/src/test/java/com/android/tools/r8/TestAppViewBuilder.java b/src/test/java/com/android/tools/r8/TestAppViewBuilder.java
new file mode 100644
index 0000000..a13b972
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/TestAppViewBuilder.java
@@ -0,0 +1,107 @@
+// Copyright (c) 2021, 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;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.ProguardConfigurationRule;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ListUtils;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+public class TestAppViewBuilder {
+
+  private AndroidApp.Builder builder = AndroidApp.builder();
+  private List<Function<DexItemFactory, List<ProguardConfigurationRule>>> rules = new ArrayList<>();
+  private List<Consumer<InternalOptions>> optionModifications = new ArrayList<>();
+
+  public static TestAppViewBuilder builder() {
+    return new TestAppViewBuilder();
+  }
+
+  private TestAppViewBuilder() {}
+
+  public TestAppViewBuilder addProgramClasses(Class<?>... classes) {
+    return addProgramClasses(Arrays.asList(classes));
+  }
+
+  public TestAppViewBuilder addProgramClasses(Collection<Class<?>> classes) {
+    classes.forEach(clazz -> builder.addProgramFile(ToolHelper.getClassFileForTestClass(clazz)));
+    return this;
+  }
+
+  public TestAppViewBuilder addProgramClassFileData(byte[]... classes) {
+    return addProgramClassFileData(Arrays.asList(classes));
+  }
+
+  public TestAppViewBuilder addProgramClassFileData(Collection<byte[]> classes) {
+    builder.addClassProgramData(classes);
+    return this;
+  }
+
+  public TestAppViewBuilder addAndroidApp(AndroidApp app) {
+    app.getProgramResourceProviders().forEach(builder::addProgramResourceProvider);
+    app.getClasspathResourceProviders().forEach(builder::addClasspathResourceProvider);
+    app.getLibraryResourceProviders().forEach(builder::addLibraryResourceProvider);
+    assert !app.hasMainDexList() : "todo";
+    return this;
+  }
+
+  public TestAppViewBuilder addKeepAllRule() {
+    rules = null;
+    return this;
+  }
+
+  public TestAppViewBuilder addKeepMainRule(Class<?> mainClass) {
+    return addKeepRuleBuilder(
+        factory -> TestBase.buildKeepRuleForClassAndMethods(mainClass, factory));
+  }
+
+  public TestAppViewBuilder addKeepRuleBuilder(
+      Function<DexItemFactory, List<ProguardConfigurationRule>> ruleBuilder) {
+    if (rules != null) {
+      rules.add(ruleBuilder);
+    }
+    return this;
+  }
+
+  public TestAppViewBuilder addOptionsModification(Consumer<InternalOptions> optionsConsumer) {
+    optionModifications.add(optionsConsumer);
+    return this;
+  }
+
+  public AppView<AppInfoWithLiveness> buildWithLiveness() throws Exception {
+    return TestBase.computeAppViewWithLiveness(
+        builder.build(),
+        (rules == null
+            ? null
+            : factory ->
+                TestBase.buildConfigForRules(
+                    factory, ListUtils.flatMap(rules, r -> r.apply(factory)))),
+        options -> optionModifications.forEach(consumer -> consumer.accept(options)));
+  }
+
+  public TestAppViewBuilder setMinApi(AndroidApiLevel minApi) {
+    optionModifications.add(options -> options.minApiLevel = minApi);
+    return this;
+  }
+
+  public TestAppViewBuilder addLibraryFiles(Path... files) {
+    return addLibraryFiles(Arrays.asList(files));
+  }
+
+  public TestAppViewBuilder addLibraryFiles(List<Path> files) {
+    builder.addLibraryFiles(files);
+    return this;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index f93398c..8c52813 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -775,17 +775,18 @@
 
   protected static AppView<AppInfoWithLiveness> computeAppViewWithLiveness(AndroidApp app)
       throws Exception {
-    return computeAppViewWithLiveness(app, null, null);
+    return TestAppViewBuilder.builder().addAndroidApp(app).addKeepAllRule().buildWithLiveness();
   }
 
   protected static AppView<AppInfoWithLiveness> computeAppViewWithLiveness(
       AndroidApp app, Class<?> mainClass) throws Exception {
-    return computeAppViewWithLiveness(
-        app,
-        factory ->
-            buildConfigForRules(factory, buildKeepRuleForClassAndMethods(mainClass, factory)));
+    return TestAppViewBuilder.builder()
+        .addAndroidApp(app)
+        .addKeepMainRule(mainClass)
+        .buildWithLiveness();
   }
 
+  // We should try to get rid of this usage of keep rule building which is very internal.
   protected static AppView<AppInfoWithLiveness> computeAppViewWithLiveness(
       AndroidApp app, Function<DexItemFactory, ProguardConfiguration> keepConfig) throws Exception {
     return computeAppViewWithLiveness(app, keepConfig, null);
diff --git a/src/test/java/com/android/tools/r8/TestParameters.java b/src/test/java/com/android/tools/r8/TestParameters.java
index 1df89b1..7e230ef 100644
--- a/src/test/java/com/android/tools/r8/TestParameters.java
+++ b/src/test/java/com/android/tools/r8/TestParameters.java
@@ -31,6 +31,8 @@
 
   public boolean canUseDefaultAndStaticInterfaceMethods() {
     assert isCfRuntime() || isDexRuntime();
+    assert !isCfRuntime() || apiLevel == null
+        : "Use canUseDefaultAndStaticInterfaceMethodsWhenDesugaring when using CF api levels.";
     return isCfRuntime()
         || getApiLevel()
             .isGreaterThanOrEqualTo(TestBase.apiLevelWithDefaultInterfaceMethodsSupport());
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java
index e997894..a580fb1 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java
@@ -6,7 +6,7 @@
 
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
 import static com.android.tools.r8.utils.AndroidApiLevel.L_MR1;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isAbstract;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static junit.framework.TestCase.assertEquals;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -59,22 +59,22 @@
               } else {
                 ClassSubject aSubject = inspector.clazz(A.class);
                 ClassSubject apiCaller = inspector.clazz(ApiCaller.class);
-                assertThat(apiCaller, isPresent());
-                MethodSubject callApiLevel = apiCaller.uniqueMethodWithName("callApiLevel");
                 if (parameters.isCfRuntime()) {
+                  assert parameters.canUseDefaultAndStaticInterfaceMethods();
+                  assertThat(apiCaller, isPresent());
                   assertThat(aSubject, isPresent());
+                  MethodSubject callApiLevel = apiCaller.uniqueMethodWithName("callApiLevel");
                   assertThat(callApiLevel, CodeMatchers.invokesMethodWithName("apiLevel22"));
                 } else {
                   assert parameters.isDexRuntime();
-                  // TODO(b/191013385): A has a virtual method that calls callApiLevel on $CC, but
-                  //  that call should be inlined.
-                  assertThat(aSubject, isPresent());
-                  assertThat(callApiLevel, isAbstract());
-                  ClassSubject classSubject = apiCaller.toCompanionClass();
-                  assertThat(classSubject, isPresent());
-                  assertEquals(1, classSubject.allMethods().size());
+                  assert !parameters.canUseDefaultAndStaticInterfaceMethods();
+                  assertThat(apiCaller, isAbsent());
+                  assertThat(aSubject, isAbsent());
+                  ClassSubject companionClass = apiCaller.toCompanionClass();
+                  assertThat(companionClass, isPresent());
+                  assertEquals(1, companionClass.allMethods().size());
                   assertThat(
-                      classSubject.allMethods().get(0),
+                      companionClass.allMethods().get(0),
                       CodeMatchers.invokesMethodWithName("apiLevel22"));
                 }
               }
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfLambdaTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfLambdaTest.java
index 0525cd5..04dc573 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfLambdaTest.java
@@ -18,6 +18,7 @@
 import com.android.tools.r8.utils.codeinspector.CodeMatchers;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import java.lang.reflect.Method;
+import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -47,6 +48,7 @@
 
   @Test
   public void testR8() throws Exception {
+    Assume.assumeTrue("b/197494749", parameters.canUseDefaultAndStaticInterfaceMethods());
     Method apiMethod = Api.class.getDeclaredMethod("apiLevel22");
     testForR8(parameters.getBackend())
         .addProgramClasses(ApiCaller.class, Action.class, Main.class)
@@ -57,7 +59,6 @@
         .apply(setMockApiLevelForMethod(apiMethod, L_MR1))
         .apply(ApiModelingTestHelper::enableApiCallerIdentification)
         .allowAccessModification()
-        .noMinification()
         .compile()
         .inspect(
             inspector -> {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfStaticInterfaceMethodsTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfStaticInterfaceMethodsTest.java
index 1e2fd44..086cfa4 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfStaticInterfaceMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfStaticInterfaceMethodsTest.java
@@ -30,7 +30,7 @@
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   public ApiModelNoInliningOfStaticInterfaceMethodsTest(TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java b/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java
index e7c5ce1..51e4d41 100644
--- a/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java
@@ -7,6 +7,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import com.android.tools.r8.TestAppViewBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -20,6 +21,7 @@
 import com.android.tools.r8.graph.MethodResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.ProguardConfigurationRule;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import java.util.HashSet;
@@ -43,18 +45,18 @@
 
   private AppView<AppInfoWithLiveness> computeAppViewWithLiveness(
       Class<?> methodToBeKept, Class<?> classToBeKept) throws Exception {
-    return computeAppViewWithLiveness(
-        buildClasses(I.class, J.class, K.class, L.class, A.class, Main.class)
-            .addLibraryFile(ToolHelper.getJava8RuntimeJar())
-            .build(),
-        factory ->
-            buildConfigForRules(
-                factory,
+    return TestAppViewBuilder.builder()
+        .addProgramClasses(I.class, J.class, K.class, L.class, A.class, Main.class)
+        .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
+        .addKeepRuleBuilder(
+            factory ->
                 ImmutableList.<ProguardConfigurationRule>builder()
                     .addAll(buildKeepRuleForClassAndMethods(methodToBeKept, factory))
                     .addAll(buildKeepRuleForClass(classToBeKept, factory))
                     .addAll(buildKeepRuleForClassAndMethods(Main.class, factory))
-                    .build()));
+                    .build())
+        .setMinApi(AndroidApiLevel.N)
+        .buildWithLiveness();
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndInterfaceMethodCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndInterfaceMethodCollisionTest.java
index f440689..837f374 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndInterfaceMethodCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndInterfaceMethodCollisionTest.java
@@ -9,7 +9,6 @@
 import com.android.tools.r8.NoUnusedInterfaceRemoval;
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
 import org.junit.Test;
 
 public class PrivateAndInterfaceMethodCollisionTest extends HorizontalClassMergingTestBase {
@@ -24,7 +23,15 @@
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
         .addHorizontallyMergedClassesInspector(
-            HorizontallyMergedClassesInspector::assertNoClassesMerged)
+            i -> {
+              if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
+                i.assertClassesMerged();
+              } else {
+                // With default method desugaring all uses of J::foo are eliminated so A and B
+                // merge.
+                i.assertIsCompleteMergeGroup(A.class, B.class);
+              }
+            })
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .enableNoUnusedInterfaceRemovalAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndInterfaceMethodCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndInterfaceMethodCollisionTest.java
index 48844ff..c21469c 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndInterfaceMethodCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndInterfaceMethodCollisionTest.java
@@ -9,7 +9,6 @@
 import com.android.tools.r8.NoUnusedInterfaceRemoval;
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
 import org.junit.Test;
 
 public class StaticAndInterfaceMethodCollisionTest extends HorizontalClassMergingTestBase {
@@ -24,7 +23,15 @@
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
         .addHorizontallyMergedClassesInspector(
-            HorizontallyMergedClassesInspector::assertNoClassesMerged)
+            i -> {
+              if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
+                i.assertNoClassesMerged();
+              } else {
+                // When desugaring the call to C.foo in main will be inlined to target the CC.
+                // With J.foo now unused the classes A and B are safe to merge.
+                i.assertIsCompleteMergeGroup(A.class, B.class);
+              }
+            })
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .enableNoUnusedInterfaceRemovalAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideAbstractMethodWithDefaultTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideAbstractMethodWithDefaultTest.java
index e2eef5f..4e38b33 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideAbstractMethodWithDefaultTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideAbstractMethodWithDefaultTest.java
@@ -30,7 +30,9 @@
         .addHorizontallyMergedClassesInspector(
             inspector ->
                 inspector
-                    .assertIsCompleteMergeGroup(I.class, J.class)
+                    .applyIf(
+                        parameters.canUseDefaultAndStaticInterfaceMethods(),
+                        i -> i.assertIsCompleteMergeGroup(I.class, J.class))
                     .applyIf(
                         !parameters.canUseDefaultAndStaticInterfaceMethods(),
                         i -> i.assertIsCompleteMergeGroup(B1.class, B2.class))
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultMethodTest.java
index 0af1e85..f7f2e0d 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultMethodTest.java
@@ -14,6 +14,7 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.classmerging.horizontal.HorizontalClassMergingTestBase;
 import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
+import org.junit.Assume;
 import org.junit.Test;
 
 public class OverrideDefaultMethodTest extends HorizontalClassMergingTestBase {
@@ -23,6 +24,7 @@
 
   @Test
   public void testR8() throws Exception {
+    Assume.assumeTrue("b/197494749", parameters.canUseDefaultAndStaticInterfaceMethods());
     testForR8(parameters.getBackend())
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultOnSuperMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultOnSuperMethodTest.java
index 0ea8597..313dec7 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultOnSuperMethodTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultOnSuperMethodTest.java
@@ -38,11 +38,17 @@
                 inspector.assertNoClassesMerged();
               } else {
                 inspector
-                    .assertClassesNotMerged(A.class, B.class)
                     .assertIsCompleteMergeGroup(I.class, J.class)
-                    .assertIsCompleteMergeGroup(
-                        SyntheticItemsTestUtils.syntheticCompanionClass(I.class),
-                        SyntheticItemsTestUtils.syntheticCompanionClass(J.class))
+                    .applyIf(
+                        parameters.canUseDefaultAndStaticInterfaceMethods(),
+                        i ->
+                            i.assertClassesNotMerged(A.class, B.class)
+                                .assertIsCompleteMergeGroup(
+                                    SyntheticItemsTestUtils.syntheticCompanionClass(I.class),
+                                    SyntheticItemsTestUtils.syntheticCompanionClass(J.class)))
+                    .applyIf(
+                        !parameters.canUseDefaultAndStaticInterfaceMethods(),
+                        i -> i.assertClassesMerged(A.class, B.class))
                     .assertNoOtherClassesMerged();
               }
             })
@@ -56,7 +62,9 @@
                   onlyIf(parameters.canUseDefaultAndStaticInterfaceMethods(), isPresent()));
               assertThat(codeInspector.clazz(Parent.class), isPresent());
               assertThat(codeInspector.clazz(A.class), isPresent());
-              assertThat(codeInspector.clazz(B.class), isPresent());
+              assertThat(
+                  codeInspector.clazz(B.class),
+                  onlyIf(parameters.canUseDefaultAndStaticInterfaceMethods(), isPresent()));
               assertThat(codeInspector.clazz(C.class), isPresent());
             });
   }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideMergeAbsentTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideMergeAbsentTest.java
index 6f5e761..1ec170d 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideMergeAbsentTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideMergeAbsentTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.classmerging.horizontal.dispatch;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 
@@ -12,7 +13,6 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.classmerging.horizontal.HorizontalClassMergingTestBase;
-import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
 import org.junit.Test;
 
 public class OverrideMergeAbsentTest extends HorizontalClassMergingTestBase {
@@ -30,14 +30,23 @@
         .enableNoVerticalClassMergingAnnotations()
         .setMinApi(parameters.getApiLevel())
         .addHorizontallyMergedClassesInspector(
-            HorizontallyMergedClassesInspector::assertNoClassesMerged)
+            inspector -> {
+              if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
+                inspector.assertNoClassesMerged();
+              } else {
+                // When desugaring B.m is moved and A and B can be merged.
+                inspector.assertIsCompleteMergeGroup(A.class, B.class);
+              }
+            })
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("A", "B", "A", "J")
         .inspect(
             codeInspector -> {
               assertThat(codeInspector.clazz(J.class), isPresent());
               assertThat(codeInspector.clazz(A.class), isPresent());
-              assertThat(codeInspector.clazz(B.class), isPresent());
+              assertThat(
+                  codeInspector.clazz(B.class),
+                  parameters.canUseDefaultAndStaticInterfaceMethods() ? isPresent() : isAbsent());
               assertThat(codeInspector.clazz(C.class), isPresent());
             });
   }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodOutsideMergeGroupAfterSubclassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodOutsideMergeGroupAfterSubclassMergingTest.java
index cc19dd2..6529d20 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodOutsideMergeGroupAfterSubclassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodOutsideMergeGroupAfterSubclassMergingTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.classmerging.horizontal.interfaces;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isImplementing;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -55,11 +56,10 @@
                   .assertMergedInto(B.class, A.class);
               if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
                 inspector.assertClassesNotMerged(I.class, J.class, K.class);
-              } else {
-                inspector
-                    .assertIsCompleteMergeGroup(I.class, J.class)
-                    .assertClassesNotMerged(K.class);
+              } else if (enableInterfaceMergingInInitial) {
+                inspector.assertIsCompleteMergeGroup(I.class, J.class);
               }
+              inspector.assertNoOtherClassesMerged();
             })
         .addOptionsModification(
             options -> {
@@ -82,14 +82,12 @@
               assertThat(aClassSubject, isImplementing(inspector.clazz(K.class)));
 
               ClassSubject cClassSubject = inspector.clazz(C.class);
-              assertThat(cClassSubject, isPresent());
-              assertThat(
-                  cClassSubject,
-                  isImplementing(
-                      inspector.clazz(
-                          parameters.canUseDefaultAndStaticInterfaceMethods()
-                              ? J.class
-                              : I.class)));
+              if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
+                assertThat(cClassSubject, isPresent());
+                assertThat(cClassSubject, isImplementing(inspector.clazz(J.class)));
+              } else {
+                assertThat(cClassSubject, isAbsent());
+              }
             })
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("A", "K", "J");
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodOutsideMergeGroupClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodOutsideMergeGroupClassTest.java
index e18ce93..5ee0365 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodOutsideMergeGroupClassTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodOutsideMergeGroupClassTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.classmerging.horizontal.interfaces;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isImplementing;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -16,7 +17,9 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -37,6 +40,7 @@
 
   @Test
   public void test() throws Exception {
+    Assume.assumeTrue("b/197494749", parameters.canUseDefaultAndStaticInterfaceMethods());
     testForR8(parameters.getBackend())
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
@@ -47,7 +51,10 @@
               if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
                 inspector.assertNoClassesMerged();
               } else {
-                inspector.assertIsCompleteMergeGroup(I.class, J.class);
+                // J is removed as part of desugaring. This enables merging of its CC class.
+                inspector.assertIsCompleteMergeGroup(
+                    SyntheticItemsTestUtils.syntheticCompanionClass(J.class),
+                    SyntheticItemsTestUtils.syntheticCompanionClass(K.class));
               }
             })
         .enableInliningAnnotations()
@@ -60,19 +67,18 @@
         .inspect(
             inspector -> {
               ClassSubject aClassSubject = inspector.clazz(A.class);
-              assertThat(aClassSubject, isPresent());
-              assertThat(aClassSubject, isImplementing(inspector.clazz(I.class)));
-              assertThat(aClassSubject, isImplementing(inspector.clazz(K.class)));
-
               ClassSubject bClassSubject = inspector.clazz(B.class);
-              assertThat(bClassSubject, isPresent());
-              assertThat(
-                  bClassSubject,
-                  isImplementing(
-                      inspector.clazz(
-                          parameters.canUseDefaultAndStaticInterfaceMethods()
-                              ? J.class
-                              : I.class)));
+              if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
+                assertThat(aClassSubject, isPresent());
+                assertThat(aClassSubject, isImplementing(inspector.clazz(I.class)));
+                assertThat(aClassSubject, isImplementing(inspector.clazz(K.class)));
+                assertThat(bClassSubject, isPresent());
+                assertThat(bClassSubject, isImplementing(inspector.clazz(J.class)));
+              } else {
+                // When desugaring the calls in main will directly target the CC classes.
+                assertThat(aClassSubject, isAbsent());
+                assertThat(bClassSubject, isAbsent());
+              }
             })
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("K", "J");
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodOutsideMergeGroupLambdaTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodOutsideMergeGroupLambdaTest.java
index 2324f03..a1dbbaf 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodOutsideMergeGroupLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodOutsideMergeGroupLambdaTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.classmerging.horizontal.interfaces;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isImplementing;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -61,11 +62,15 @@
         .inspect(
             inspector -> {
               ClassSubject aClassSubject = inspector.clazz(A.class);
-              assertThat(aClassSubject, isPresent());
-              if (parameters.isCfRuntime()) {
-                assertThat(aClassSubject, isImplementing(inspector.clazz(I.class)));
+              if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
+                assertThat(aClassSubject, isPresent());
+                if (parameters.isCfRuntime()) {
+                  assertThat(aClassSubject, isImplementing(inspector.clazz(I.class)));
+                } else {
+                  assertThat(aClassSubject, isImplementing(inspector.clazz(J.class)));
+                }
               } else {
-                assertThat(aClassSubject, isImplementing(inspector.clazz(J.class)));
+                assertThat(aClassSubject, isAbsent());
               }
             })
         .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/DisjointInterfacesWithDefaultMethodsMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/DisjointInterfacesWithDefaultMethodsMergingTest.java
index 5a656d9..2c40a58 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/DisjointInterfacesWithDefaultMethodsMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/DisjointInterfacesWithDefaultMethodsMergingTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.classmerging.horizontal.interfaces;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isImplementing;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -40,7 +41,13 @@
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
         .addHorizontallyMergedClassesInspector(
-            inspector -> inspector.assertIsCompleteMergeGroup(I.class, J.class))
+            inspector -> {
+              if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
+                inspector.assertIsCompleteMergeGroup(I.class, J.class);
+              } else {
+                inspector.assertNoClassesMerged();
+              }
+            })
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .enableNoUnusedInterfaceRemovalAnnotations()
@@ -50,8 +57,12 @@
         .inspect(
             inspector -> {
               ClassSubject aClassSubject = inspector.clazz(A.class);
-              assertThat(aClassSubject, isPresent());
-              assertThat(aClassSubject, isImplementing(inspector.clazz(I.class)));
+              if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
+                assertThat(aClassSubject, isPresent());
+                assertThat(aClassSubject, isImplementing(inspector.clazz(I.class)));
+              } else {
+                assertThat(aClassSubject, isAbsent());
+              }
             })
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("I", "J");
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/NoDefaultMethodMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/NoDefaultMethodMergingTest.java
index a84dbac..f68dd90 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/NoDefaultMethodMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/NoDefaultMethodMergingTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.classmerging.horizontal.interfaces;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isImplementing;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -17,6 +18,7 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -42,13 +44,7 @@
         .addKeepMainRule(Main.class)
         // I and J are not eligible for merging, since they declare the same default method.
         .addHorizontallyMergedClassesInspector(
-            inspector -> {
-              if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
-                inspector.assertNoClassesMerged();
-              } else {
-                inspector.assertIsCompleteMergeGroup(I.class, J.class);
-              }
-            })
+            HorizontallyMergedClassesInspector::assertNoClassesMerged)
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .enableNoHorizontalClassMergingAnnotations()
@@ -59,10 +55,17 @@
         .inspect(
             inspector -> {
               ClassSubject aClassSubject = inspector.clazz(A.class);
+              ClassSubject bClassSubject = inspector.clazz(B.class);
+              if (!parameters.canUseDefaultAndStaticInterfaceMethods()) {
+                // When desugaring, the forwarding methods to the CC.m methods will be inlined and
+                // the class instances become dead code.
+                assertThat(aClassSubject, isAbsent());
+                assertThat(bClassSubject, isAbsent());
+                return;
+              }
               assertThat(aClassSubject, isPresent());
               assertThat(aClassSubject, isImplementing(inspector.clazz(I.class)));
 
-              ClassSubject bClassSubject = inspector.clazz(B.class);
               assertThat(bClassSubject, isPresent());
               assertThat(
                   bClassSubject,
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
index 2f157d0..3b35a12 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
@@ -50,6 +50,7 @@
 import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
+import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -355,6 +356,7 @@
 
   @Test
   public void testNestedDefaultInterfaceMethodsTest() throws Throwable {
+    Assume.assumeTrue("b/197494749", parameters.canUseDefaultAndStaticInterfaceMethods());
     String main = "classmerging.NestedDefaultInterfaceMethodsTest";
     Path[] programFiles =
         new Path[] {
diff --git a/src/test/java/com/android/tools/r8/code/invokedynamic/InvokeDynamicVirtualDispatchToDefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/code/invokedynamic/InvokeDynamicVirtualDispatchToDefaultInterfaceMethodTest.java
new file mode 100644
index 0000000..7494b13
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/code/invokedynamic/InvokeDynamicVirtualDispatchToDefaultInterfaceMethodTest.java
@@ -0,0 +1,144 @@
+// Copyright (c) 2021, 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.code.invokedynamic;
+
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.StringUtils;
+import java.lang.invoke.CallSite;
+import java.lang.invoke.ConstantCallSite;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Test invokedynamic with a static bootstrap method with an extra arg that is a MethodHandle of
+ * kind invoke virtual. The target method is a method into a class implementing an abstract method
+ * and that shadows a default method from an interface.
+ */
+// TODO(b/167145686): Copy this test and implement all of the variants in
+//  ...AndroidOTest.invokeCustom... and then delete those tests.
+@RunWith(Parameterized.class)
+public class InvokeDynamicVirtualDispatchToDefaultInterfaceMethodTest extends TestBase {
+
+  static final String EXPECTED = StringUtils.lines("Called I.foo");
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters()
+        .withAllRuntimes()
+        .withApiLevelsStartingAtIncluding(apiLevelWithInvokeCustomSupport())
+        .enableApiLevelsForCf()
+        .build();
+  }
+
+  public InvokeDynamicVirtualDispatchToDefaultInterfaceMethodTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testReference() throws Exception {
+    testForDesugaring(parameters)
+        .addProgramClasses(I.class, A.class)
+        .addProgramClassFileData(getTransformedTestClass())
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    assumeTrue(
+        "Only test one R8/CF build.",
+        parameters.isDexRuntime() || parameters.getApiLevel() == apiLevelWithInvokeCustomSupport());
+    testForR8(parameters.getBackend())
+        .allowAccessModification()
+        .addProgramClasses(I.class, A.class)
+        .addProgramClassFileData(getTransformedTestClass())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(TestClass.class)
+        .addKeepRules("-keepclassmembers class * { *** foo(...); }")
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  private byte[] getTransformedTestClass() throws Exception {
+    ClassReference aClass = Reference.classFromClass(A.class);
+    MethodReference iFoo = Reference.methodFromMethod(I.class.getDeclaredMethod("foo"));
+    MethodReference bsm =
+        Reference.methodFromMethod(
+            TestClass.class.getDeclaredMethod(
+                "bsmCreateCallSite",
+                Lookup.class,
+                String.class,
+                MethodType.class,
+                MethodHandle.class));
+    return transformer(TestClass.class)
+        .transformMethodInsnInMethod(
+            "main",
+            (opcode, owner, name, descriptor, isInterface, visitor) -> {
+              if (name.equals("replaced")) {
+                visitor.visitInvokeDynamicInsn(
+                    iFoo.getMethodName(),
+                    "(" + aClass.getDescriptor() + ")V",
+                    new Handle(
+                        Opcodes.H_INVOKESTATIC,
+                        bsm.getHolderClass().getBinaryName(),
+                        bsm.getMethodName(),
+                        bsm.getMethodDescriptor(),
+                        false),
+                    new Handle(
+                        Opcodes.H_INVOKEVIRTUAL,
+                        aClass.getBinaryName(),
+                        iFoo.getMethodName(),
+                        iFoo.getMethodDescriptor(),
+                        false));
+              } else {
+                visitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+              }
+            })
+        .transform();
+  }
+
+  public interface I {
+
+    default void foo() {
+      System.out.println("Called I.foo");
+    }
+  }
+
+  public static class A implements I {
+    // Instantiation with default from I.
+  }
+
+  static class TestClass {
+
+    public static CallSite bsmCreateCallSite(
+        MethodHandles.Lookup caller, String name, MethodType type, MethodHandle handle)
+        throws Throwable {
+      return new ConstantCallSite(handle);
+    }
+
+    public static void replaced(Object o) {
+      throw new RuntimeException("unreachable!");
+    }
+
+    public static void main(String[] args) {
+      replaced(new A());
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithUnderscoreThisTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithUnderscoreThisTestRunner.java
index 7cde792..2e9abfb 100644
--- a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithUnderscoreThisTestRunner.java
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithUnderscoreThisTestRunner.java
@@ -100,9 +100,9 @@
         testForD8()
             .addProgramClassesAndInnerClasses(CLASS)
             .setMinApiThreshold(AndroidApiLevel.K)
-            .compile();
+            .compile()
+            .assertNoMessages();
     compileResult
-        // TODO(b/123506120): Add .assertNoMessages()
         .run(parameters.getRuntime(), CLASS)
         .assertSuccessWithOutput(EXPECTED);
     runDebugger(compileResult.debugConfig(), true);
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarInnerClassesInInterfaces.java b/src/test/java/com/android/tools/r8/desugar/DesugarInnerClassesInInterfaces.java
index 1c8d5b9..8902cd2 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarInnerClassesInInterfaces.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarInnerClassesInInterfaces.java
@@ -4,11 +4,13 @@
 package com.android.tools.r8.desugar;
 
 import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix;
+import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.DesugarTestConfiguration;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
 import java.util.concurrent.Callable;
@@ -30,13 +32,6 @@
           WithLocalInner.class.getName() + getCompanionClassNameSuffix(),
           "true");
 
-  private final List<String> EXPECTED_RESULT_WITH_DESUGARING_B168697955 =
-      ImmutableList.of(
-          WithAnonymousInner.class.getName() + getCompanionClassNameSuffix(),
-          "false",
-          WithLocalInner.class.getName() + getCompanionClassNameSuffix(),
-          "false");
-
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
@@ -69,6 +64,7 @@
 
   @Test
   public void testR8Compat() throws Exception {
+    assumeTrue(parameters.isDexRuntime() || parameters.getApiLevel() == AndroidApiLevel.B);
     testForR8Compat(parameters.getBackend())
         .addInnerClasses(DesugarInnerClassesInInterfaces.class)
         .setMinApi(parameters.getApiLevel())
@@ -78,37 +74,14 @@
         .compile()
         .run(parameters.getRuntime(), TestClass.class)
         .applyIf(
-            parameters.canUseDefaultAndStaticInterfaceMethods(),
+            parameters.isCfRuntime() || parameters.canUseDefaultAndStaticInterfaceMethods(),
             result -> result.assertSuccessWithOutputLines(EXPECTED_RESULT_WITHOUT_DESUGARING),
-            // The static method which is moved to the companion class is inlined and causing
-            // this different output. The rule "-keep class * { *; }" does not keep the static
-            // method from being inlined after it has moved. Turning off inlining produces the
-            // expected result. The inlining cause the getEnclosingClass() to return null.
-            // See b/168697955.
-            result ->
-                result.assertSuccessWithOutputLines(EXPECTED_RESULT_WITH_DESUGARING_B168697955));
-  }
-
-  @Test
-  public void testR8_B168697955() throws Exception {
-    testForR8(parameters.getBackend())
-        .addInnerClasses(DesugarInnerClassesInInterfaces.class)
-        .setMinApi(parameters.getApiLevel())
-        .addKeepAllClassesRule()
-        .addKeepAttributeInnerClassesAndEnclosingMethod()
-        // With inlining turned off we get the expected result.
-        .addOptionsModification(options -> options.enableInlining = false)
-        .compile()
-        .run(parameters.getRuntime(), TestClass.class)
-        .applyIf(
-            parameters.canUseDefaultAndStaticInterfaceMethods(),
-            result -> result.assertSuccessWithOutputLines(EXPECTED_RESULT_WITHOUT_DESUGARING),
-            // TODO(b/187377562): We remove the attribute due to not pinning the moved methods.
-            result -> result.assertFailureWithErrorThatThrows(NullPointerException.class));
+            result -> result.assertSuccessWithOutputLines(EXPECTED_RESULT_WITH_DESUGARING));
   }
 
   @Test
   public void testR8Full() throws Exception {
+    assumeTrue(parameters.isDexRuntime() || parameters.getApiLevel() == AndroidApiLevel.B);
     testForR8(parameters.getBackend())
         .addInnerClasses(DesugarInnerClassesInInterfaces.class)
         .setMinApi(parameters.getApiLevel())
@@ -117,10 +90,9 @@
         .compile()
         .run(parameters.getRuntime(), TestClass.class)
         .applyIf(
-            parameters.canUseDefaultAndStaticInterfaceMethods(),
+            parameters.isCfRuntime() || parameters.canUseDefaultAndStaticInterfaceMethods(),
             result -> result.assertSuccessWithOutputLines(EXPECTED_RESULT_WITHOUT_DESUGARING),
-            // TODO(b/187377562): We remove the attribute due to not pinning the moved methods.
-            result -> result.assertFailureWithErrorThatThrows(NullPointerException.class));
+            result -> result.assertSuccessWithOutputLines(EXPECTED_RESULT_WITH_DESUGARING));
   }
 
   interface WithAnonymousInner {
diff --git a/src/test/java/com/android/tools/r8/desugar/enclosingmethod/EnclosingMethodRewriteTest.java b/src/test/java/com/android/tools/r8/desugar/enclosingmethod/EnclosingMethodRewriteTest.java
index e7cc9c9..9a47de9 100644
--- a/src/test/java/com/android/tools/r8/desugar/enclosingmethod/EnclosingMethodRewriteTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/enclosingmethod/EnclosingMethodRewriteTest.java
@@ -6,7 +6,6 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
@@ -73,8 +72,6 @@
         "interface " + A.class.getTypeName(), "public int " + A.class.getTypeName() + ".def()", "42"
       };
 
-  private final String[] EXPECTED_FULL = new String[] {"null", "null", "42"};
-
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters().withAllRuntimesAndApiLevels().build();
@@ -102,7 +99,7 @@
         .addKeepAttributeInnerClassesAndEnclosingMethod()
         .setMinApi(parameters.getApiLevel())
         .compile()
-        .inspect(inspector -> inspect(inspector, true))
+        .inspect(this::inspect)
         .run(parameters.getRuntime(), MAIN)
         .applyIf(
             parameters.canUseDefaultAndStaticInterfaceMethods(),
@@ -126,8 +123,7 @@
         .addKeepAttributeInnerClassesAndEnclosingMethod()
         .setMinApi(parameters.getApiLevel())
         .compile()
-        .inspect(
-            inspector -> inspect(inspector, parameters.canUseDefaultAndStaticInterfaceMethods()))
+        .inspect(this::inspect)
         .run(parameters.getRuntime(), MAIN)
         .applyIf(
             parameters.canUseDefaultAndStaticInterfaceMethods(),
@@ -139,25 +135,21 @@
                 result.assertSuccessWithOutputLines(EXPECTED);
               }
             },
-            result -> result.assertSuccessWithOutputLines(EXPECTED_FULL));
+            result -> result.assertSuccessWithOutputLines(EXPECTED_CC));
   }
 
-  private void inspect(CodeInspector inspector, boolean hasEnclosingMethod) {
+  private void inspect(CodeInspector inspector) {
     ClassSubject cImplSubject = inspector.clazz(A.class.getTypeName() + "$1");
     assertThat(cImplSubject, isPresent());
     ClassSubject enclosingClassSubject =
         parameters.canUseDefaultAndStaticInterfaceMethods()
             ? inspector.clazz(A.class.getTypeName())
-            : inspector.clazz(A.class.getTypeName() + "$-CC");
+            : inspector.clazz(A.class.getTypeName()).toCompanionClass();
     assertThat(enclosingClassSubject, isPresent());
     EnclosingMethodAttribute enclosingMethodAttribute =
         cImplSubject.getDexProgramClass().getEnclosingMethodAttribute();
-    if (hasEnclosingMethod) {
-      assertEquals(
-          enclosingClassSubject.getDexProgramClass().getType(),
-          enclosingMethodAttribute.getEnclosingMethod().getHolderType());
-    } else {
-      assertNull(enclosingMethodAttribute);
-    }
+    assertEquals(
+        enclosingClassSubject.getDexProgramClass().getType(),
+        enclosingMethodAttribute.getEnclosingMethod().getHolderType());
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/staticinterfacemethod/InvokeStaticDesugarTest.java b/src/test/java/com/android/tools/r8/desugar/staticinterfacemethod/InvokeStaticDesugarTest.java
index 35e52b4..8cd35aa 100644
--- a/src/test/java/com/android/tools/r8/desugar/staticinterfacemethod/InvokeStaticDesugarTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/staticinterfacemethod/InvokeStaticDesugarTest.java
@@ -7,6 +7,7 @@
 import static com.android.tools.r8.desugar.staticinterfacemethod.InvokeStaticDesugarTest.Library.foo;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeFalse;
 
@@ -151,12 +152,14 @@
 
   private Set<FoundMethodSubject> getSyntheticMethods(CodeInspector inspector) {
     Set<FoundMethodSubject> methods = new HashSet<>();
-    assert inspector.allClasses().stream()
-        .allMatch(
+    inspector
+        .allClasses()
+        .forEach(
             c ->
-                !SyntheticItemsTestUtils.isExternalSynthetic(c.getFinalReference())
-                    || SyntheticItemsTestUtils.isExternalStaticInterfaceCall(
-                        c.getFinalReference()));
+                assertTrue(
+                    !SyntheticItemsTestUtils.isExternalSynthetic(c.getFinalReference())
+                        || SyntheticItemsTestUtils.isExternalStaticInterfaceCall(
+                            c.getFinalReference())));
     inspector.allClasses().stream()
         .filter(c -> SyntheticItemsTestUtils.isExternalStaticInterfaceCall(c.getFinalReference()))
         .forEach(c -> methods.addAll(c.allMethods(m -> !m.isInstanceInitializer())));
diff --git a/src/test/java/com/android/tools/r8/desugar/staticinterfacemethod/MutuallyRecursiveMethodsTest.java b/src/test/java/com/android/tools/r8/desugar/staticinterfacemethod/MutuallyRecursiveMethodsTest.java
index ee911d3..dfbbd6e 100644
--- a/src/test/java/com/android/tools/r8/desugar/staticinterfacemethod/MutuallyRecursiveMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/staticinterfacemethod/MutuallyRecursiveMethodsTest.java
@@ -35,6 +35,16 @@
         .assertSuccessWithOutput(EXPECTED);
   }
 
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(MutuallyRecursiveMethodsTest.class)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(TestClass.class)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
   interface I {
     static boolean isEven(int i) {
       return i == 0 || isOdd(i - 1);
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java
index 12869e2..c960b33 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java
@@ -102,22 +102,21 @@
   private void checkResult(TestRunResult<?> result, boolean isR8) {
     // Invalid invoke case is where the invoke-virtual targets C.m.
     if (invalidInvoke) {
-      if (parameters.isCfRuntime()) {
-        result.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
-        return;
-      }
-      if (parameters.getDexRuntimeVersion().isInRangeInclusive(Version.V5_1_1, Version.V7_0_0)) {
+      if (parameters.isDexRuntimeVersion(Version.V7_0_0)
+          && parameters.canUseDefaultAndStaticInterfaceMethodsWhenDesugaring()) {
+        // The v7 VM incorrectly fails to throw.
         result.assertSuccessWithOutput(EXPECTED);
-        return;
+      } else {
+        result.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
       }
-      result.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
       return;
     }
 
     if (isR8
         && parameters.isDexRuntime()
         && parameters.getDexRuntimeVersion().isNewerThan(Version.V6_0_1)
-        && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0)) {
+        && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0)
+        && parameters.canUseDefaultAndStaticInterfaceMethodsWhenDesugaring()) {
       // TODO(b/182255398): This should be EXPECTED.
       result.assertSuccessWithOutput(EXPECTED_R8);
       return;
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionOnClassTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionOnClassTest.java
index 1684c5a..b5949f7 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionOnClassTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionOnClassTest.java
@@ -70,10 +70,9 @@
         .setMinApi(parameters.getApiLevel())
         .compile()
         .run(parameters.getRuntime(), TestClass.class)
-        // TODO(b/182335909): Ideally, this should also throw ICCE when desugaring.
         .applyIf(
-            !parameters.canUseDefaultAndStaticInterfaceMethodsWhenDesugaring()
-                || parameters.isDexRuntimeVersion(Version.V7_0_0),
+            parameters.canUseDefaultAndStaticInterfaceMethodsWhenDesugaring()
+                && parameters.isDexRuntimeVersion(Version.V7_0_0),
             r -> r.assertSuccessWithOutput(EXPECTED_INVALID),
             r -> r.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class));
   }
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodToNonImmediateInterfaceTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodToNonImmediateInterfaceTest.java
index 698cf50..f4fec42 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodToNonImmediateInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodToNonImmediateInterfaceTest.java
@@ -16,6 +16,7 @@
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.collect.ImmutableList;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -36,6 +37,11 @@
   }
 
   @Test
+  @Ignore("b/197494749 and b/120130831")
+  // TODO(b/197494749): Update this test now that desugaring is moved up. In particular this must
+  //  be rewritten with CF based transformers as R8 does not support interface desugaring on DEX.
+  // TODO(b/120130831): With the move of desugaring this issue should be resolved. The bug indicates
+  //  that a workaround for issues related to the IR implementation can now be reverted.
   public void test() throws Exception {
     // Note that the expected output is independent of the presence of J.m().
     String expectedOutput = StringUtils.lines("I.m()", "JImpl.m()");
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/InterfaceEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/InterfaceEnumUnboxingTest.java
index 2f27855..3bc5c02 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/InterfaceEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/InterfaceEnumUnboxingTest.java
@@ -59,9 +59,12 @@
                             SuccessUnusedDefaultMethod.EnumInterface.class,
                             SuccessUnusedDefaultMethodOverride.EnumInterface.class,
                             SuccessUnusedDefaultMethodOverrideEnum.EnumInterface.class)
-                        .assertNotUnboxed(
-                            FailureDefaultMethodUsed.EnumInterface.class,
-                            FailureUsedAsInterface.EnumInterface.class))
+                        .assertNotUnboxed(FailureUsedAsInterface.EnumInterface.class)
+                        // When desugaring interfaces the dispatch will inline the forwarding method
+                        // to the CC method allowing unboxing.
+                        .assertUnboxedIf(
+                            !parameters.canUseDefaultAndStaticInterfaceMethods(),
+                            FailureDefaultMethodUsed.EnumInterface.class))
             .noMinification()
             .enableNoVerticalClassMergingAnnotations()
             .enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/graph/invokespecial/InvokeSpecialOnOtherInterfaceTest.java b/src/test/java/com/android/tools/r8/graph/invokespecial/InvokeSpecialOnOtherInterfaceTest.java
index 509bfa2..99ab7b3 100644
--- a/src/test/java/com/android/tools/r8/graph/invokespecial/InvokeSpecialOnOtherInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/graph/invokespecial/InvokeSpecialOnOtherInterfaceTest.java
@@ -38,9 +38,9 @@
         .addProgramClasses(I.class)
         .addProgramClassFileData(getClassWithTransformedInvoked())
         .run(parameters.getRuntime(), Main.class)
+        .assertFailureWithErrorThatThrowsIf(parameters.isCfRuntime(), VerifyError.class)
         // TODO(b/144410139): Consider making this a compilation failure when generating DEX.
-        .assertSuccessWithOutputLinesIf(parameters.isDexRuntime(), "Hello World!")
-        .assertFailureWithErrorThatThrowsIf(parameters.isCfRuntime(), VerifyError.class);
+        .assertSuccessWithOutputLinesIf(parameters.isDexRuntime(), "Hello World!");
   }
 
   @Test
@@ -52,11 +52,14 @@
         .addKeepMainRule(Main.class)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), Main.class)
-        .assertFailureWithErrorThatThrows(
-            parameters.isCfRuntime()
-                ? VerifyError.class
-                // TODO(b/144410139): Consider making this a compilation failure.
-                : NullPointerException.class);
+        .assertFailureWithErrorThatThrowsIf(parameters.isCfRuntime(), VerifyError.class)
+        // TODO(b/144410139): Consider making this a compilation failure when generating DEX.
+        .assertSuccessWithOutputLinesIf(
+            parameters.isDexRuntime() && !parameters.canUseDefaultAndStaticInterfaceMethods(),
+            "Hello World!")
+        .assertFailureWithErrorThatThrowsIf(
+            parameters.isDexRuntime() && parameters.canUseDefaultAndStaticInterfaceMethods(),
+            NullPointerException.class);
   }
 
   private byte[] getClassWithTransformedInvoked() throws IOException {
diff --git a/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest.java b/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest.java
index f989728..a8a222d 100644
--- a/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest.java
+++ b/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest.java
@@ -12,7 +12,6 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -38,10 +37,7 @@
     testForJvm()
         .addInnerClasses(getClass())
         .run(parameters.getRuntime(), Main.class)
-        .applyIf(
-            parameters.isCfRuntime(CfVm.JDK11),
-            r -> r.assertSuccessWithOutputLines("I::foo"),
-            r -> r.assertFailureWithErrorThatThrows(IllegalAccessError.class));
+        .apply(r -> assertResultIsCorrect(r, true));
   }
 
   @Test
@@ -50,7 +46,7 @@
         .addInnerClasses(getClass())
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), Main.class)
-        .apply(this::assertResultIsCorrect);
+        .apply(r -> assertResultIsCorrect(r, false));
   }
 
   @Test
@@ -63,17 +59,23 @@
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), Main.class)
         // TODO(b/182189123): This should have the same behavior as D8.
-        .assertSuccessWithOutputLines("I::foo");
+        .applyIf(
+            parameters.isCfRuntime(),
+            r -> r.assertSuccessWithOutputLines("I::foo"),
+            r -> assertResultIsCorrect(r, true));
   }
 
-  public void assertResultIsCorrect(SingleTestRunResult<?> result) {
-    if (parameters.isCfRuntime(CfVm.JDK11)
-        && parameters.getApiLevel().isGreaterThan(AndroidApiLevel.M)) {
+  public void assertResultIsCorrect(SingleTestRunResult<?> result, boolean nonDesugaredCf) {
+    boolean isNotDesugared =
+        (nonDesugaredCf && parameters.isCfRuntime())
+            || parameters.canUseDefaultAndStaticInterfaceMethodsWhenDesugaring();
+    // JDK 11 allows this incorrect dispatch for some reason.
+    if (parameters.isCfRuntime(CfVm.JDK11) && isNotDesugared) {
       result.assertSuccessWithOutputLines("I::foo");
       return;
     }
-    // TODO(b/152199517): Should be illegal access for DEX.
-    if (parameters.isDexRuntime() && parameters.getApiLevel().isGreaterThan(AndroidApiLevel.M)) {
+    // TODO(b/152199517): Should become an illegal access on future DEX VM.
+    if (parameters.isDexRuntime() && isNotDesugared) {
       result.assertSuccessWithOutputLines("I::foo");
       return;
     }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineFromDefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineFromDefaultInterfaceMethodTest.java
index 9b3dd42..baf0868 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineFromDefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineFromDefaultInterfaceMethodTest.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.ir.optimize.outliner;
 
 import static com.android.tools.r8.references.Reference.methodFromMethod;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
@@ -16,11 +17,9 @@
 import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
 import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -65,25 +64,22 @@
   }
 
   private void inspect(CodeInspector inspector) {
-    ClassSubject interfaceSubject;
-    MethodSubject greetMethodSubject;
-    if (parameters.isCfRuntime()
-        || parameters
-            .getApiLevel()
-            .isGreaterThanOrEqualTo(apiLevelWithDefaultInterfaceMethodsSupport())) {
-      interfaceSubject = inspector.clazz(I.class);
-      greetMethodSubject = interfaceSubject.uniqueMethodWithName("greet");
+    if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
+      ClassSubject interfaceSubject = inspector.clazz(I.class);
+      MethodSubject greetMethodSubject = interfaceSubject.uniqueMethodWithName("greet");
+      assertThat(interfaceSubject, isPresent());
+      assertThat(greetMethodSubject, isPresent());
+      assertEquals(
+          1,
+          greetMethodSubject
+              .streamInstructions()
+              .filter(InstructionSubject::isInvokeStatic)
+              .count());
     } else {
-      interfaceSubject = inspector.clazz(SyntheticItemsTestUtils.syntheticCompanionClass(I.class));
-      List<FoundMethodSubject> companionMethods = interfaceSubject.allMethods();
-      assertEquals(1, companionMethods.size());
-      greetMethodSubject = companionMethods.get(0);
+      // The companion class method is inlined into main.
+      assertThat(
+          inspector.clazz(SyntheticItemsTestUtils.syntheticCompanionClass(I.class)), isAbsent());
     }
-    assertThat(interfaceSubject, isPresent());
-    assertThat(greetMethodSubject, isPresent());
-    assertEquals(
-        1,
-        greetMethodSubject.streamInstructions().filter(InstructionSubject::isInvokeStatic).count());
   }
 
   static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceWithDefaultMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceWithDefaultMethodTest.java
index 6bc0862..c10d1db 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceWithDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceWithDefaultMethodTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.ir.optimize.unusedinterfaces;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
@@ -57,7 +58,9 @@
     assertThat(iClassSubject, isPresent());
 
     ClassSubject jClassSubject = inspector.clazz(J.class);
-    assertThat(jClassSubject, isPresent());
+    assertThat(
+        jClassSubject,
+        parameters.canUseDefaultAndStaticInterfaceMethods() ? isPresent() : isAbsent());
 
     ClassSubject aClassSubject = inspector.clazz(A.class);
     assertThat(aClassSubject, isPresent());
@@ -66,7 +69,9 @@
     // m() that happens to be used.
     assertEquals(1, aClassSubject.getDexProgramClass().interfaces.size());
     assertEquals(
-        jClassSubject.getDexProgramClass().type,
+        parameters.canUseDefaultAndStaticInterfaceMethods()
+            ? jClassSubject.getDexProgramClass().type
+            : iClassSubject.getDexProgramClass().type,
         aClassSubject.getDexProgramClass().interfaces.values[0]);
   }
 
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingRemoveInterfaceDefaultBridgeTest.java b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingRemoveInterfaceDefaultBridgeTest.java
index 38eed54..e11bdfe 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingRemoveInterfaceDefaultBridgeTest.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingRemoveInterfaceDefaultBridgeTest.java
@@ -4,9 +4,9 @@
 
 package com.android.tools.r8.memberrebinding;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.NeverInline;
@@ -17,7 +17,6 @@
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -60,13 +59,7 @@
               assertTrue(clazz.allMethods().isEmpty());
               if (!parameters.canUseDefaultAndStaticInterfaceMethods()) {
                 ClassSubject classSubject = clazz.toCompanionClass();
-                assertThat(classSubject, isPresent());
-                // TODO(b/197851381): We should be able to remove the bridge but it is problematic
-                //   since this require rewriting the call sites. Moving desugaring to the enqueuer
-                //   will also fix this.
-                assertEquals(2, classSubject.allMethods().size());
-                assertTrue(
-                    classSubject.allMethods().stream().anyMatch(FoundMethodSubject::isBridge));
+                assertThat(classSubject, isAbsent());
               }
             });
   }
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
index 1868602..18f0c96 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
@@ -3,16 +3,15 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.naming.applymapping.desugar;
 
-import static com.android.tools.r8.references.Reference.classFromClass;
-import static org.junit.Assert.assertTrue;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting;
-import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -73,26 +72,21 @@
 
   @Test
   public void testLibraryLinkedWithProgram() throws Throwable {
-    String ruleContent = "-keep class " + LibraryInterface.class.getTypeName() + " { *; }";
     R8TestCompileResult libraryResult =
         testForR8(parameters.getBackend())
             .addProgramClasses(LibraryInterface.class)
-            .addKeepRules(ruleContent)
+            .addKeepClassAndMembersRules(LibraryInterface.class)
             .setMinApi(parameters.getApiLevel())
             .compile();
     CodeInspector inspector = libraryResult.inspector();
-    assertTrue(inspector.clazz(LibraryInterface.class).isPresent());
-    assertTrue(inspector.method(LibraryInterface.class.getMethod("foo")).isPresent());
-    if (willDesugarDefaultInterfaceMethods(parameters.getApiLevel())) {
+    assertThat(inspector.clazz(LibraryInterface.class), isPresent());
+    assertThat(inspector.method(LibraryInterface.class.getMethod("foo")), isPresent());
+    if (!parameters.canUseDefaultAndStaticInterfaceMethods()) {
       ClassSubject companion =
-          inspector.clazz(
-              Reference.classFromDescriptor(
-                  InterfaceDesugaringForTesting.getCompanionClassDescriptor(
-                      classFromClass(LibraryInterface.class).getDescriptor())));
-      // Check that we included the companion class.
-      assertTrue(companion.isPresent());
-      // TODO(b/129223905): Check the method is also present on the companion class.
-      assertTrue(inspector.method(LibraryInterface.class.getMethod("foo")).isPresent());
+          inspector.clazz(SyntheticItemsTestUtils.syntheticCompanionClass(LibraryInterface.class));
+      // Check that we included the companion class and method.
+      assertThat(companion, isPresent());
+      assertEquals(1, companion.allMethods().size());
     }
 
     testForR8(parameters.getBackend())
@@ -107,8 +101,4 @@
         .run(parameters.getRuntime(), ProgramClass.class)
         .assertSuccessWithOutput(EXPECTED);
   }
-
-  private static boolean willDesugarDefaultInterfaceMethods(AndroidApiLevel apiLevel) {
-    return apiLevel != null && apiLevel.getLevel() < AndroidApiLevel.N.getLevel();
-  }
 }
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/desugar/StaticInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/desugar/StaticInterfaceMethodTest.java
new file mode 100644
index 0000000..1dfd029
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/desugar/StaticInterfaceMethodTest.java
@@ -0,0 +1,110 @@
+// Copyright (c) 2019, 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.naming.applymapping.desugar;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+// Reproduction for b/196345511.
+@RunWith(Parameterized.class)
+public class StaticInterfaceMethodTest extends TestBase {
+
+  public static final String OUTPUT = "Called LibraryInterface::foo";
+  public static final String EXPECTED = StringUtils.lines(OUTPUT);
+
+  public interface LibraryInterface {
+    static void foo() {
+      System.out.println(OUTPUT);
+    }
+  }
+
+  public static class ProgramClass implements LibraryInterface {
+
+    public static void main(String[] args) {
+      LibraryInterface.foo();
+    }
+  }
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection params() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  private final TestParameters parameters;
+
+  public StaticInterfaceMethodTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testJvm() throws Throwable {
+    Assume.assumeTrue(parameters.isCfRuntime());
+    testForJvm()
+        .addProgramClasses(LibraryInterface.class, ProgramClass.class)
+        .run(parameters.getRuntime(), ProgramClass.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testFullProgram() throws Throwable {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(LibraryInterface.class, ProgramClass.class)
+        .addKeepMainRule(ProgramClass.class)
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), ProgramClass.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testLibraryLinkedWithProgram() throws Throwable {
+    R8TestCompileResult libraryResult =
+        testForR8(parameters.getBackend())
+            .addProgramClasses(LibraryInterface.class)
+            .addKeepClassAndMembersRules(LibraryInterface.class)
+            .setMinApi(parameters.getApiLevel())
+            .compile();
+    CodeInspector inspector = libraryResult.inspector();
+    ClassSubject libraryInterface = inspector.clazz(LibraryInterface.class);
+    assertThat(libraryInterface, isPresent());
+    if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
+      assertThat(libraryInterface.method(LibraryInterface.class.getMethod("foo")), isPresent());
+    } else {
+      // Desugaring must remove the static on the interface.
+      assertThat(libraryInterface.method(LibraryInterface.class.getMethod("foo")), isAbsent());
+      // Check that we included the companion class and method.
+      ClassSubject companion =
+          inspector.clazz(SyntheticItemsTestUtils.syntheticCompanionClass(LibraryInterface.class));
+      assertThat(companion, isPresent());
+      assertEquals(1, companion.allMethods().size());
+    }
+
+    testForR8(parameters.getBackend())
+        .noTreeShaking()
+        .addProgramClasses(ProgramClass.class)
+        .addClasspathClasses(LibraryInterface.class)
+        .addApplyMapping(libraryResult.getProguardMap())
+        .addKeepMainRule(ProgramClass.class)
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .addRunClasspathFiles(libraryResult.writeToZip())
+        .run(parameters.getRuntime(), ProgramClass.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/DefaultMethodShadowedByStaticTest.java b/src/test/java/com/android/tools/r8/resolution/DefaultMethodShadowedByStaticTest.java
index 19424d8..b974111 100644
--- a/src/test/java/com/android/tools/r8/resolution/DefaultMethodShadowedByStaticTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/DefaultMethodShadowedByStaticTest.java
@@ -6,7 +6,6 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRunResult;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.resolution.shadowing1.AClassDump;
 import com.android.tools.r8.resolution.shadowing1.InterfaceDump;
@@ -39,22 +38,15 @@
 
   @Test
   public void testReference() throws Exception {
-    TestRunResult<?> result =
-        testForRuntime(parameters)
-            .addProgramClassFileData(CLASSES)
-            .run(parameters.getRuntime(), "Main");
-    if (parameters.isDexRuntime()
-        && (parameters.getApiLevel().isLessThan(apiLevelWithStaticInterfaceMethodsSupport())
-            || parameters.getDexRuntimeVersion().equals(Version.V7_0_0))) {
-      // TODO(b/167535447): Desugaring should preserve the error.
-      result.assertSuccessWithOutputLines("42");
-    } else if (parameters.isDexRuntime()
-        && parameters.getDexRuntimeVersion().equals(Version.V7_0_0)) {
-      // Note: VM 7.0.0 without desugaring of defaults will incorrectly allow the virtual dispatch.
-      result.assertSuccessWithOutputLines("42");
-    } else {
-      result.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
-    }
+    testForRuntime(parameters)
+        .addProgramClassFileData(CLASSES)
+        .run(parameters.getRuntime(), "Main")
+        .applyIf(
+            // When not desugaring interfaces, the v7 runtime fails to throw the correct error.
+            parameters.canUseDefaultAndStaticInterfaceMethods()
+                && parameters.isDexRuntimeVersion(Version.V7_0_0),
+            r -> r.assertSuccessWithOutputLines("42"),
+            r -> r.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class));
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
index b176930..7d18aee 100644
--- a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
@@ -8,6 +8,7 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.AsmTestBase;
+import com.android.tools.r8.TestAppViewBuilder;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -89,12 +90,17 @@
   @BeforeClass
   public static void computeAppInfo() throws Exception {
     appView =
-        computeAppViewWithLiveness(
-            buildClassesWithTestingAnnotations(CLASSES)
-                .addClassProgramData(ASM_CLASSES)
-                .addLibraryFile(getMostRecentAndroidJar())
-                .build(),
-            Main.class);
+        TestAppViewBuilder.builder()
+            .addAndroidApp(
+                buildClassesWithTestingAnnotations(CLASSES)
+                    .addClassProgramData(ASM_CLASSES)
+                    .addLibraryFile(getMostRecentAndroidJar())
+                    .build())
+            .addKeepMainRule(Main.class)
+            // Some of these tests resolve default methods.
+            // If desugared they will hit the forward methods and not the expected defaults.
+            .setMinApi(apiLevelWithDefaultInterfaceMethodsSupport())
+            .buildWithLiveness();
     appInfo = appView.appInfo();
   }
 
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java
index cbad874..846c994 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java
@@ -4,22 +4,18 @@
 package com.android.tools.r8.resolution;
 
 import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
-import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 
 import com.android.tools.r8.AsmTestBase;
-import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRunResult;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.MethodResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
 import org.junit.Assert;
@@ -150,22 +146,11 @@
 
   @Test
   public void runJvmAndD8() throws Exception {
-    TestRunResult<?> runResult;
-    if (parameters.isCfRuntime()) {
-      runResult =
-          testForJvm()
-              .addProgramClasses(CLASSES)
-              .addProgramClassFileData(DUMP)
-              .run(parameters.getRuntime(), Main.class);
-    } else {
-      runResult =
-          testForD8()
-              .addProgramClasses(CLASSES)
-              .addProgramClassFileData(DUMP)
-              .setMinApi(parameters.getApiLevel())
-              .run(parameters.getRuntime(), Main.class);
-    }
-    checkResult(runResult);
+    testForRuntime(parameters)
+        .addProgramClasses(CLASSES)
+        .addProgramClassFileData(DUMP)
+        .run(parameters.getRuntime(), Main.class)
+        .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
   }
 
   @Test
@@ -179,33 +164,13 @@
   }
 
   public void runR8(boolean enableVerticalClassMerging) throws Exception {
-    R8TestRunResult runResult =
-        testForR8(parameters.getBackend())
-            .addProgramClasses(CLASSES)
-            .addProgramClassFileData(DUMP)
-            .addKeepMainRule(Main.class)
-            .setMinApi(parameters.getApiLevel())
-            .addOptionsModification(o -> o.enableVerticalClassMerging = enableVerticalClassMerging)
-            .run(parameters.getRuntime(), Main.class);
-    if (enableVerticalClassMerging) {
-      // Vertical class merging will merge B and C and change the instruction to invoke-virtual
-      // causing the legacy ART runtime behavior to match the expected error.
-      runResult.assertFailureWithErrorThatMatches(containsString("IncompatibleClassChangeError"));
-    } else {
-      checkResult(runResult);
-    }
-  }
-
-  private void checkResult(TestRunResult<?> runResult) {
-    runResult.assertFailureWithErrorThatMatches(containsString(expectedRuntimeError()));
-  }
-
-  private String expectedRuntimeError() {
-    if (parameters.isDexRuntime()
-        && parameters.getApiLevel().getLevel() < AndroidApiLevel.N.getLevel()) {
-      // When desugaring default interface methods the error will be NoSuchMethodError.
-      return "NoSuchMethodError";
-    }
-    return "IncompatibleClassChangeError";
+    testForR8(parameters.getBackend())
+        .addProgramClasses(CLASSES)
+        .addProgramClassFileData(DUMP)
+        .addKeepMainRule(Main.class)
+        .setMinApi(parameters.getApiLevel())
+        .addOptionsModification(o -> o.enableVerticalClassMerging = enableVerticalClassMerging)
+        .run(parameters.getRuntime(), Main.class)
+        .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java
index 4787b97..82c6b63 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java
@@ -10,6 +10,7 @@
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
+import com.android.tools.r8.TestAppViewBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRunResult;
@@ -20,6 +21,7 @@
 import com.android.tools.r8.graph.MethodResolutionResult.NoSuchMethodResult;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
 import com.android.tools.r8.transformers.ClassFileTransformer;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.DescriptorUtils;
@@ -52,6 +54,7 @@
             .withCfRuntimesStartingFromIncluding(JDK11)
             .withDexRuntimes()
             .withAllApiLevels()
+            .enableApiLevelsForCf()
             .build(),
         BooleanUtils.values(),
         BooleanUtils.values());
@@ -132,7 +135,16 @@
     MethodSubject foo = inspector.clazz(callerClass).uniqueMethodWithName("foo");
     assertTrue(
         foo.streamInstructions()
-            .anyMatch(i -> i.asCfInstruction().isInvokeSpecial() && i.getMethod() == method));
+            .anyMatch(
+                i -> {
+                  if (parameters.canUseDefaultAndStaticInterfaceMethodsWhenDesugaring()) {
+                    return i.asCfInstruction().isInvokeSpecial() && i.getMethod() == method;
+                  } else {
+                    return i.isInvokeStatic()
+                        && SyntheticItemsTestUtils.isInternalThrowNSME(
+                            i.getMethod().asMethodReference());
+                  }
+                }));
   }
 
   private DexMethod getTargetMethodSignature(Class<?> declaredClass, AppInfoWithLiveness appInfo) {
@@ -148,12 +160,13 @@
   }
 
   private AppView<AppInfoWithLiveness> getAppView() throws Exception {
-    return computeAppViewWithLiveness(
-        buildClasses(getClasses())
-            .addClassProgramData(getTransformedClasses())
-            .addLibraryFile(TestBase.runtimeJar(parameters.getBackend()))
-            .build(),
-        Main.class);
+    return TestAppViewBuilder.builder()
+        .addProgramClasses(getClasses())
+        .addProgramClassFileData(getTransformedClasses())
+        .addLibraryFiles(parameters.getDefaultRuntimeLibrary())
+        .addKeepMainRule(Main.class)
+        .setMinApi(parameters.getApiLevel())
+        .buildWithLiveness();
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java
index 77fad9a..f6b2df5 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java
@@ -6,6 +6,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assume.assumeTrue;
 
+import com.android.tools.r8.TestAppViewBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -15,7 +16,6 @@
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableList;
 import java.util.Collection;
-import java.util.Collections;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -42,12 +42,13 @@
     // The resolution is runtime independent, so just run it on the default CF VM.
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppInfoWithLiveness appInfo =
-        computeAppViewWithLiveness(
-                buildClasses(CLASSES)
-                    .addClassProgramData(Collections.singletonList(transformB()))
-                    .addLibraryFile(parameters.getDefaultRuntimeLibrary())
-                    .build(),
-                Main.class)
+        TestAppViewBuilder.builder()
+            .addProgramClasses(CLASSES)
+            .addProgramClassFileData(transformB())
+            .addLibraryFiles(parameters.getDefaultRuntimeLibrary())
+            .addKeepMainRule(Main.class)
+            .setMinApi(apiLevelWithDefaultInterfaceMethodsSupport())
+            .buildWithLiveness()
             .appInfo();
     DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
     MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java
index 0139049..8901542 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java
@@ -5,17 +5,19 @@
 
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
+import com.android.tools.r8.TestAppViewBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.MethodResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -44,21 +46,45 @@
   public void testResolution() throws Exception {
     // The resolution is runtime independent, so just run it on the default CF VM.
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
-        computeAppViewWithLiveness(
-                buildClasses(CLASSES)
-                    .addClassProgramData(Collections.singletonList(transformB()))
-                    .addLibraryFile(parameters.getDefaultRuntimeLibrary())
-                    .build(),
-                Main.class)
-            .appInfo();
-    DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
-    MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
-    Set<String> holders = new HashSet<>();
-    resolutionResult
-        .asFailedResolution()
-        .forEachFailureDependency(m -> holders.add(m.getHolderType().toSourceString()));
-    assertEquals(ImmutableSet.of(I.class.getTypeName(), J.class.getTypeName()), holders);
+    for (AndroidApiLevel minApi :
+        ImmutableList.of(AndroidApiLevel.B, apiLevelWithDefaultInterfaceMethodsSupport())) {
+      AppInfoWithLiveness appInfo =
+          TestAppViewBuilder.builder()
+              .addProgramClasses(CLASSES)
+              .addProgramClassFileData(transformB())
+              .addLibraryFiles(parameters.getDefaultRuntimeLibrary())
+              .addKeepMainRule(Main.class)
+              .setMinApi(minApi)
+              .buildWithLiveness()
+              .appInfo();
+      DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
+      MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+      if (minApi.isLessThan(apiLevelWithDefaultInterfaceMethodsSupport())) {
+        // When desugaring a forwarding method throwing ICCE is inserted.
+        // Check that the resolved method throws such an exception.
+        assertTrue(
+            resolutionResult
+                .asSingleResolution()
+                .getResolvedMethod()
+                .getCode()
+                .asCfCode()
+                .getInstructions()
+                .stream()
+                .anyMatch(
+                    i ->
+                        i.isTypeInstruction()
+                            && i.asTypeInstruction().getType()
+                                == appInfo.dexItemFactory().icceType));
+      } else {
+        // When not desugaring resolution should fail. Check the failure dependencies are the two
+        // default methods in conflict.
+        Set<String> holders = new HashSet<>();
+        resolutionResult
+            .asFailedResolution()
+            .forEachFailureDependency(m -> holders.add(m.getHolderType().toSourceString()));
+        assertEquals(ImmutableSet.of(I.class.getTypeName(), J.class.getTypeName()), holders);
+      }
+    }
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java
index 0ec1ce8..4dcead3 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.resolution.interfacetargets;
 
-import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assume.assumeTrue;
 import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
 
@@ -17,7 +16,6 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.DescriptorUtils;
 import java.io.IOException;
 import java.util.concurrent.ExecutionException;
@@ -70,7 +68,7 @@
         .addProgramClasses(A.class, I.class)
         .addProgramClassFileData(transformMain())
         .run(parameters.getRuntime(), Main.class)
-        .assertFailureWithErrorThatMatches(containsString(getExpected()));
+        .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
   }
 
   @Test
@@ -81,14 +79,7 @@
         .addKeepMainRule(Main.class)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), Main.class)
-        .assertFailureWithErrorThatMatches(containsString(getExpected()));
-  }
-
-  private String getExpected() {
-    return parameters.isCfRuntime()
-            || parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)
-        ? "IncompatibleClassChangeError"
-        : "NoSuchMethodError";
+        .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
   }
 
   private byte[] transformMain() throws IOException {
diff --git a/src/test/java/com/android/tools/r8/shaking/NonVirtualOverrideTest.java b/src/test/java/com/android/tools/r8/shaking/NonVirtualOverrideTest.java
index 4a8306a..801d678 100644
--- a/src/test/java/com/android/tools/r8/shaking/NonVirtualOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/NonVirtualOverrideTest.java
@@ -4,9 +4,9 @@
 
 package com.android.tools.r8.shaking;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
-import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 
@@ -105,9 +105,9 @@
           "In C.m3()",
           "In A.m4()",
           "In A.m1()", // With Java: Caught IllegalAccessError when calling B.m1()
-          "In A.m3()", // With Java: Caught IncompatibleClassChangeError when calling B.m3()
+          "Caught IncompatibleClassChangeError when calling B.m3()",
           "In C.m1()", // With Java: Caught IllegalAccessError when calling B.m1()
-          "In C.m3()", // With Java: Caught IncompatibleClassChangeError when calling B.m3()
+          "Caught IncompatibleClassChangeError when calling B.m3()",
           "In C.m1()",
           "In C.m3()",
           "");
@@ -178,9 +178,11 @@
       ClassSubject classSubject = inspector.clazz(B.class.getName());
       assertThat(classSubject, isPresentAndRenamed());
       assertThat(classSubject.method("void", "m1", ImmutableList.of()), isPresent());
-      assertThat(classSubject.method("void", "m2", ImmutableList.of()), not(isPresent()));
-      assertThat(classSubject.method("void", "m3", ImmutableList.of()), isPresent());
-      assertThat(classSubject.method("void", "m4", ImmutableList.of()), not(isPresent()));
+      assertThat(classSubject.method("void", "m2", ImmutableList.of()), isAbsent());
+      assertThat(
+          classSubject.method("void", "m3", ImmutableList.of()),
+          parameters.isCfRuntime() ? isPresent() : isAbsent());
+      assertThat(classSubject.method("void", "m4", ImmutableList.of()), isAbsent());
     }
   }
 
@@ -263,7 +265,8 @@
       System.out.println("In B.m2()");
     }
 
-    // Made static in the dump below. This method is targeted and can therefore not be removed.
+    // Made static in the dump below. Ends up dead as the targeting call is replaced by throw ICCE.
+    // Except in non-desugaring CF the method will remain instead of inserting a stub.
     @Override
     public void m3() {
       System.out.println("In B.m3()");
diff --git a/src/test/java/com/android/tools/r8/shaking/clinit/ClassInitializationTriggersIndirectInterfaceInitializationTest.java b/src/test/java/com/android/tools/r8/shaking/clinit/ClassInitializationTriggersIndirectInterfaceInitializationTest.java
index b427736..29960f9 100644
--- a/src/test/java/com/android/tools/r8/shaking/clinit/ClassInitializationTriggersIndirectInterfaceInitializationTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/clinit/ClassInitializationTriggersIndirectInterfaceInitializationTest.java
@@ -4,8 +4,8 @@
 
 package com.android.tools.r8.shaking.clinit;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static com.android.tools.r8.utils.codeinspector.Matchers.onlyIf;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -51,22 +51,27 @@
         .compile()
         .inspect(
             inspector -> {
-              // Verify that I's class initializer is still present.
               ClassSubject iClassSubject = inspector.clazz(I.class);
-              assertThat(iClassSubject, isPresent());
-              assertThat(
-                  iClassSubject.clinit(),
-                  onlyIf(hasDefaultInterfaceMethodsSupport(parameters), isPresent()));
-
-              // Verify that J is still there.
               ClassSubject jClassSubject = inspector.clazz(J.class);
-              assertThat(jClassSubject, isPresent());
-
-              // Verify that A still implements J.
               ClassSubject aClassSubject = inspector.clazz(A.class);
-              assertThat(aClassSubject, isPresent());
-              assertEquals(1, aClassSubject.getDexProgramClass().getInterfaces().size());
-              assertTrue(aClassSubject.isImplementing(jClassSubject));
+              if (hasDefaultInterfaceMethodsSupport(parameters)) {
+                // Verify that I's class initializer is still present.
+                assertThat(iClassSubject, isPresent());
+                assertThat(iClassSubject.clinit(), isPresent());
+
+                // Verify that J is still there.
+                assertThat(jClassSubject, isPresent());
+
+                // Verify that A still implements J.
+                assertThat(aClassSubject, isPresent());
+                assertEquals(1, aClassSubject.getDexProgramClass().getInterfaces().size());
+                assertTrue(aClassSubject.isImplementing(jClassSubject));
+              } else {
+                // All interfaces are gone and the default methods companion call is inlined.
+                assertThat(iClassSubject, isAbsent());
+                assertThat(jClassSubject, isAbsent());
+                assertThat(aClassSubject, isAbsent());
+              }
             })
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLinesIf(
diff --git a/src/test/java/com/android/tools/r8/shaking/desugar/KeepRuleWarningTest.java b/src/test/java/com/android/tools/r8/shaking/desugar/KeepRuleWarningTest.java
index c2be7a8..02dfda4 100644
--- a/src/test/java/com/android/tools/r8/shaking/desugar/KeepRuleWarningTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/desugar/KeepRuleWarningTest.java
@@ -3,8 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.shaking.desugar;
 
-import static org.hamcrest.CoreMatchers.containsString;
-
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestDiagnosticMessages;
@@ -106,14 +104,8 @@
         .enableNoVerticalClassMergingAnnotations()
         .addKeepMainRule(MAIN)
         .addKeepRules("-keep interface **.I { static void foo(); }")
-        .allowDiagnosticWarningMessages()
         .compile()
-        .inspectDiagnosticMessages(
-            m ->
-                m.assertWarningsCount(1)
-                    .assertWarningMessageThatMatches(containsString("static void foo()"))
-                    .assertWarningMessageThatMatches(containsString("is ignored"))
-                    .assertWarningMessageThatMatches(containsString("will be desugared")))
+        .inspectDiagnosticMessages(TestDiagnosticMessages::assertNoMessages)
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
index 19b87e4..01d977a 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.shaking.ifrule.interfacemethoddesugaring;
 
-import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPublic;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isStatic;
@@ -12,6 +11,8 @@
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NeverInline;
@@ -34,9 +35,17 @@
 
   private final TestParameters parameters;
 
+  private static final String STATIC_STR = "In Interface.staticMethod()";
+  private static final String VIRTUAL_STR = "In Interface.virtualMethod()";
+  private static final String EXPECTED_OUTPUT = StringUtils.lines(STATIC_STR, VIRTUAL_STR);
+
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withDexRuntimes().withApiLevel(AndroidApiLevel.M).build();
+    return getTestParameters()
+        .withCfRuntimes()
+        .withDexRuntimes()
+        .withApiLevel(AndroidApiLevel.M)
+        .build();
   }
 
   public IfRuleWithInterfaceMethodDesugaringTest(TestParameters parameters) {
@@ -44,50 +53,64 @@
   }
 
   @Test
+  public void testReference() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
+    testForJvm()
+        .addTestClasspath()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
+
+  @Test
   public void test() throws Exception {
-    String expectedOutput =
-        StringUtils.lines("In Interface.staticMethod()", "In Interface.virtualMethod()");
-
-    testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
-
     CodeInspector inspector =
         testForR8(parameters.getBackend())
             .addInnerClasses(IfRuleWithInterfaceMethodDesugaringTest.class)
             .addKeepMainRule(TestClass.class)
             .addKeepRules(
                 "-if class " + Interface.class.getTypeName() + " {",
-                "  !public static void staticMethod();",
+                "  static void staticMethod();",
                 "}",
                 "-keep class " + Unused1.class.getTypeName(),
                 "-if class " + Interface.class.getTypeName() + " {",
-                "  !public !static void virtualMethod();",
+                "  !static void virtualMethod();",
                 "}",
                 "-keep class " + Unused2.class.getTypeName())
-            .allowUnusedProguardConfigurationRules()
+            .allowUnusedProguardConfigurationRules(parameters.isDexRuntime())
             .enableInliningAnnotations()
             .enableNeverClassInliningAnnotations()
             .enableNoVerticalClassMergingAnnotations()
             .setMinApi(parameters.getApiLevel())
-            .compile()
             .run(parameters.getRuntime(), TestClass.class)
-            .assertSuccessWithOutput(expectedOutput)
+            .assertSuccessWithOutput(EXPECTED_OUTPUT)
             .inspector();
 
-    ClassSubject classSubject =
-        inspector.clazz(Interface.class.getTypeName() + getCompanionClassNameSuffix());
-    assertThat(classSubject, isPresent());
-    assertEquals(2, classSubject.allMethods().size());
+    if (parameters.isCfRuntime()) {
+      ClassSubject itfClass = inspector.clazz(Interface.class.getTypeName());
+      assertThat(itfClass, isPresent());
+      assertThat(itfClass.uniqueMethodWithName("staticMethod"), isPresent());
+      assertThat(itfClass.uniqueMethodWithName("virtualMethod"), isPresent());
+      assertThat(inspector.clazz(Unused1.class), isPresent());
+      assertThat(inspector.clazz(Unused2.class), isPresent());
+      return;
+    }
 
+    ClassSubject classSubject = inspector.clazz(Interface.class.getTypeName()).toCompanionClass();
+    assertThat(classSubject, isPresent());
+
+    // NeverInline is only applicable to the static method at this point (could change).
+    assertEquals(1, classSubject.allMethods().size());
     MethodSubject staticMethodSubject = classSubject.uniqueMethodWithName("staticMethod");
     assertThat(staticMethodSubject, allOf(isPresent(), isPublic(), isStatic()));
+    assertTrue(staticMethodSubject.streamInstructions().anyMatch(i -> i.isConstString(STATIC_STR)));
 
-    // TODO(b/120764902): MethodSubject.getOriginalName() not working in presence of desugaring.
-    MethodSubject virtualMethodSubject =
-        classSubject.allMethods().stream()
-            .filter(subject -> subject != staticMethodSubject)
-            .findFirst()
-            .get();
-    assertThat(virtualMethodSubject, allOf(isPresent(), isPublic(), isStatic()));
+    // The virtual method is inlined as @NeverInline does not apply at this point (could change).
+    assertTrue(
+        inspector
+            .clazz(TestClass.class)
+            .mainMethod()
+            .streamInstructions()
+            .anyMatch(i -> i.isConstString(VIRTUAL_STR)));
 
     // TODO(b/122875545): The Unused class should be present due to the -if rule.
     assertThat(inspector.clazz(Unused1.class), not(isPresent()));
diff --git a/src/test/java/com/android/tools/r8/shaking/staticinterfacemethods/defaultmethods/StaticInterfaceMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/staticinterfacemethods/defaultmethods/StaticInterfaceMethodsTest.java
index ca0aaa5..e9af866 100644
--- a/src/test/java/com/android/tools/r8/shaking/staticinterfacemethods/defaultmethods/StaticInterfaceMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/staticinterfacemethods/defaultmethods/StaticInterfaceMethodsTest.java
@@ -107,7 +107,7 @@
     assertFalse(clazz.method("int", "method", ImmutableList.of()).isPresent());
   }
 
-  private void staticMethodKeptB159987443(CodeInspector inspector) {
+  private void staticMethodKept(CodeInspector inspector) {
     ClassSubject clazz = inspector.clazz(InterfaceWithStaticMethods.class);
     assertThat(clazz, isPresent());
     MethodSubject method = clazz.method("int", "method", ImmutableList.of());
@@ -117,13 +117,12 @@
       assertThat(companionClass, not(isPresent()));
     } else {
       assertThat(method, not(isPresent()));
-      // TODO(159987443): The companion class should be present.
-      assertThat(companionClass, not(isPresent()));
-      // Also check that method exists on companion class.
+      assertThat(companionClass, isPresent());
+      assertThat(companionClass.uniqueMethodWithName("method"), isPresent());
     }
   }
 
-  private void staticMethodKept(CodeInspector inspector) {
+  private void staticMethodKeptB160142903(CodeInspector inspector) {
     ClassSubject clazz = inspector.clazz(InterfaceWithStaticMethods.class);
     ClassSubject companionClass = clazz.toCompanionClass();
     MethodSubject method = clazz.method("int", "method", ImmutableList.of());
@@ -136,7 +135,7 @@
       // after desugaring, only the companion class is left.
       assertThat(clazz, not(isPresent()));
       assertThat(method, not(isPresent()));
-      // TODO(159987443): The companion class should be present.
+      // TODO(160142903): The companion class should be present.
       assertThat(companionClass, not(isPresent()));
       // Also check that method exists on companion class.
     }
@@ -168,7 +167,7 @@
             "-keep interface " + InterfaceWithStaticMethods.class.getTypeName() + "{",
             "  <methods>;",
             "}"),
-        this::staticMethodKeptB159987443);
+        this::staticMethodKept);
   }
 
   @Test
@@ -196,7 +195,7 @@
             "}");
       }
     }
-    runTest(builder.build(), this::staticMethodKept);
+    runTest(builder.build(), this::staticMethodKeptB160142903);
   }
 
   public static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
index 6ffbce9..92774e1 100644
--- a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
+++ b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
@@ -21,9 +21,12 @@
   }
 
   public static ClassReference syntheticCompanionClass(Class<?> clazz) {
+    return syntheticCompanionClass(Reference.classFromClass(clazz));
+  }
+
+  public static ClassReference syntheticCompanionClass(ClassReference clazz) {
     return Reference.classFromDescriptor(
-        InterfaceDesugaringForTesting.getCompanionClassDescriptor(
-            Reference.classFromClass(clazz).getDescriptor()));
+        InterfaceDesugaringForTesting.getCompanionClassDescriptor(clazz.getDescriptor()));
   }
 
   private static ClassReference syntheticClass(Class<?> clazz, SyntheticKind kind, int id) {
@@ -72,7 +75,8 @@
 
   public static boolean isExternalSynthetic(ClassReference reference) {
     for (SyntheticKind kind : SyntheticKind.values()) {
-      if (kind == SyntheticKind.RECORD_TAG) {
+      if (kind == SyntheticKind.RECORD_TAG
+          || kind == SyntheticKind.EMULATED_INTERFACE_MARKER_CLASS) {
         continue;
       }
       if (kind.isFixedSuffixSynthetic) {
@@ -134,4 +138,9 @@
   public static Matcher<String> containsExternalSyntheticReference() {
     return containsString(SyntheticNaming.getPhaseSeparator(Phase.EXTERNAL));
   }
+
+  public static boolean isInternalThrowNSME(MethodReference method) {
+    return SyntheticNaming.isSynthetic(
+        method.getHolderClass(), Phase.INTERNAL, SyntheticKind.THROW_NSME);
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
index f552a25..b100332 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -4,8 +4,6 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
-import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix;
-
 import com.android.tools.r8.graph.ClassAccessFlags;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -13,11 +11,11 @@
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.references.TypeReference;
 import com.android.tools.r8.retrace.RetraceClassElement;
 import com.android.tools.r8.retrace.RetraceClassResult;
 import com.android.tools.r8.smali.SmaliBuilder;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
 import com.android.tools.r8.utils.ListUtils;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
@@ -231,12 +229,7 @@
   public abstract KotlinClassMetadata getKotlinClassMetadata();
 
   public ClassSubject toCompanionClass() {
-    String descriptor = reference.getDescriptor();
-    return codeInspector.clazz(
-        Reference.classFromDescriptor(
-            descriptor.substring(0, descriptor.length() - 1)
-                + getCompanionClassNameSuffix()
-                + ";"));
+    return codeInspector.clazz(SyntheticItemsTestUtils.syntheticCompanionClass(reference));
   }
 
   public abstract RetraceClassResult retrace();
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index 77c68b3..76d76e5 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -3,8 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.utils.codeinspector;
 
-import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix;
-
 import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.StringResource;
 import com.android.tools.r8.TestDiagnosticMessagesImpl;
@@ -40,6 +38,7 @@
 import com.android.tools.r8.retrace.Retracer;
 import com.android.tools.r8.retrace.internal.DirectClassNameMapperProguardMapProducer;
 import com.android.tools.r8.retrace.internal.RetracerImpl;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.BiMapContainer;
 import com.android.tools.r8.utils.DescriptorUtils;
@@ -328,7 +327,7 @@
   }
 
   public ClassSubject companionClassFor(Class<?> clazz) {
-    return clazz(Reference.classFromTypeName(clazz.getTypeName() + getCompanionClassNameSuffix()));
+    return clazz(SyntheticItemsTestUtils.syntheticCompanionClass(clazz));
   }
 
   public void forAllClasses(Consumer<FoundClassSubject> inspection) {