Rewrite instance/static invokes to static/instance methods to ICCE in R8

Change-Id: If56ad9fa674cbc66f704b7b98ea4510f4f78a966
diff --git a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
index b425a2a..c1ff02b 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
@@ -84,6 +84,10 @@
     return null;
   }
 
+  public DexEncodedMethod getResolvedMethod() {
+    return null;
+  }
+
   /** Short-hand to get the single resolution method if resolution finds it, null otherwise. */
   public final DexEncodedMethod getSingleTarget() {
     return isSingleResolution() ? asSingleResolution().getResolvedMethod() : null;
@@ -189,6 +193,7 @@
       return resolvedMethod;
     }
 
+    @Override
     public DexEncodedMethod getResolvedMethod() {
       return resolvedMethod;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index 0b20c42..596f4cc 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -16,6 +16,7 @@
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
+import com.android.tools.r8.ir.desugar.icce.AlwaysThrowingInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialToSelfDesugaring;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
@@ -57,6 +58,13 @@
       AppView<?> appView, AndroidApiLevelCompute apiLevelCompute) {
     this.appView = appView;
     this.apiLevelCompute = apiLevelCompute;
+    AlwaysThrowingInstructionDesugaring alwaysThrowingInstructionDesugaring =
+        appView.enableWholeProgramOptimizations()
+            ? new AlwaysThrowingInstructionDesugaring(appView.withClassHierarchy())
+            : null;
+    if (alwaysThrowingInstructionDesugaring != null) {
+      desugarings.add(alwaysThrowingInstructionDesugaring);
+    }
     if (appView.options().desugarState.isOff()) {
       this.nestBasedAccessDesugaring = null;
       this.recordRewriter = null;
@@ -85,7 +93,9 @@
           new InterfaceMethodRewriter(
               appView,
               SetUtils.newImmutableSetExcludingNullItems(
-                  backportedMethodRewriter, desugaredLibraryRetargeter));
+                  alwaysThrowingInstructionDesugaring,
+                  backportedMethodRewriter,
+                  desugaredLibraryRetargeter));
       desugarings.add(interfaceMethodRewriter);
     } else {
       interfaceMethodRewriter = null;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
new file mode 100644
index 0000000..5c89290
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
@@ -0,0 +1,200 @@
+// 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.ir.desugar.icce;
+
+import com.android.tools.r8.cf.code.CfConstNull;
+import com.android.tools.r8.cf.code.CfConstNumber;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfStackInstruction;
+import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.MethodResolutionResult;
+import com.android.tools.r8.graph.MethodResolutionResult.FailedResolutionResult;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.DesugarDescription;
+import com.android.tools.r8.ir.desugar.FreshLocalProvider;
+import com.android.tools.r8.ir.desugar.LocalStackAllocator;
+import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations;
+import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations.MethodSynthesizerConsumer;
+import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations.UtilityMethodForCodeOptimizations;
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class AlwaysThrowingInstructionDesugaring implements CfInstructionDesugaring {
+
+  private final AppView<? extends AppInfoWithClassHierarchy> appView;
+
+  public AlwaysThrowingInstructionDesugaring(AppView<? extends AppInfoWithClassHierarchy> appView) {
+    this.appView = appView;
+  }
+
+  @Override
+  public Collection<CfInstruction> desugarInstruction(
+      CfInstruction instruction,
+      FreshLocalProvider freshLocalProvider,
+      LocalStackAllocator localStackAllocator,
+      CfInstructionDesugaringEventConsumer eventConsumer,
+      ProgramMethod context,
+      MethodProcessingContext methodProcessingContext,
+      CfInstructionDesugaringCollection desugaringCollection,
+      DexItemFactory dexItemFactory) {
+    return computeDesugarDescription(instruction)
+        .desugarInstruction(
+            freshLocalProvider,
+            localStackAllocator,
+            eventConsumer,
+            context,
+            methodProcessingContext,
+            dexItemFactory);
+  }
+
+  @Override
+  public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) {
+    return computeDesugarDescription(instruction).needsDesugaring();
+  }
+
+  private DesugarDescription computeDesugarDescription(CfInstruction instruction) {
+    if (instruction.isInvoke()) {
+      CfInvoke invoke = instruction.asInvoke();
+      DexMethod invokedMethod = invoke.getMethod();
+      MethodResolutionResult resolutionResult =
+          appView.appInfo().resolveMethod(invokedMethod, invoke.isInterface());
+      if (shouldRewriteInvokeToThrow(invoke, resolutionResult)) {
+        return computeInvokeAsThrowRewrite(appView, invoke, resolutionResult);
+      }
+    }
+    return DesugarDescription.nothing();
+  }
+
+  private boolean shouldRewriteInvokeToThrow(
+      CfInvoke invoke, MethodResolutionResult resolutionResult) {
+    if (resolutionResult.isArrayCloneMethodResult()) {
+      return false;
+    }
+    if (resolutionResult.isFailedResolution()) {
+      // For now don't materialize NSMEs from failed resolutions.
+      return resolutionResult.asFailedResolution().hasMethodsCausingError();
+    }
+    assert resolutionResult.isSingleResolution();
+    return resolutionResult.getResolvedMethod().isStatic() != invoke.isInvokeStatic();
+  }
+
+  public static DesugarDescription computeInvokeAsThrowRewrite(
+      AppView<?> appView, CfInvoke invoke, MethodResolutionResult resolutionResult) {
+    return DesugarDescription.builder()
+        .setDesugarRewrite(
+            (freshLocalProvider,
+                localStackAllocator,
+                eventConsumer,
+                context,
+                methodProcessingContext,
+                dexItemFactory) ->
+                getThrowInstructions(
+                    appView,
+                    invoke,
+                    resolutionResult,
+                    localStackAllocator,
+                    eventConsumer,
+                    context,
+                    methodProcessingContext))
+        .build();
+  }
+
+  private static Collection<CfInstruction> getThrowInstructions(
+      AppView<?> appView,
+      CfInvoke invoke,
+      MethodResolutionResult resolutionResult,
+      LocalStackAllocator localStackAllocator,
+      CfInstructionDesugaringEventConsumer eventConsumer,
+      ProgramMethod context,
+      MethodProcessingContext methodProcessingContext) {
+    MethodSynthesizerConsumer methodSynthesizerConsumer = null;
+    if (resolutionResult == null) {
+      methodSynthesizerConsumer =
+          UtilityMethodsForCodeOptimizations::synthesizeThrowNoSuchMethodErrorMethod;
+    } else if (resolutionResult.isSingleResolution()) {
+      if (resolutionResult.getResolvedMethod().isStatic() != invoke.isInvokeStatic()) {
+        methodSynthesizerConsumer =
+            UtilityMethodsForCodeOptimizations::synthesizeThrowIncompatibleClassChangeErrorMethod;
+      }
+    } else if (resolutionResult.isFailedResolution()) {
+      FailedResolutionResult failedResolutionResult = resolutionResult.asFailedResolution();
+      AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
+      if (failedResolutionResult.isIllegalAccessErrorResult(context.getHolder(), appInfo)) {
+        methodSynthesizerConsumer =
+            UtilityMethodsForCodeOptimizations::synthesizeThrowIllegalAccessErrorMethod;
+      } else if (failedResolutionResult.isNoSuchMethodErrorResult(context.getHolder(), appInfo)) {
+        methodSynthesizerConsumer =
+            UtilityMethodsForCodeOptimizations::synthesizeThrowNoSuchMethodErrorMethod;
+      } else if (failedResolutionResult.isIncompatibleClassChangeErrorResult()) {
+        methodSynthesizerConsumer =
+            UtilityMethodsForCodeOptimizations::synthesizeThrowIncompatibleClassChangeErrorMethod;
+      }
+    }
+
+    if (methodSynthesizerConsumer == null) {
+      assert false;
+      return null;
+    }
+
+    // Replace the entire effect of the invoke by by call to the throwing helper:
+    //   ...
+    //   invoke <method> [receiver] args*
+    // =>
+    //   ...
+    //   (pop arg)*
+    //   [pop receiver]
+    //   invoke <throwing-method>
+    //   pop exception result
+    //   [push fake result for <method>]
+    UtilityMethodForCodeOptimizations throwMethod =
+        methodSynthesizerConsumer.synthesizeMethod(appView, methodProcessingContext);
+    ProgramMethod throwProgramMethod = throwMethod.uncheckedGetMethod();
+    eventConsumer.acceptThrowMethod(throwProgramMethod, context);
+
+    ArrayList<CfInstruction> replacement = new ArrayList<>();
+    DexTypeList parameters = invoke.getMethod().getParameters();
+    for (int i = parameters.values.length - 1; i >= 0; i--) {
+      replacement.add(
+          new CfStackInstruction(
+              parameters.get(i).isWideType()
+                  ? CfStackInstruction.Opcode.Pop2
+                  : CfStackInstruction.Opcode.Pop));
+    }
+    if (!invoke.isInvokeStatic()) {
+      replacement.add(new CfStackInstruction(CfStackInstruction.Opcode.Pop));
+    }
+
+    CfInvoke throwInvoke =
+        new CfInvoke(
+            org.objectweb.asm.Opcodes.INVOKESTATIC, throwProgramMethod.getReference(), false);
+    assert throwInvoke.getMethod().getReturnType().isClassType();
+    replacement.add(throwInvoke);
+    replacement.add(new CfStackInstruction(CfStackInstruction.Opcode.Pop));
+
+    DexType returnType = invoke.getMethod().getReturnType();
+    if (!returnType.isVoidType()) {
+      replacement.add(
+          returnType.isPrimitiveType()
+              ? new CfConstNumber(0, ValueType.fromDexType(returnType))
+              : new CfConstNull());
+    } else {
+      // If the return type is void, the stack may need an extra slot to fit the return type of
+      // the call to the throwing method.
+      localStackAllocator.allocateLocalStack(1);
+    }
+    return replacement;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index d91a6fb..db52706 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -6,11 +6,8 @@
 
 import com.android.tools.r8.DesugarGraphConsumer;
 import com.android.tools.r8.cf.CfVersion;
-import com.android.tools.r8.cf.code.CfConstNull;
-import com.android.tools.r8.cf.code.CfConstNumber;
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
-import com.android.tools.r8.cf.code.CfStackInstruction;
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.Unimplemented;
@@ -27,13 +24,11 @@
 import com.android.tools.r8.graph.DexMethodHandle;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.DexValue;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.MethodResolutionResult;
 import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
@@ -41,11 +36,9 @@
 import com.android.tools.r8.ir.desugar.FreshLocalProvider;
 import com.android.tools.r8.ir.desugar.LocalStackAllocator;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.icce.AlwaysThrowingInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.lambda.LambdaInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.stringconcat.StringConcatInstructionDesugaring;
-import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations;
-import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations.MethodSynthesizerConsumer;
-import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations.UtilityMethodForCodeOptimizations;
 import com.android.tools.r8.ir.synthetic.ForwardMethodBuilder;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.MethodPosition;
@@ -56,7 +49,6 @@
 import com.android.tools.r8.utils.structural.Ordered;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Map;
@@ -353,7 +345,7 @@
     if (target != null && target.isDefaultMethod()) {
       // Rewrite the invoke to a throw ICCE as the default method forward would otherwise hide the
       // static / virtual mismatch.
-      return computeInvokeAsThrowRewrite(invoke, resolution.asSingleResolution());
+      return computeInvokeAsThrowRewrite(invoke, resolution.asSingleResolution(), context);
     }
     return DesugarDescription.nothing();
   }
@@ -447,7 +439,7 @@
             .resolveMethodOnInterface(holder, invoke.getMethod())
             .asSingleResolution();
     if (holder.isInterface() && shouldRewriteToInvokeToThrow(resolutionResult, true)) {
-      return computeInvokeAsThrowRewrite(invoke, resolutionResult);
+      return computeInvokeAsThrowRewrite(invoke, resolutionResult, context);
     }
 
     assert resolutionResult != null;
@@ -482,7 +474,7 @@
       return computeInvokeDirect(holder, invoke, context);
     }
     if (resolution != null && resolution.getResolvedMethod().isStatic()) {
-      return computeInvokeAsThrowRewrite(invoke, resolution);
+      return computeInvokeAsThrowRewrite(invoke, resolution, context);
     }
     DesugarDescription description = computeEmulatedInterfaceVirtualDispatchOrNull(invoke);
     return description != null ? description : DesugarDescription.nothing();
@@ -527,7 +519,7 @@
     MethodResolutionResult resolution =
         appView.appInfoForDesugaring().resolveMethod(invokedMethod, invoke.isInterface());
     if (resolution.isFailedResolution()) {
-      return computeInvokeAsThrowRewrite(invoke, null);
+      return computeInvokeAsThrowRewrite(invoke, null, context);
     }
 
     SingleResolutionResult singleResolution = resolution.asSingleResolution();
@@ -606,23 +598,10 @@
   }
 
   private DesugarDescription computeInvokeAsThrowRewrite(
-      CfInvoke invoke, SingleResolutionResult resolution) {
-    return DesugarDescription.builder()
-        .setDesugarRewrite(
-            (freshLocalProvider,
-                localStackAllocator,
-                eventConsumer,
-                context,
-                methodProcessingContext,
-                dexItemFactory) ->
-                getThrowInstructions(
-                    invoke,
-                    resolution,
-                    localStackAllocator,
-                    eventConsumer,
-                    context,
-                    methodProcessingContext))
-        .build();
+      CfInvoke invoke, SingleResolutionResult resolution, ProgramMethod context) {
+    assert !isAlreadyDesugared(invoke, context);
+    return AlwaysThrowingInstructionDesugaring.computeInvokeAsThrowRewrite(
+        appView, invoke, resolution);
   }
 
   private Collection<CfInstruction> getInvokeStaticInstructions(DexMethod newTarget) {
@@ -630,76 +609,6 @@
         new CfInvoke(org.objectweb.asm.Opcodes.INVOKESTATIC, newTarget, false));
   }
 
-  private Collection<CfInstruction> getThrowInstructions(
-      CfInvoke invoke,
-      SingleResolutionResult resolutionResult,
-      LocalStackAllocator localStackAllocator,
-      CfInstructionDesugaringEventConsumer eventConsumer,
-      ProgramMethod context,
-      MethodProcessingContext methodProcessingContext) {
-    assert !isAlreadyDesugared(invoke, context);
-
-    MethodSynthesizerConsumer methodSynthesizerConsumer;
-    if (resolutionResult == null) {
-      methodSynthesizerConsumer =
-          UtilityMethodsForCodeOptimizations::synthesizeThrowNoSuchMethodErrorMethod;
-    } else if (resolutionResult.getResolvedMethod().isStatic() != invoke.isInvokeStatic()) {
-      methodSynthesizerConsumer =
-          UtilityMethodsForCodeOptimizations::synthesizeThrowIncompatibleClassChangeErrorMethod;
-    } else {
-      assert false;
-      return null;
-    }
-
-    // Replace the entire effect of the invoke by by call to the throwing helper:
-    //   ...
-    //   invoke <method> [receiver] args*
-    // =>
-    //   ...
-    //   (pop arg)*
-    //   [pop receiver]
-    //   invoke <throwing-method>
-    //   pop exception result
-    //   [push fake result for <method>]
-    UtilityMethodForCodeOptimizations throwMethod =
-        methodSynthesizerConsumer.synthesizeMethod(appView, methodProcessingContext);
-    ProgramMethod throwProgramMethod = throwMethod.uncheckedGetMethod();
-    eventConsumer.acceptThrowMethod(throwProgramMethod, context);
-
-    ArrayList<CfInstruction> replacement = new ArrayList<>();
-    DexTypeList parameters = invoke.getMethod().getParameters();
-    for (int i = parameters.values.length - 1; i >= 0; i--) {
-      replacement.add(
-          new CfStackInstruction(
-              parameters.get(i).isWideType()
-                  ? CfStackInstruction.Opcode.Pop2
-                  : CfStackInstruction.Opcode.Pop));
-    }
-    if (!invoke.isInvokeStatic()) {
-      replacement.add(new CfStackInstruction(CfStackInstruction.Opcode.Pop));
-    }
-
-    CfInvoke throwInvoke =
-        new CfInvoke(
-            org.objectweb.asm.Opcodes.INVOKESTATIC, throwProgramMethod.getReference(), false);
-    assert throwInvoke.getMethod().getReturnType().isClassType();
-    replacement.add(throwInvoke);
-    replacement.add(new CfStackInstruction(CfStackInstruction.Opcode.Pop));
-
-    DexType returnType = invoke.getMethod().getReturnType();
-    if (returnType != factory.voidType) {
-      replacement.add(
-          returnType.isPrimitiveType()
-              ? new CfConstNumber(0, ValueType.fromDexType(returnType))
-              : new CfConstNull());
-    } else {
-      // If the return type is void, the stack may need an extra slot to fit the return type of
-      // the call to the throwing method.
-      localStackAllocator.allocateLocalStack(1);
-    }
-    return replacement;
-  }
-
   private void leavingStaticInvokeToInterface(ProgramMethod method) {
     // When leaving static interface method invokes possibly upgrade the class file
     // version, but don't go above the initial class file version. If the input was
@@ -756,7 +665,7 @@
     SingleResolutionResult resolutionResult =
         appView.appInfoForDesugaring().resolveMethodOn(clazz, invokedMethod).asSingleResolution();
     if (clazz.isInterface() && shouldRewriteToInvokeToThrow(resolutionResult, false)) {
-      return computeInvokeAsThrowRewrite(invoke, resolutionResult);
+      return computeInvokeAsThrowRewrite(invoke, resolutionResult, context);
     }
 
     if (clazz.isInterface() && !clazz.isLibraryClass()) {
@@ -772,7 +681,7 @@
       if (resolutionResult.getResolvedMethod().isPrivateMethod()) {
         if (resolutionResult.isAccessibleFrom(context, appView.appInfoForDesugaring()).isFalse()) {
           // TODO(b/145775365): This should throw IAE.
-          return computeInvokeAsThrowRewrite(invoke, null);
+          return computeInvokeAsThrowRewrite(invoke, null, context);
         }
         return DesugarDescription.builder()
             .setDesugarRewrite(
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
index 6bf8cf9..51b4226 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
@@ -105,23 +105,22 @@
             .setMinApi(parameters.getApiLevel())
             .run(parameters.getRuntime(), mainClass);
 
-    assertEquals(
-        expectedOutput,
-        result
-            .getStdOut()
-            .replace("java.lang.IncompatibleClassChangeError", "java.lang.IllegalAccessError"));
+    assertEquals(expectedOutput, result.getStdOut());
 
     CodeInspector inspector = result.inspector();
+
+    MethodSignature barMethodSignatureAfterArgumentRemoval =
+        new MethodSignature(
+            "bar", STRING, enableArgumentRemoval ? ImmutableList.of() : ImmutableList.of("int"));
     assertPublic(inspector, A.class, new MethodSignature("baz", STRING, ImmutableList.of()));
     assertPublic(inspector, A.class, new MethodSignature("bar", STRING, ImmutableList.of()));
-    assertPublic(inspector, A.class, new MethodSignature("bar", STRING, ImmutableList.of("int")));
+    assertPublic(inspector, A.class, barMethodSignatureAfterArgumentRemoval);
 
-    MethodSignature blahMethodSignature =
+    MethodSignature blahMethodSignatureAfterArgumentRemoval =
         new MethodSignature(
             "blah", STRING, enableArgumentRemoval ? ImmutableList.of() : ImmutableList.of("int"));
-    assertPublic(inspector, A.class, blahMethodSignature);
-    assertPublic(inspector, B.class, blahMethodSignature);
-    assertPublic(inspector, BB.class, blahMethodSignature);
+    assertPublic(inspector, A.class, blahMethodSignatureAfterArgumentRemoval);
+    assertPublic(inspector, BB.class, blahMethodSignatureAfterArgumentRemoval);
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultTest.java b/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultTest.java
index 9c9926d..698de1b 100644
--- a/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultTest.java
+++ b/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultTest.java
@@ -63,12 +63,7 @@
         .setMinApi(parameters.getApiLevel())
         .compile()
         .run(parameters.getRuntime(), Main.class)
-        .applyIf(
-            parameters.isCfRuntime()
-                || parameters.getApiLevel().isLessThanOrEqualTo(AndroidApiLevel.M),
-            r -> r.assertFailureWithErrorThatThrows(IllegalAccessError.class),
-            // TODO(b/152199517): Should be illegal access for DEX.
-            r -> r.assertSuccessWithOutputLines("I::foo"));
+        .assertFailureWithErrorThatThrows(IllegalAccessError.class);
   }
 
   @NoVerticalClassMerging
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress199142666.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress199142666.java
index e92f84a..7f77799 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress199142666.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress199142666.java
@@ -4,13 +4,13 @@
 
 package com.android.tools.r8.ir.optimize.inliner;
 
-import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertEquals;
 
-import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import java.io.IOException;
@@ -39,24 +39,21 @@
 
   @Test
   public void testInliningWhenInvalidCaller() throws Exception {
-    R8TestRunResult run =
-        testForR8(parameters.getBackend())
-            .addProgramClasses(HasInvalidStaticCall.class)
-            .addProgramClassFileData(getVirtualAAsStaticA())
-            .addKeepMainRule(HasInvalidStaticCall.class)
-            .addKeepMethodRules(StaticA.class, "void foo()")
-            .setMinApi(parameters.getApiLevel())
-            .run(parameters.getRuntime(), HasInvalidStaticCall.class);
-    if (parameters.getRuntime().asDex().getVm().getVersion().isDalvik()) {
-      // TODO(b/199142666): We should not inline to provoke this error.
-      run.assertFailureWithErrorThatMatches(
-          containsString("invoke type does not match method type of"));
-    } else {
-      // TODO(b/199142666): We should consider if we want to inline in this case (there are no
-      // verification errors)
-      run.assertSuccessWithOutputLines("foochanged")
-          .inspect(inspector -> ensureThisNumberOfCalls(inspector, HasInvalidStaticCall.class, 2));
-    }
+    testForR8(parameters.getBackend())
+        .addProgramClasses(HasInvalidStaticCall.class)
+        .addProgramClassFileData(getVirtualAAsStaticA())
+        .addKeepMainRule(HasInvalidStaticCall.class)
+        .addKeepMethodRules(StaticA.class, "void foo()")
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), HasInvalidStaticCall.class)
+        // TODO(b/199142666): We should consider if we want to inline in this case (there are no
+        //  verification errors)
+        .assertSuccessWithOutputLines("foochanged")
+        .inspect(
+            inspector -> {
+              ensureThisNumberOfCalls(inspector, HasInvalidStaticCall.class, 1);
+              ensureThisNumberThrowICCE(inspector, HasInvalidStaticCall.class, 1);
+            });
   }
 
   @Test
@@ -70,10 +67,13 @@
         .run(parameters.getRuntime(), TargetHasInvalidStaticCall.class)
         .assertSuccessWithEmptyOutput()
         .inspect(
-            inspector -> ensureThisNumberOfCalls(inspector, TargetHasInvalidStaticCall.class, 1));
+            inspector -> {
+              ensureThisNumberOfCalls(inspector, TargetHasInvalidStaticCall.class, 0);
+              ensureThisNumberThrowICCE(inspector, TargetHasInvalidStaticCall.class, 2);
+            });
   }
 
-  private void ensureThisNumberOfCalls(CodeInspector inspector, Class clazz, int fooCalls) {
+  private void ensureThisNumberOfCalls(CodeInspector inspector, Class<?> clazz, int fooCalls) {
     long count =
         inspector
             .clazz(clazz)
@@ -85,6 +85,27 @@
     assertEquals(fooCalls, count);
   }
 
+  private void ensureThisNumberThrowICCE(CodeInspector inspector, Class<?> clazz, int expected) {
+    IRCode code = inspector.clazz(clazz).mainMethod().buildIR();
+    long count =
+        code.streamInstructions()
+            .filter(Instruction::isThrow)
+            .filter(
+                instruction ->
+                    instruction
+                        .getFirstOperand()
+                        .isDefinedByInstructionSatisfying(
+                            definition ->
+                                definition.isNewInstance()
+                                    && definition
+                                        .asNewInstance()
+                                        .getType()
+                                        .getTypeName()
+                                        .equals(IncompatibleClassChangeError.class.getTypeName())))
+            .count();
+    assertEquals(expected, count);
+  }
+
   static class StaticA {
     public static void callFoo() {
       StaticA.foo();
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionAsmTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionAsmTest.java
index 1d188fb..a689715 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionAsmTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionAsmTest.java
@@ -204,8 +204,7 @@
 
     compileResult
         .run(parameters.getRuntime(), swappingMain)
-        .assertFailureWithErrorThatThrows(IllegalAccessError.class)
-        .assertFailureWithErrorThatMatches(containsString(getMethodSignature("X", "y")));
+        .assertFailureWithErrorThatThrows(IllegalAccessError.class);
 
     CodeInspector codeInspector = compileResult.inspector();
     ClassSubject base = codeInspector.clazz("A");
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
index 9c596c9..6289967 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
@@ -186,7 +186,7 @@
         .addProgramClasses(getClasses())
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), Main.class)
-        .apply(this::checkExpectedResult);
+        .apply(runResult -> checkExpectedResult(runResult, false));
   }
 
   @Test
@@ -197,10 +197,10 @@
         .setMinApi(parameters.getApiLevel())
         .addKeepMainRule(Main.class)
         .run(parameters.getRuntime(), Main.class)
-        .apply(this::checkExpectedResult);
+        .apply(runResult -> checkExpectedResult(runResult, true));
   }
 
-  private void checkExpectedResult(TestRunResult<?> result) {
+  private void checkExpectedResult(TestRunResult<?> result, boolean isR8) {
     // If not in the same nest, the error is always illegal access.
     if (!inSameNest) {
       result.assertFailureWithErrorThatThrows(IllegalAccessError.class);
@@ -209,8 +209,8 @@
 
     // If in the same nest but the reference is not exact, the error is always no such method.
     if (!symbolicReferenceIsDefiningType) {
-      // TODO(b/145775365): D8/R8 does not preserve the thrown error.
-      if (parameters.isDexRuntime()) {
+      // TODO(b/145775365): D8 does not preserve the thrown error.
+      if (parameters.isDexRuntime() && !isR8) {
         result.assertFailureWithErrorThatThrows(IllegalAccessError.class);
         return;
       }
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java
index 9a549f2..795f109 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java
@@ -82,7 +82,7 @@
         .addProgramClasses(getClasses())
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), Main.class)
-        .apply(this::checkExpectedResult);
+        .apply(runResult -> checkExpectedResult(runResult, false));
   }
 
   @Test
@@ -93,11 +93,11 @@
         .setMinApi(parameters.getApiLevel())
         .addKeepMainRule(Main.class)
         .run(parameters.getRuntime(), Main.class)
-        .apply(this::checkExpectedResult);
+        .apply(runResult -> checkExpectedResult(runResult, true));
   }
 
-  private void checkExpectedResult(TestRunResult<?> result) {
-    if (inSameNest && parameters.isCfRuntime()) {
+  private void checkExpectedResult(TestRunResult<?> result, boolean isR8) {
+    if (inSameNest && (parameters.isCfRuntime() || isR8)) {
       result.assertFailureWithErrorThatMatches(containsString(NoSuchMethodError.class.getName()));
     } else {
       result.assertFailureWithErrorThatMatches(containsString(IllegalAccessError.class.getName()));
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
index ec1222f..9adae80 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
@@ -81,7 +81,7 @@
         .addProgramClasses(getClasses())
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), Main.class)
-        .apply(this::checkExpectedResult);
+        .apply(runResult -> checkExpectedResult(runResult, false));
   }
 
   @Test
@@ -92,11 +92,11 @@
         .setMinApi(parameters.getApiLevel())
         .addKeepMainRule(Main.class)
         .run(parameters.getRuntime(), Main.class)
-        .apply(this::checkExpectedResult);
+        .apply(runResult -> checkExpectedResult(runResult, true));
   }
 
-  private void checkExpectedResult(TestRunResult<?> result) {
-    if (inSameNest && parameters.isCfRuntime()) {
+  private void checkExpectedResult(TestRunResult<?> result, boolean isR8) {
+    if (inSameNest && (parameters.isCfRuntime() || isR8)) {
       result.assertFailureWithErrorThatThrows(NoSuchMethodError.class);
     } else {
       result.assertFailureWithErrorThatThrows(IllegalAccessError.class);
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 f529432..7c9c834 100644
--- a/src/test/java/com/android/tools/r8/shaking/NonVirtualOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/NonVirtualOverrideTest.java
@@ -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()",
           "");
@@ -179,7 +179,7 @@
       assertThat(classSubject, isPresentAndRenamed());
       assertThat(classSubject.method("void", "m1", ImmutableList.of()), isPresent());
       assertThat(classSubject.method("void", "m2", ImmutableList.of()), isAbsent());
-      assertThat(classSubject.method("void", "m3", ImmutableList.of()), isPresent());
+      assertThat(classSubject.method("void", "m3", ImmutableList.of()), isAbsent());
       assertThat(classSubject.method("void", "m4", ImmutableList.of()), isAbsent());
     }
   }