Merge commit 'c27f41198df8bc546e2fba8d63328a361b794ed4' into dev-release
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
index a8386df..1328f67 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.cf.code.CfFrame.FrameType;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -147,6 +148,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
index 734246c..232f7c1 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -26,6 +27,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
index 3f93558..411ea64 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.cf.code.CfFrame.FrameType;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -74,6 +75,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
index bab53f5..585b4bc 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.cf.code.CfFrame.FrameType;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -72,6 +73,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
index f4bfd7a..4dfa1c5 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -48,6 +49,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
index 98b4cef..cc83558 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.cf.code.CfFrame.FrameType;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -97,6 +98,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
index adf0ba2..43a3a4f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -48,6 +49,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
index ff490b5..9a22ae7 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -48,6 +49,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
index 5b9e4aa..632a24c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -48,6 +49,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
index 9a42170..f6a720d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -26,6 +27,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
index a919748..6f7fcf4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -76,6 +77,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
index 8ff71b9..1c9305b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -59,6 +60,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
index 64c45fa..eed2ef1 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -65,6 +66,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
index ba90681..30bb5cc 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexField;
@@ -72,6 +73,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
index 1770409..dfa633c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
@@ -7,6 +7,7 @@
 
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCodeStackMapValidatingException;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -350,6 +351,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
index afc44f5..f3babee 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -61,6 +62,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIf.java b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
index fba8f74..433d5d9 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -89,6 +90,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
index d4119ba..bf76936 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -89,6 +90,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
index ab56f05..2d0e0f0 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -47,6 +48,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
index 70d5b53..cb0d50f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexField;
@@ -53,6 +54,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
index d7f5ef5..46d56b4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -57,6 +58,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
index 39857bf..0616bed 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.ClasspathMethod;
 import com.android.tools.r8.graph.DexClassAndMethod;
@@ -26,6 +27,7 @@
 public abstract class CfInstruction {
 
   public abstract void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index 5dfc5cb..26e029a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -88,6 +88,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
index b151132..2651e10 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexClassAndMethod;
@@ -53,6 +54,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
@@ -68,7 +70,7 @@
       bsmArgs[i] = decodeBootstrapArgument(bootstrapArgs.get(i), namingLens);
     }
     Handle bsmHandle = bootstrapMethod.toAsmHandle(namingLens);
-    DexString methodName = namingLens.lookupMethodName(rewrittenCallSite);
+    DexString methodName = namingLens.lookupMethodName(rewrittenCallSite, appView);
     visitor.visitInvokeDynamicInsn(
         methodName.toString(),
         rewrittenCallSite.methodProto.toDescriptorString(namingLens),
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
index 75f1a0f..eee91ae 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCodeStackMapValidatingException;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -47,6 +48,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
index af69cbb..5701493 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -59,6 +60,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
index 591b608..679e75d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -73,6 +74,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
index 3f487f8..b3b8a3c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.cf.code.CfFrame.FrameType;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -122,6 +123,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
index 8515ece..c947e17 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -48,6 +49,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
index b00a3fe..2209a80 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -57,6 +58,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
index 37c37f4..6da10c4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.cf.code.CfFrame.FrameType;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -49,6 +50,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNew.java b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
index b4939b6..3913b83 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNew.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -48,6 +49,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
index 41f2029..593abb4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -90,6 +91,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNop.java b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
index 5d6205a..f30e52e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -35,6 +36,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
index 6c82b1d..abe5ad1 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.cf.code.CfFrame.FrameType;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -59,6 +60,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
index fe22ae9..2d8c11d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -45,6 +46,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
index e1cebfd..9d8df3b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -70,6 +71,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
index 5a7e864..de43a8d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -40,6 +41,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
index 205808f..109df7f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.cf.code.CfFrame.FrameType;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -93,6 +94,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStore.java b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
index 1856c84..51bc1b7 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.cf.code.CfFrame.FrameType;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -74,6 +75,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
index 62effd7..9e883cf 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
@@ -6,6 +6,7 @@
 import static com.android.tools.r8.utils.ComparatorUtils.listComparator;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -95,6 +96,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
index b8b31b1..b00ef94 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -51,6 +52,7 @@
 
   @Override
   public void write(
+      AppView<?> appView,
       ProgramMethod context,
       DexItemFactory dexItemFactory,
       GraphLens graphLens,
diff --git a/src/main/java/com/android/tools/r8/graph/AppServices.java b/src/main/java/com/android/tools/r8/graph/AppServices.java
index d9ad820..70bb382 100644
--- a/src/main/java/com/android/tools/r8/graph/AppServices.java
+++ b/src/main/java/com/android/tools/r8/graph/AppServices.java
@@ -301,23 +301,24 @@
                           origin);
                       return false;
                     }
-                    if (appView.enableWholeProgramOptimizations()) {
-                      DexClass serviceImplementationClass =
-                          appView
-                              .appInfo()
-                              .definitionForWithoutExistenceAssert(serviceImplementationType);
-                      if (serviceImplementationClass == null) {
-                        warn(
-                            "Unexpected reference to missing service implementation class in "
-                                + "META-INF/services/"
-                                + serviceType.toSourceString()
-                                + ": "
-                                + serviceImplementationType.toSourceString()
-                                + ".",
-                            serviceImplementationType,
-                            origin);
-                      }
-                    }
+                    // TODO(b/169753370): Re-enable again after roll.
+                    // if (appView.enableWholeProgramOptimizations()) {
+                    //   DexClass serviceImplementationClass =
+                    //       appView
+                    //           .appInfo()
+                    //           .definitionForWithoutExistenceAssert(serviceImplementationType);
+                    //   if (serviceImplementationClass == null) {
+                    //     warn(
+                    //         "Unexpected reference to missing service implementation class in "
+                    //             + "META-INF/services/"
+                    //             + serviceType.toSourceString()
+                    //             + ": "
+                    //             + serviceImplementationType.toSourceString()
+                    //             + ".",
+                    //         serviceImplementationType,
+                    //         origin);
+                    //   }
+                    // }
                     // Only keep one of each implementation type in the list.
                     return !serviceImplementations.contains(serviceImplementationType);
                   })
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index 79d6d83..de1c2b9 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -299,7 +299,7 @@
     if (shouldAddParameterNames(method.getDefinition(), appView)) {
       parameterLabel = new CfLabel();
       parameterLabel.write(
-          method, dexItemFactory, graphLens, initClassLens, namingLens, rewriter, visitor);
+          appView, method, dexItemFactory, graphLens, initClassLens, namingLens, rewriter, visitor);
     }
     for (CfInstruction instruction : instructions) {
       if (instruction instanceof CfFrame
@@ -308,7 +308,7 @@
         continue;
       }
       instruction.write(
-          method, dexItemFactory, graphLens, initClassLens, namingLens, rewriter, visitor);
+          appView, method, dexItemFactory, graphLens, initClassLens, namingLens, rewriter, visitor);
     }
     visitor.visitEnd();
     visitor.visitMaxs(maxStack, maxLocals);
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index cfccc2b..00dfa0b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -2261,6 +2261,7 @@
         });
   }
 
+  @Deprecated
   synchronized public void forAllTypes(Consumer<DexType> f) {
     new ArrayList<>(types.values()).forEach(f);
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexString.java b/src/main/java/com/android/tools/r8/graph/DexString.java
index 602a6b7..b5d50f0 100644
--- a/src/main/java/com/android/tools/r8/graph/DexString.java
+++ b/src/main/java/com/android/tools/r8/graph/DexString.java
@@ -500,4 +500,11 @@
     }
     return arrayDim;
   }
+
+  public DexString toArrayDescriptor(int dimensions, DexItemFactory dexItemFactory) {
+    byte[] newContent = new byte[content.length + dimensions];
+    Arrays.fill(newContent, 0, dimensions, (byte) '[');
+    System.arraycopy(content, 0, newContent, dimensions, content.length);
+    return dexItemFactory.createString(size + dimensions, newContent);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index f21e965..b1892bf 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -52,6 +52,10 @@
     this.descriptor = descriptor;
   }
 
+  public DexString getDescriptor() {
+    return descriptor;
+  }
+
   @Override
   public int computeHashCode() {
     return descriptor.hashCode();
@@ -431,11 +435,7 @@
   }
 
   public DexType toArrayType(int dimensions, DexItemFactory dexItemFactory) {
-    byte[] content = new byte[descriptor.content.length + dimensions];
-    Arrays.fill(content, 0, dimensions, (byte) '[');
-    System.arraycopy(descriptor.content, 0, content, dimensions, descriptor.content.length);
-    DexString newDesc = dexItemFactory.createString(descriptor.size + dimensions, content);
-    return dexItemFactory.createType(newDesc);
+    return dexItemFactory.createType(descriptor.toArrayDescriptor(dimensions, dexItemFactory));
   }
 
   public DexType toArrayElementType(DexItemFactory dexItemFactory) {
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignature.java b/src/main/java/com/android/tools/r8/graph/GenericSignature.java
index beb391d..2427913 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignature.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignature.java
@@ -7,13 +7,13 @@
 import static com.android.tools.r8.utils.DescriptorUtils.getDescriptorFromClassBinaryName;
 
 import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.ImmutableList;
 import java.lang.reflect.GenericSignatureFormatError;
 import java.nio.CharBuffer;
 import java.util.List;
-import java.util.function.Function;
 
 /**
  * Internal encoding of the generics signature attribute as defined by JVMS 7 $ 4.3.4.
@@ -95,29 +95,33 @@
  */
 public class GenericSignature {
 
-  private static final List<FormalTypeParameter> EMPTY_TYPE_PARAMS = ImmutableList.of();
+  static final List<FormalTypeParameter> EMPTY_TYPE_PARAMS = ImmutableList.of();
+  static final List<FieldTypeSignature> EMPTY_TYPE_ARGUMENTS = ImmutableList.of();
+  static final List<ClassTypeSignature> EMPTY_SUPER_INTERFACES = ImmutableList.of();
+  static final List<TypeSignature> EMPTY_TYPE_SIGNATURES = ImmutableList.of();
 
   interface DexDefinitionSignature<T extends DexDefinition> {
+
     default boolean isClassSignature() {
       return false;
     }
 
+    default boolean isFieldTypeSignature() {
+      return false;
+    }
+
+    default boolean isMethodTypeSignature() {
+      return false;
+    }
+
     default ClassSignature asClassSignature() {
       return null;
     }
 
-    default boolean isFieldTypeSignature() {
-      return false;
-    }
-
     default FieldTypeSignature asFieldTypeSignature() {
       return null;
     }
 
-    default boolean isMethodTypeSignature() {
-      return false;
-    }
-
     default MethodTypeSignature asMethodTypeSignature() {
       return null;
     }
@@ -147,14 +151,22 @@
     public List<FieldTypeSignature> getInterfaceBounds() {
       return interfaceBounds;
     }
+
+    public void visit(GenericSignatureVisitor visitor) {
+      visitor.visitClassBound(classBound);
+      if (interfaceBounds == null) {
+        return;
+      }
+      for (FieldTypeSignature interfaceBound : interfaceBounds) {
+        visitor.visitInterfaceBound(interfaceBound);
+      }
+    }
   }
 
   public static class ClassSignature implements DexDefinitionSignature<DexClass> {
-    static final ClassSignature UNKNOWN_CLASS_SIGNATURE =
-        new ClassSignature(
-            ImmutableList.of(),
-            ClassTypeSignature.UNKNOWN_CLASS_TYPE_SIGNATURE,
-            ImmutableList.of());
+
+    public static final ClassSignature NO_CLASS_SIGNATURE =
+        new ClassSignature(EMPTY_TYPE_PARAMS, NO_FIELD_TYPE_SIGNATURE, EMPTY_SUPER_INTERFACES);
 
     final List<FormalTypeParameter> formalTypeParameters;
     final ClassTypeSignature superClassSignature;
@@ -180,6 +192,14 @@
       return superInterfaceSignatures;
     }
 
+    public boolean hasSignature() {
+      return this != NO_CLASS_SIGNATURE;
+    }
+
+    public boolean hasNoSignature() {
+      return !hasSignature();
+    }
+
     @Override
     public boolean isClassSignature() {
       return true;
@@ -189,9 +209,18 @@
     public ClassSignature asClassSignature() {
       return this;
     }
+
+    public void visit(GenericSignatureVisitor visitor) {
+      visitor.visitFormalTypeParameters(formalTypeParameters);
+      visitor.visitSuperClass(superClassSignature);
+      for (ClassTypeSignature superInterface : superInterfaceSignatures) {
+        visitor.visitSuperInterface(superInterface);
+      }
+    }
   }
 
   public abstract static class TypeSignature {
+
     public boolean isFieldTypeSignature() {
       return false;
     }
@@ -208,11 +237,7 @@
       return null;
     }
 
-    public TypeSignature toArrayTypeSignature(AppView<?> appView) {
-      return null;
-    }
-
-    public TypeSignature toArrayElementTypeSignature(AppView<?> appView) {
+    public ArrayTypeSignature toArrayTypeSignature() {
       return null;
     }
   }
@@ -275,8 +300,8 @@
       return null;
     }
 
-    public boolean isUnknown() {
-      return this == ClassTypeSignature.UNKNOWN_CLASS_TYPE_SIGNATURE;
+    public boolean hasSignature() {
+      return this != GenericSignature.NO_FIELD_TYPE_SIGNATURE;
     }
 
     public abstract FieldTypeSignature asArgument(WildcardIndicator indicator);
@@ -286,10 +311,9 @@
     }
   }
 
-  private static final class StarFieldTypeSignature extends FieldTypeSignature {
+  static final class StarFieldTypeSignature extends FieldTypeSignature {
 
-    private static final StarFieldTypeSignature STAR_FIELD_TYPE_SIGNATURE =
-        new StarFieldTypeSignature();
+    static final StarFieldTypeSignature STAR_FIELD_TYPE_SIGNATURE = new StarFieldTypeSignature();
 
     private StarFieldTypeSignature() {
       super(WildcardIndicator.NONE);
@@ -306,11 +330,13 @@
     }
   }
 
+  public static final ClassTypeSignature NO_FIELD_TYPE_SIGNATURE =
+      new ClassTypeSignature(DexItemFactory.nullValueType, EMPTY_TYPE_ARGUMENTS);
+
   public static class ClassTypeSignature extends FieldTypeSignature {
-    static final ClassTypeSignature UNKNOWN_CLASS_TYPE_SIGNATURE =
-        new ClassTypeSignature(DexItemFactory.nullValueType, ImmutableList.of());
 
     final DexType type;
+
     // E.g., for Map<K, V>, a signature will indicate what types are for K and V.
     // Note that this could be nested, e.g., Map<K, Consumer<V>>.
     final List<FieldTypeSignature> typeArguments;
@@ -361,8 +387,12 @@
       return argument;
     }
 
+    public boolean isNoSignature() {
+      return this == NO_FIELD_TYPE_SIGNATURE;
+    }
+
     @Override
-    public ArrayTypeSignature toArrayTypeSignature(AppView<?> appView) {
+    public ArrayTypeSignature toArrayTypeSignature() {
       return new ArrayTypeSignature(this);
     }
 
@@ -371,6 +401,13 @@
       outer.innerTypeSignature = inner;
       inner.enclosingTypeSignature = outer;
     }
+
+    public void visit(GenericSignatureVisitor visitor) {
+      visitor.visitTypeArguments(typeArguments);
+      if (innerTypeSignature != null) {
+        visitor.visitSimpleClass(innerTypeSignature);
+      }
+    }
   }
 
   public static class ArrayTypeSignature extends FieldTypeSignature {
@@ -408,13 +445,12 @@
     }
 
     @Override
-    public TypeSignature toArrayTypeSignature(AppView<?> appView) {
+    public ArrayTypeSignature toArrayTypeSignature() {
       return new ArrayTypeSignature(this);
     }
 
-    @Override
-    public TypeSignature toArrayElementTypeSignature(AppView<?> appView) {
-      return elementSignature;
+    public void visit(GenericSignatureVisitor visitor) {
+      visitor.visitTypeSignature(elementSignature);
     }
   }
 
@@ -449,7 +485,7 @@
     }
 
     @Override
-    public ArrayTypeSignature toArrayTypeSignature(AppView<?> appView) {
+    public ArrayTypeSignature toArrayTypeSignature() {
       return new ArrayTypeSignature(this);
     }
 
@@ -479,7 +515,7 @@
     }
 
     @Override
-    public ArrayTypeSignature toArrayTypeSignature(AppView<?> appView) {
+    public ArrayTypeSignature toArrayTypeSignature() {
       assert !type.isVoidType();
       return new ArrayTypeSignature(this);
     }
@@ -505,9 +541,10 @@
   }
 
   public static class MethodTypeSignature implements DexDefinitionSignature<DexEncodedMethod> {
-    static final MethodTypeSignature UNKNOWN_METHOD_TYPE_SIGNATURE =
+
+    public static final MethodTypeSignature NO_METHOD_TYPE_SIGNATURE =
         new MethodTypeSignature(
-            ImmutableList.of(), ImmutableList.of(), ReturnType.VOID, ImmutableList.of());
+            EMPTY_TYPE_PARAMS, EMPTY_TYPE_SIGNATURES, ReturnType.VOID, EMPTY_TYPE_SIGNATURES);
 
     final List<FormalTypeParameter> formalTypeParameters;
     final List<TypeSignature> typeSignatures;
@@ -549,110 +586,82 @@
       return true;
     }
 
+    public boolean hasSignature() {
+      return this != NO_METHOD_TYPE_SIGNATURE;
+    }
+
     @Override
     public MethodTypeSignature asMethodTypeSignature() {
       return this;
     }
 
+    public void visit(GenericSignatureVisitor visitor) {
+      visitor.visitFormalTypeParameters(formalTypeParameters);
+      visitor.visitMethodTypeSignatures(typeSignatures);
+      visitor.visitReturnType(returnType);
+      visitor.visitThrowsSignatures(throwsSignatures);
+    }
+
     public List<FormalTypeParameter> getFormalTypeParameters() {
       return formalTypeParameters;
     }
   }
 
-  enum Kind {
-    CLASS, FIELD, METHOD;
-
-    static Kind fromDexDefinition(DexDefinition definition) {
-      if (definition.isDexClass()) {
-        return CLASS;
-      }
-      if (definition.isDexEncodedField()) {
-        return FIELD;
-      }
-      if (definition.isDexEncodedMethod()) {
-        return METHOD;
-      }
-      throw new Unreachable("Unexpected kind of DexDefinition: " + definition);
+  public static ClassSignature parseClassSignature(
+      String className,
+      String signature,
+      Origin origin,
+      DexItemFactory factory,
+      Reporter reporter) {
+    if (signature == null || signature.isEmpty()) {
+      return ClassSignature.NO_CLASS_SIGNATURE;
     }
+    Parser parser = new Parser(factory);
+    try {
+      return parser.parseClassSignature(signature);
+    } catch (GenericSignatureFormatError e) {
+      reporter.warning(
+          GenericSignatureDiagnostic.invalidClassSignature(signature, className, origin, e));
+      return ClassSignature.NO_CLASS_SIGNATURE;
+    }
+  }
 
-    Function<String, ? extends DexDefinitionSignature<? extends DexDefinition>>
-        parserMethod(Parser parser) {
-      switch (this) {
-        case CLASS:
-          return parser::parseClassSignature;
-        case FIELD:
-          return parser::parseFieldTypeSignature;
-        case METHOD:
-          return parser::parseMethodTypeSignature;
-      }
-      throw new Unreachable("Unexpected kind: " + this);
+  public static FieldTypeSignature parseFieldTypeSignature(
+      String fieldName,
+      String signature,
+      Origin origin,
+      DexItemFactory factory,
+      Reporter reporter) {
+    Parser parser = new Parser(factory);
+    try {
+      return parser.parseFieldTypeSignature(signature);
+    } catch (GenericSignatureFormatError e) {
+      reporter.warning(
+          GenericSignatureDiagnostic.invalidFieldSignature(signature, fieldName, origin, e));
+      return GenericSignature.NO_FIELD_TYPE_SIGNATURE;
+    }
+  }
+
+  public static MethodTypeSignature parseMethodSignature(
+      String methodName,
+      String signature,
+      Origin origin,
+      DexItemFactory factory,
+      Reporter reporter) {
+    if (signature == null || signature.isEmpty()) {
+      return MethodTypeSignature.NO_METHOD_TYPE_SIGNATURE;
+    }
+    Parser parser = new Parser(factory);
+    try {
+      return parser.parseMethodTypeSignature(signature);
+    } catch (GenericSignatureFormatError e) {
+      reporter.warning(
+          GenericSignatureDiagnostic.invalidMethodSignature(signature, methodName, origin, e));
+      return MethodTypeSignature.NO_METHOD_TYPE_SIGNATURE;
     }
   }
 
   public static class Parser {
-    // TODO(b/129925954): Can we merge variants of to*Signature below and just expose
-    //  type-parameterized version of this, like
-    //    <T extends DexDefinitionSignature<?>> T toGenericSignature
-    //  without unchecked cast?
-    private static DexDefinitionSignature<? extends DexDefinition> toGenericSignature(
-        DexClass currentClassContext,
-        DexDefinition definition,
-        AppView<AppInfoWithLiveness> appView) {
-      DexAnnotationSet annotations = definition.annotations();
-      if (annotations.annotations.length == 0) {
-        return null;
-      }
-      for (int i = 0; i < annotations.annotations.length; i++) {
-        DexAnnotation annotation = annotations.annotations[i];
-        if (!DexAnnotation.isSignatureAnnotation(annotation, appView.dexItemFactory())) {
-          continue;
-        }
-        Kind kind = Kind.fromDexDefinition(definition);
-        Parser parser = new Parser(currentClassContext, appView);
-        String signature = DexAnnotation.getSignature(annotation);
-        try {
-          return kind.parserMethod(parser).apply(signature);
-        } catch (GenericSignatureFormatError e) {
-          appView.options().warningInvalidSignature(
-              definition, currentClassContext.getOrigin(), signature, e);
-        }
-      }
-      return null;
-    }
-
-    public static ClassSignature toClassSignature(
-        DexClass clazz, AppView<AppInfoWithLiveness> appView) {
-      DexDefinitionSignature<?> signature = toGenericSignature(clazz, clazz, appView);
-      if (signature != null) {
-        assert signature.isClassSignature();
-        return signature.asClassSignature();
-      }
-      return ClassSignature.UNKNOWN_CLASS_SIGNATURE;
-    }
-
-    public static FieldTypeSignature toFieldTypeSignature(
-        DexEncodedField field, AppView<AppInfoWithLiveness> appView) {
-      DexClass currentClassContext = appView.definitionFor(field.holder());
-      DexDefinitionSignature<?> signature =
-          toGenericSignature(currentClassContext, field, appView);
-      if (signature != null) {
-        assert signature.isFieldTypeSignature();
-        return signature.asFieldTypeSignature();
-      }
-      return ClassTypeSignature.UNKNOWN_CLASS_TYPE_SIGNATURE;
-    }
-
-    public static MethodTypeSignature toMethodTypeSignature(
-        DexEncodedMethod method, AppView<AppInfoWithLiveness> appView) {
-      DexClass currentClassContext = appView.definitionFor(method.holder());
-      DexDefinitionSignature<?> signature =
-          toGenericSignature(currentClassContext, method, appView);
-      if (signature != null) {
-        assert signature.isMethodTypeSignature();
-        return signature.asMethodTypeSignature();
-      }
-      return MethodTypeSignature.UNKNOWN_METHOD_TYPE_SIGNATURE;
-    }
 
     /*
      * Parser:
@@ -672,9 +681,8 @@
 
     private int pos;
 
-    private Parser(DexClass currentClassContext, AppView<AppInfoWithLiveness> appView) {
-      this.currentClassContext = currentClassContext;
-      this.appView = appView;
+    private Parser(DexItemFactory factory) {
+      this.factory = factory;
     }
 
     ClassSignature parseClassSignature(String signature) {
@@ -708,7 +716,7 @@
     FieldTypeSignature parseFieldTypeSignature(String signature) {
       try {
         setInput(signature);
-        return parseFieldTypeSignature(ParserPosition.MEMBER_ANNOTATION);
+        return parseFieldTypeSignature();
       } catch (GenericSignatureFormatError e) {
         throw e;
       } catch (Throwable t) {
@@ -732,40 +740,11 @@
     // Action:
     //
 
-    enum ParserPosition {
-      CLASS_SUPER_OR_INTERFACE_ANNOTATION,
-      ENCLOSING_INNER_OR_TYPE_ANNOTATION,
-      MEMBER_ANNOTATION
-    }
+    private final DexItemFactory factory;
 
-    private final AppView<AppInfoWithLiveness> appView;
-    private final DexClass currentClassContext;
-    private DexType lastWrittenType = null;
-
-    private DexType parsedTypeName(String name, ParserPosition parserPosition) {
-      if (parserPosition == ParserPosition.ENCLOSING_INNER_OR_TYPE_ANNOTATION
-          && lastWrittenType == null) {
-        // We are writing type-arguments for a merged class.
-        return null;
-      }
+    private DexType parsedTypeName(String name) {
       String originalDescriptor = getDescriptorFromClassBinaryName(name);
-      DexType type =
-          appView.graphLens().lookupType(appView.dexItemFactory().createType(originalDescriptor));
-      if (appView.appInfo().wasPruned(type)) {
-        type = appView.dexItemFactory().objectType;
-      }
-      if (parserPosition == ParserPosition.CLASS_SUPER_OR_INTERFACE_ANNOTATION
-          && currentClassContext != null) {
-        // We may have merged the type down to the current class type.
-        DexString classDescriptor = currentClassContext.type.descriptor;
-        if (!originalDescriptor.equals(classDescriptor.toString())
-            && type.descriptor.equals(classDescriptor)) {
-          lastWrittenType = null;
-          return type;
-        }
-      }
-      lastWrittenType = type;
-      return type;
+      return factory.createType(originalDescriptor);
     }
 
     private DexType parsedInnerTypeName(DexType enclosingType, String name) {
@@ -775,15 +754,11 @@
       }
       assert enclosingType.isClassType();
       String enclosingDescriptor = enclosingType.toDescriptorString();
-      DexType type =
-          appView
-              .dexItemFactory()
-              .createType(
-                  getDescriptorFromClassBinaryName(
-                      getClassBinaryNameFromDescriptor(enclosingDescriptor)
-                          + DescriptorUtils.INNER_CLASS_SEPARATOR
-                          + name));
-      return appView.graphLens().lookupType(type);
+      return factory.createType(
+          getDescriptorFromClassBinaryName(
+              getClassBinaryNameFromDescriptor(enclosingDescriptor)
+                  + DescriptorUtils.INNER_CLASS_SEPARATOR
+                  + name));
     }
 
     //
@@ -796,13 +771,12 @@
       List<FormalTypeParameter> formalTypeParameters = parseOptFormalTypeParameters();
 
       // SuperclassSignature ::= ClassTypeSignature.
-      ClassTypeSignature superClassSignature =
-          parseClassTypeSignature(ParserPosition.CLASS_SUPER_OR_INTERFACE_ANNOTATION);
+      ClassTypeSignature superClassSignature = parseClassTypeSignature();
 
       ImmutableList.Builder<ClassTypeSignature> builder = ImmutableList.builder();
       while (symbol > 0) {
         // SuperinterfaceSignature ::= ClassTypeSignature.
-        builder.add(parseClassTypeSignature(ParserPosition.CLASS_SUPER_OR_INTERFACE_ANNOTATION));
+        builder.add(parseClassTypeSignature());
       }
 
       return new ClassSignature(formalTypeParameters, superClassSignature, builder.build());
@@ -833,9 +807,9 @@
       // ClassBound ::= ":" FieldTypeSignature?.
       expect(':');
 
-      FieldTypeSignature classBound = ClassTypeSignature.UNKNOWN_CLASS_TYPE_SIGNATURE;
+      FieldTypeSignature classBound = GenericSignature.NO_FIELD_TYPE_SIGNATURE;
       if (symbol == 'L' || symbol == '[' || symbol == 'T') {
-        classBound = parseFieldTypeSignature(ParserPosition.MEMBER_ANNOTATION);
+        classBound = parseFieldTypeSignature();
       }
 
       // Only build the interfacebound builder, which is uncommon, if we actually see an interface.
@@ -846,7 +820,7 @@
           builder = ImmutableList.builder();
         }
         scanSymbol();
-        builder.add(parseFieldTypeSignature(ParserPosition.MEMBER_ANNOTATION));
+        builder.add(parseFieldTypeSignature());
       }
       if (builder == null) {
         return new FormalTypeParameter(typeParameterIdentifier, classBound, null);
@@ -854,16 +828,16 @@
       return new FormalTypeParameter(typeParameterIdentifier, classBound, builder.build());
     }
 
-    private FieldTypeSignature parseFieldTypeSignature(ParserPosition parserPosition) {
+    private FieldTypeSignature parseFieldTypeSignature() {
       // FieldTypeSignature ::= ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature.
       switch (symbol) {
         case 'L':
-          return parseClassTypeSignature(parserPosition);
+          return parseClassTypeSignature();
         case '[':
           // ArrayTypeSignature ::= "[" TypeSignature.
           scanSymbol();
-          TypeSignature baseTypeSignature = updateTypeSignature(parserPosition);
-          return baseTypeSignature.toArrayTypeSignature(appView).asFieldTypeSignature();
+          TypeSignature baseTypeSignature = updateTypeSignature();
+          return baseTypeSignature.toArrayTypeSignature().asFieldTypeSignature();
         case 'T':
           return updateTypeVariableSignature();
         default:
@@ -872,7 +846,7 @@
       throw new Unreachable("Either FieldTypeSignature is returned or a parse error is thrown.");
     }
 
-    private ClassTypeSignature parseClassTypeSignature(ParserPosition parserPosition) {
+    private ClassTypeSignature parseClassTypeSignature() {
       // ClassTypeSignature ::=
       //   "L" (Identifier "/")* Identifier TypeArguments? ("." Identifier TypeArguments?)* ";".
       expect('L');
@@ -888,11 +862,12 @@
       }
 
       qualIdent.append(this.identifier);
-      DexType parsedEnclosingType = parsedTypeName(qualIdent.toString(), parserPosition);
+      DexType parsedEnclosingType = parsedTypeName(qualIdent.toString());
 
       List<FieldTypeSignature> typeArguments = updateOptTypeArguments();
       ClassTypeSignature outerMostTypeSignature =
-          new ClassTypeSignature(parsedEnclosingType, typeArguments);
+          new ClassTypeSignature(
+              parsedEnclosingType, typeArguments.isEmpty() ? EMPTY_TYPE_ARGUMENTS : typeArguments);
 
       ClassTypeSignature outerTypeSignature = outerMostTypeSignature;
       ClassTypeSignature innerTypeSignature;
@@ -903,7 +878,10 @@
         assert identifier != null;
         parsedEnclosingType = parsedInnerTypeName(parsedEnclosingType, identifier);
         typeArguments = updateOptTypeArguments();
-        innerTypeSignature = new ClassTypeSignature(parsedEnclosingType, typeArguments);
+        innerTypeSignature =
+            new ClassTypeSignature(
+                parsedEnclosingType,
+                typeArguments.isEmpty() ? EMPTY_TYPE_ARGUMENTS : typeArguments);
         ClassTypeSignature.link(outerTypeSignature, innerTypeSignature);
         outerTypeSignature = innerTypeSignature;
       }
@@ -935,15 +913,12 @@
         return StarFieldTypeSignature.STAR_FIELD_TYPE_SIGNATURE;
       } else if (symbol == '+') {
         scanSymbol();
-        return parseFieldTypeSignature(ParserPosition.ENCLOSING_INNER_OR_TYPE_ANNOTATION)
-            .asArgument(WildcardIndicator.POSITIVE);
+        return parseFieldTypeSignature().asArgument(WildcardIndicator.POSITIVE);
       } else if (symbol == '-') {
         scanSymbol();
-        return parseFieldTypeSignature(ParserPosition.ENCLOSING_INNER_OR_TYPE_ANNOTATION)
-            .asArgument(WildcardIndicator.NEGATIVE);
+        return parseFieldTypeSignature().asArgument(WildcardIndicator.NEGATIVE);
       } else {
-        return parseFieldTypeSignature(ParserPosition.ENCLOSING_INNER_OR_TYPE_ANNOTATION)
-            .asArgument(WildcardIndicator.NONE);
+        return parseFieldTypeSignature().asArgument(WildcardIndicator.NONE);
       }
     }
 
@@ -958,7 +933,7 @@
       return new TypeVariableSignature(identifier);
     }
 
-    private TypeSignature updateTypeSignature(ParserPosition parserPosition) {
+    private TypeSignature updateTypeSignature() {
       switch (symbol) {
         case 'B':
         case 'C':
@@ -968,13 +943,13 @@
         case 'J':
         case 'S':
         case 'Z':
-          DexType type = appView.dexItemFactory().createType(String.valueOf(symbol));
+          DexType type = factory.createType(String.valueOf(symbol));
           BaseTypeSignature baseTypeSignature = new BaseTypeSignature(type);
           scanSymbol();
           return baseTypeSignature;
         default:
           // Not an elementary type, but a FieldTypeSignature.
-          return parseFieldTypeSignature(parserPosition);
+          return parseFieldTypeSignature();
       }
     }
 
@@ -987,7 +962,7 @@
 
       ImmutableList.Builder<TypeSignature> parameterSignatureBuilder = ImmutableList.builder();
       while (symbol != ')' && (symbol > 0)) {
-        parameterSignatureBuilder.add(updateTypeSignature(ParserPosition.MEMBER_ANNOTATION));
+        parameterSignatureBuilder.add(updateTypeSignature());
       }
 
       expect(')');
@@ -1003,7 +978,7 @@
           if (symbol == 'T') {
             throwsSignatureBuilder.add(updateTypeVariableSignature());
           } else {
-            throwsSignatureBuilder.add(parseClassTypeSignature(ParserPosition.MEMBER_ANNOTATION));
+            throwsSignatureBuilder.add(parseClassTypeSignature());
           }
         } while (symbol == '^');
       }
@@ -1018,7 +993,7 @@
     private ReturnType updateReturnType() {
       // ReturnType ::= TypeSignature | "V".
       if (symbol != 'V') {
-        return new ReturnType(updateTypeSignature(ParserPosition.MEMBER_ANNOTATION));
+        return new ReturnType(updateTypeSignature());
       } else {
         scanSymbol();
         return ReturnType.VOID;
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureDiagnostic.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureDiagnostic.java
new file mode 100644
index 0000000..fa95bce
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureDiagnostic.java
@@ -0,0 +1,75 @@
+// Copyright (c) 2020, 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.graph;
+
+import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
+import java.lang.reflect.GenericSignatureFormatError;
+
+public class GenericSignatureDiagnostic implements Diagnostic {
+
+  private final Origin origin;
+  private final Position position;
+  private final String message;
+
+  GenericSignatureDiagnostic(Origin origin, Position position, String message) {
+    this.origin = origin;
+    this.position = position;
+    this.message = message;
+  }
+
+  @Override
+  public Origin getOrigin() {
+    return origin;
+  }
+
+  @Override
+  public Position getPosition() {
+    return position;
+  }
+
+  @Override
+  public String getDiagnosticMessage() {
+    return message;
+  }
+
+  static GenericSignatureDiagnostic invalidClassSignature(
+      String signature, String name, Origin origin, GenericSignatureFormatError error) {
+    return invalidSignature(signature, "class", name, origin, error);
+  }
+
+  static GenericSignatureDiagnostic invalidMethodSignature(
+      String signature, String name, Origin origin, GenericSignatureFormatError error) {
+    return invalidSignature(signature, "method", name, origin, error);
+  }
+
+  static GenericSignatureDiagnostic invalidFieldSignature(
+      String signature, String name, Origin origin, GenericSignatureFormatError error) {
+    return invalidSignature(signature, "field", name, origin, error);
+  }
+
+  private static GenericSignatureDiagnostic invalidSignature(
+      String signature,
+      String kind,
+      String name,
+      Origin origin,
+      GenericSignatureFormatError error) {
+    String message =
+        "Invalid signature '"
+            + signature
+            + "' for "
+            + kind
+            + " "
+            + name
+            + "."
+            + System.lineSeparator()
+            + "Signature is ignored and will not be present in the output."
+            + System.lineSeparator()
+            + "Parser error: "
+            + error.getMessage();
+    return new GenericSignatureDiagnostic(origin, Position.UNKNOWN, message);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureVisitor.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureVisitor.java
new file mode 100644
index 0000000..22ddca7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureVisitor.java
@@ -0,0 +1,75 @@
+// Copyright (c) 2020, 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.graph;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.GenericSignature.ClassSignature;
+import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
+import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
+import com.android.tools.r8.graph.GenericSignature.FormalTypeParameter;
+import com.android.tools.r8.graph.GenericSignature.ReturnType;
+import com.android.tools.r8.graph.GenericSignature.TypeSignature;
+import com.android.tools.r8.naming.MemberNaming.FieldSignature;
+import com.android.tools.r8.naming.MemberNaming.MethodSignature;
+import java.util.List;
+
+public interface GenericSignatureVisitor {
+
+  default void visitClassSignature(ClassSignature classSignature) {
+    throw new Unreachable("Implement if visited");
+  }
+
+  default void visitMethodSignature(MethodSignature methodSignature) {
+    throw new Unreachable("Implement if visited");
+  }
+
+  default void visitFieldSignature(FieldSignature fieldSignature) {
+    throw new Unreachable("Implement if visited");
+  }
+
+  default void visitFormalTypeParameters(List<FormalTypeParameter> formalTypeParameters) {
+    throw new Unreachable("Implement if visited");
+  }
+
+  default void visitClassBound(FieldTypeSignature fieldSignature) {
+    throw new Unreachable("Implement if visited");
+  }
+
+  default void visitInterfaceBound(FieldTypeSignature fieldSignature) {
+    throw new Unreachable("Implement if visited");
+  }
+
+  default void visitSuperClass(ClassTypeSignature classTypeSignature) {
+    throw new Unreachable("Implement if visited");
+  }
+
+  default void visitSuperInterface(ClassTypeSignature classTypeSignature) {
+    throw new Unreachable("Implement if visited");
+  }
+
+  default void visitTypeSignature(TypeSignature typeSignature) {
+    throw new Unreachable("Implement if visited");
+  }
+
+  default void visitSimpleClass(ClassTypeSignature classTypeSignature) {
+    throw new Unreachable("Implement if visited");
+  }
+
+  default void visitReturnType(ReturnType returnType) {
+    throw new Unreachable("Implement if visited");
+  }
+
+  default void visitMethodTypeSignatures(List<TypeSignature> typeSignatures) {
+    throw new Unreachable("Implement if visited");
+  }
+
+  default void visitThrowsSignatures(List<TypeSignature> typeSignatures) {
+    throw new Unreachable("Implement if visited");
+  }
+
+  default void visitTypeArguments(List<FieldTypeSignature> typeArguments) {
+    throw new Unreachable("Implement if visited");
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLens.java b/src/main/java/com/android/tools/r8/graph/GraphLens.java
index b276437..20c918c 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLens.java
@@ -331,9 +331,7 @@
   }
 
   /** Lookup a rebound or non-rebound method reference using the current graph lens. */
-  public MethodLookupResult lookupMethod(DexMethod method, DexMethod context, Type type) {
-    return internalLookupMethod(method, context, type, result -> result);
-  }
+  public abstract MethodLookupResult lookupMethod(DexMethod method, DexMethod context, Type type);
 
   protected abstract MethodLookupResult internalLookupMethod(
       DexMethod reference, DexMethod context, Type type, LookupMethodContinuation continuation);
@@ -610,6 +608,10 @@
       this.previousLens = previousLens;
     }
 
+    public final DexItemFactory dexItemFactory() {
+      return dexItemFactory;
+    }
+
     public final GraphLens getPrevious() {
       return previousLens;
     }
@@ -622,6 +624,20 @@
     }
 
     @Override
+    public MethodLookupResult lookupMethod(DexMethod method, DexMethod context, Type type) {
+      if (method.getHolderType().isArrayType()) {
+        assert method.getName() == dexItemFactory.cloneMethodName;
+        assert method.getReturnType() == dexItemFactory.objectType;
+        return MethodLookupResult.builder(this)
+            .setReference(method.withHolder(lookupType(method.getHolderType()), dexItemFactory))
+            .setType(type)
+            .build();
+      }
+      assert method.getHolderType().isClassType();
+      return internalLookupMethod(method, context, type, result -> result);
+    }
+
+    @Override
     public final DexType lookupType(DexType type) {
       if (type.isPrimitiveType() || type.isVoidType() || type.isNullValueType()) {
         return type;
@@ -744,6 +760,11 @@
     }
 
     @Override
+    public MethodLookupResult lookupMethod(DexMethod method, DexMethod context, Type type) {
+      return MethodLookupResult.builder(this).setReference(method).setType(type).build();
+    }
+
+    @Override
     public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
         DexMethod method) {
       return RewrittenPrototypeDescription.none();
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
index d87bddc..adc4f12 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.horizontalclassmerging.policies.DontMergeSynchronizedClasses;
+import com.android.tools.r8.horizontalclassmerging.policies.NoAbstractClasses;
 import com.android.tools.r8.horizontalclassmerging.policies.NoAnnotations;
 import com.android.tools.r8.horizontalclassmerging.policies.NoClassesOrMembersWithAnnotations;
 import com.android.tools.r8.horizontalclassmerging.policies.NoClassesWithInterfaces;
@@ -56,6 +57,7 @@
             new NoInterfaces(),
             new NoClassesWithInterfaces(),
             new NoAnnotations(),
+            new NoAbstractClasses(),
             new NoClassesOrMembersWithAnnotations(),
             new NoInnerClasses(),
             new NoStaticClassInitializer(),
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
index 2bf2b97..0f9fdc1 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -67,6 +67,9 @@
       if (resolutionResult == null) {
         return null;
       }
+      if (resolutionResult.getResolvedMethod().isAbstract()) {
+        return null;
+      }
       return resolutionResult.getResolvedMethod().method;
     }
 
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoAbstractClasses.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoAbstractClasses.java
new file mode 100644
index 0000000..fdc849d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoAbstractClasses.java
@@ -0,0 +1,18 @@
+// Copyright (c) 2020, 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.horizontalclassmerging.policies;
+
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
+import com.google.common.collect.Iterables;
+
+public class NoAbstractClasses extends SingleClassPolicy {
+  @Override
+  public boolean canMerge(DexProgramClass program) {
+    return !program.isAbstract()
+        && !Iterables.any(program.virtualMethods(), DexEncodedMethod::isAbstract);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
index 6f5a765..ac21dd8 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -32,8 +32,6 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
 import java.util.function.Predicate;
 
 class ClassNameMinifier {
@@ -114,14 +112,11 @@
     }
   }
 
-  ClassRenaming computeRenaming(Timing timing, ExecutorService executorService)
-      throws ExecutionException {
-    return computeRenaming(timing, executorService, Collections.emptyMap());
+  ClassRenaming computeRenaming(Timing timing) {
+    return computeRenaming(timing, Collections.emptyMap());
   }
 
-  ClassRenaming computeRenaming(
-      Timing timing, ExecutorService executorService, Map<DexType, DexString> syntheticClasses)
-      throws ExecutionException {
+  ClassRenaming computeRenaming(Timing timing, Map<DexType, DexString> syntheticClasses) {
     // Externally defined synthetic classes populate an initial renaming.
     renaming.putAll(syntheticClasses);
 
@@ -159,10 +154,6 @@
     }
     timing.end();
 
-    timing.begin("rename-arrays");
-    appView.dexItemFactory().forAllTypes(this::renameArrayTypeIfNeeded);
-    timing.end();
-
     return new ClassRenaming(Collections.unmodifiableMap(renaming), getPackageRenaming());
   }
 
@@ -359,23 +350,6 @@
     return state;
   }
 
-  private void renameArrayTypeIfNeeded(DexType type) {
-    if (type.isArrayType()) {
-      DexType base = type.toBaseType(appView.dexItemFactory());
-      DexString value = renaming.get(base);
-      if (value != null) {
-        int dimensions = type.descriptor.numberOfLeadingSquareBrackets();
-        StringBuilder builder = new StringBuilder();
-        for (int i = 0; i < dimensions; i++) {
-          builder.append('[');
-        }
-        builder.append(value.toString());
-        DexString descriptor = appView.dexItemFactory().createString(builder.toString());
-        renaming.put(type, descriptor);
-      }
-    }
-  }
-
   protected class Namespace implements InternalNamingState {
 
     private final String packageName;
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
index 98293ab..28cdcf5 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
@@ -40,7 +40,7 @@
     private final Map<MethodSignature, MemberNaming> methodMembers = Maps.newHashMap();
     private final Map<FieldSignature, MemberNaming> fieldMembers = Maps.newHashMap();
     private final Map<String, List<MappedRange>> mappedRangesByName = Maps.newHashMap();
-    private final Map<String, List<MemberNaming>> mappedNamingsByName = Maps.newHashMap();
+    private final Map<String, List<MemberNaming>> mappedFieldNamingsByName = Maps.newHashMap();
     private final Map<Signature, List<MappingInformation>> additionalMappings = Maps.newHashMap();
 
     private Builder(String renamedName, String originalName) {
@@ -54,10 +54,10 @@
         methodMembers.put(entry.getRenamedSignature().asMethodSignature(), entry);
       } else {
         fieldMembers.put(entry.getRenamedSignature().asFieldSignature(), entry);
+        mappedFieldNamingsByName
+            .computeIfAbsent(entry.getRenamedName(), m -> new ArrayList<>())
+            .add(entry);
       }
-      mappedNamingsByName
-          .computeIfAbsent(entry.getRenamedName(), m -> new ArrayList<>())
-          .add(entry);
       return this;
     }
 
@@ -119,7 +119,7 @@
           methodMembers,
           fieldMembers,
           map,
-          mappedNamingsByName,
+          mappedFieldNamingsByName,
           additionalMappings);
     }
 
@@ -249,7 +249,7 @@
   /** Map of renamed name -> MappedRangesOfName */
   public final Map<String, MappedRangesOfName> mappedRangesByRenamedName;
 
-  public final Map<String, List<MemberNaming>> mappedNamingsByName;
+  public final Map<String, List<MemberNaming>> mappedFieldNamingsByName;
 
   private final Map<Signature, List<MappingInformation>> additionalMappings;
 
@@ -259,14 +259,14 @@
       Map<MethodSignature, MemberNaming> methodMembers,
       Map<FieldSignature, MemberNaming> fieldMembers,
       Map<String, MappedRangesOfName> mappedRangesByRenamedName,
-      Map<String, List<MemberNaming>> mappedNamingsByName,
+      Map<String, List<MemberNaming>> mappedFieldNamingsByName,
       Map<Signature, List<MappingInformation>> additionalMappings) {
     this.renamedName = renamedName;
     this.originalName = originalName;
     this.methodMembers = ImmutableMap.copyOf(methodMembers);
     this.fieldMembers = ImmutableMap.copyOf(fieldMembers);
     this.mappedRangesByRenamedName = mappedRangesByRenamedName;
-    this.mappedNamingsByName = mappedNamingsByName;
+    this.mappedFieldNamingsByName = mappedFieldNamingsByName;
     this.additionalMappings = additionalMappings;
   }
 
diff --git a/src/main/java/com/android/tools/r8/naming/InterfaceMethodNameMinifier.java b/src/main/java/com/android/tools/r8/naming/InterfaceMethodNameMinifier.java
index 448a8fa..e6fcce6 100644
--- a/src/main/java/com/android/tools/r8/naming/InterfaceMethodNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/InterfaceMethodNameMinifier.java
@@ -27,7 +27,6 @@
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -362,8 +361,6 @@
   private final Equivalence<DexEncodedMethod> definitionEquivalence;
   private final MethodNameMinifier.State minifierState;
 
-  private final Map<DexCallSite, DexString> callSiteRenamings = new IdentityHashMap<>();
-
   /** A map from DexMethods to all the states linked to interfaces they appear in. */
   private final Map<Wrapper<DexEncodedMethod>, InterfaceMethodGroupState> globalStateMap =
       new HashMap<>();
@@ -396,10 +393,6 @@
     return Comparator.comparing(globalStateMap::get);
   }
 
-  Map<DexCallSite, DexString> getCallSiteRenamings() {
-    return callSiteRenamings;
-  }
-
   private void reserveNamesInInterfaces(Collection<DexClass> interfaces) {
     for (DexClass iface : interfaces) {
       assert iface.isInterface();
@@ -560,10 +553,6 @@
       } else {
         // Propagate reserved name to all states.
         groupState.reserveName(reservedName);
-        for (DexCallSite callSite : groupState.callSites) {
-          assert !callSiteRenamings.containsKey(callSite);
-          callSiteRenamings.put(callSite, reservedName);
-        }
       }
     }
     timing.end();
@@ -584,10 +573,6 @@
           print(interfaceMethodGroup.get().getReference(), sourceMethods, System.out);
         }
       }
-      for (DexCallSite callSite : groupState.callSites) {
-        assert !callSiteRenamings.containsKey(callSite);
-        callSiteRenamings.put(callSite, newName);
-      }
     }
 
     // After all naming is completed for callsites, we must ensure to rename all interface methods
diff --git a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
index 7b3e763..49dcd83 100644
--- a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.naming;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
@@ -165,16 +164,13 @@
   static class MethodRenaming {
 
     final Map<DexMethod, DexString> renaming;
-    final Map<DexCallSite, DexString> callSiteRenaming;
 
-    private MethodRenaming(
-        Map<DexMethod, DexString> renaming, Map<DexCallSite, DexString> callSiteRenaming) {
+    private MethodRenaming(Map<DexMethod, DexString> renaming) {
       this.renaming = renaming;
-      this.callSiteRenaming = callSiteRenaming;
     }
 
     public static MethodRenaming empty() {
-      return new MethodRenaming(ImmutableMap.of(), ImmutableMap.of());
+      return new MethodRenaming(ImmutableMap.of());
     }
   }
 
@@ -199,7 +195,7 @@
     assignNamesToClassesMethods(appView.dexItemFactory().objectType, rootNamingState);
     timing.end();
 
-    return new MethodRenaming(renaming, interfaceMethodNameMinifier.getCallSiteRenamings());
+    return new MethodRenaming(renaming);
   }
 
   private void assignNamesToClassesMethods(DexType type, MethodNamingState<?> parentNamingState) {
diff --git a/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java b/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
index 7773239..b7bfcdb 100644
--- a/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
+++ b/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
@@ -6,7 +6,6 @@
 
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItem;
@@ -18,6 +17,7 @@
 import com.android.tools.r8.naming.ClassNameMinifier.ClassRenaming;
 import com.android.tools.r8.naming.FieldNameMinifier.FieldRenaming;
 import com.android.tools.r8.naming.MethodNameMinifier.MethodRenaming;
+import com.android.tools.r8.naming.NamingLens.NonIdentityNamingLens;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.google.common.collect.ImmutableMap;
@@ -28,7 +28,7 @@
 import java.util.function.Function;
 import java.util.function.Predicate;
 
-class MinifiedRenaming extends NamingLens {
+class MinifiedRenaming extends NonIdentityNamingLens {
 
   final AppView<? extends AppInfoWithClassHierarchy> appView;
   private final Map<String, String> packageRenaming;
@@ -39,11 +39,11 @@
       ClassRenaming classRenaming,
       MethodRenaming methodRenaming,
       FieldRenaming fieldRenaming) {
+    super(appView.dexItemFactory());
     this.appView = appView;
     this.packageRenaming = classRenaming.packageRenaming;
     renaming.putAll(classRenaming.classRenaming);
     renaming.putAll(methodRenaming.renaming);
-    renaming.putAll(methodRenaming.callSiteRenaming);
     renaming.putAll(fieldRenaming.renaming);
   }
 
@@ -53,7 +53,7 @@
   }
 
   @Override
-  public DexString lookupDescriptor(DexType type) {
+  protected DexString internalLookupClassDescriptor(DexType type) {
     return renaming.getOrDefault(type, type.descriptor);
   }
 
@@ -119,11 +119,6 @@
   }
 
   @Override
-  public DexString lookupMethodName(DexCallSite callSite) {
-    return renaming.getOrDefault(callSite, callSite.methodName);
-  }
-
-  @Override
   public DexString lookupName(DexField field) {
     return renaming.getOrDefault(field, field.name);
   }
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java
index 3d27387..b886f2b 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -58,7 +58,7 @@
             new MinificationPackageNamingStrategy(appView),
             // Use deterministic class order to make sure renaming is deterministic.
             appView.appInfo().classesWithDeterministicOrder());
-    ClassRenaming classRenaming = classNameMinifier.computeRenaming(timing, executorService);
+    ClassRenaming classRenaming = classNameMinifier.computeRenaming(timing);
     timing.end();
 
     assert new MinifiedRenaming(
diff --git a/src/main/java/com/android/tools/r8/naming/NamingLens.java b/src/main/java/com/android/tools/r8/naming/NamingLens.java
index 3934b0f..9147b84 100644
--- a/src/main/java/com/android/tools/r8/naming/NamingLens.java
+++ b/src/main/java/com/android/tools/r8/naming/NamingLens.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.naming;
 
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -44,11 +45,38 @@
 
   public abstract DexString lookupDescriptor(DexType type);
 
+  public DexString lookupClassDescriptor(DexType type) {
+    assert type.isClassType();
+    return internalLookupClassDescriptor(type);
+  }
+
+  protected abstract DexString internalLookupClassDescriptor(DexType type);
+
   public abstract DexString lookupInnerName(InnerClassAttribute attribute, InternalOptions options);
 
   public abstract DexString lookupName(DexMethod method);
 
-  public abstract DexString lookupMethodName(DexCallSite callSite);
+  public final DexString lookupMethodName(DexCallSite callSite, AppView<?> appView) {
+    if (!appView.appInfo().hasLiveness()) {
+      return callSite.methodName;
+    }
+    Set<DexEncodedMethod> lambdaImplementedMethods =
+        appView.appInfo().withLiveness().lookupLambdaImplementedMethods(callSite);
+    if (lambdaImplementedMethods.isEmpty()) {
+      return callSite.methodName;
+    }
+    DexMethod lambdaImplementedMethodReference =
+        lambdaImplementedMethods.iterator().next().getReference();
+    DexString renamedMethodName =
+        lookupMethod(lambdaImplementedMethodReference, appView.dexItemFactory()).getName();
+    // Verify that all lambda implemented methods are renamed consistently.
+    assert lambdaImplementedMethods.stream()
+        .map(DexEncodedMethod::getReference)
+        .map(reference -> lookupMethod(reference, appView.dexItemFactory()))
+        .map(DexMethod::getName)
+        .allMatch(name -> name == renamedMethodName);
+    return renamedMethodName;
+  }
 
   public abstract DexString lookupName(DexField field);
 
@@ -95,7 +123,7 @@
       return type.replaceBaseType(newBaseType, dexItemFactory);
     }
     assert type.isClassType();
-    return dexItemFactory.createType(lookupDescriptor(type));
+    return dexItemFactory.createType(lookupClassDescriptor(type));
   }
 
   public boolean hasPrefixRewritingLogic() {
@@ -158,7 +186,34 @@
     return true;
   }
 
-  private static class IdentityLens extends NamingLens {
+  public abstract static class NonIdentityNamingLens extends NamingLens {
+
+    private final DexItemFactory dexItemFactory;
+
+    protected NonIdentityNamingLens(DexItemFactory dexItemFactory) {
+      this.dexItemFactory = dexItemFactory;
+    }
+
+    protected DexItemFactory dexItemFactory() {
+      return dexItemFactory;
+    }
+
+    @Override
+    public final DexString lookupDescriptor(DexType type) {
+      if (type.isPrimitiveType() || type.isVoidType() || type.isNullValueType()) {
+        return type.getDescriptor();
+      }
+      if (type.isArrayType()) {
+        DexType baseType = type.toBaseType(dexItemFactory);
+        DexString desc = lookupDescriptor(baseType);
+        return desc.toArrayDescriptor(type.getNumberOfLeadingSquareBrackets(), dexItemFactory);
+      }
+      assert type.isClassType();
+      return lookupClassDescriptor(type);
+    }
+  }
+
+  private static final class IdentityLens extends NamingLens {
 
     private IdentityLens() {
       // Intentionally left empty.
@@ -170,6 +225,11 @@
     }
 
     @Override
+    protected DexString internalLookupClassDescriptor(DexType type) {
+      return type.descriptor;
+    }
+
+    @Override
     public DexString lookupInnerName(InnerClassAttribute attribute, InternalOptions options) {
       return attribute.getInnerName();
     }
@@ -180,11 +240,6 @@
     }
 
     @Override
-    public DexString lookupMethodName(DexCallSite callSite) {
-      return callSite.methodName;
-    }
-
-    @Override
     public DexString lookupName(DexField field) {
       return field.name;
     }
diff --git a/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java b/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java
index 9b51f27..e987def 100644
--- a/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java
+++ b/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java
@@ -5,13 +5,13 @@
 package com.android.tools.r8.naming;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItem;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.InnerClassAttribute;
+import com.android.tools.r8.naming.NamingLens.NonIdentityNamingLens;
 import com.android.tools.r8.utils.InternalOptions;
 import java.util.Collections;
 import java.util.HashMap;
@@ -22,7 +22,7 @@
 import java.util.stream.Stream;
 
 // Naming lens for rewriting type prefixes.
-public class PrefixRewritingNamingLens extends NamingLens {
+public class PrefixRewritingNamingLens extends NonIdentityNamingLens {
 
   final NamingLens namingLens;
   final InternalOptions options;
@@ -41,6 +41,7 @@
   }
 
   public PrefixRewritingNamingLens(NamingLens namingLens, AppView<?> appView) {
+    super(appView.dexItemFactory());
     this.appView = appView;
     this.namingLens = namingLens;
     this.options = appView.options();
@@ -69,7 +70,7 @@
   }
 
   @Override
-  public DexString lookupDescriptor(DexType type) {
+  protected DexString internalLookupClassDescriptor(DexType type) {
     DexString renaming = getRenaming(type);
     return renaming != null ? renaming : namingLens.lookupDescriptor(type);
   }
@@ -93,16 +94,6 @@
   }
 
   @Override
-  public DexString lookupMethodName(DexCallSite callSite) {
-    if (callSite.bootstrapMethod.rewrittenTarget != null
-        && isRenamed(callSite.bootstrapMethod.rewrittenTarget.holder)) {
-      // Prefix rewriting does not influence the inner name.
-      return callSite.methodName;
-    }
-    return namingLens.lookupMethodName(callSite);
-  }
-
-  @Override
   public DexString lookupName(DexField field) {
     if (isRenamed(field.holder)) {
       // Prefix rewriting does not influence the field name.
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
index a29f8ef..fab1147 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -143,7 +143,7 @@
             new MinificationPackageNamingStrategy(appView),
             mappedClasses);
     ClassRenaming classRenaming =
-        classNameMinifier.computeRenaming(timing, executorService, syntheticCompanionClasses);
+        classNameMinifier.computeRenaming(timing, syntheticCompanionClasses);
     timing.end();
 
     ApplyMappingMemberNamingStrategy nameStrategy =
@@ -578,9 +578,9 @@
     }
 
     @Override
-    public DexString lookupDescriptor(DexType type) {
+    protected DexString internalLookupClassDescriptor(DexType type) {
       checkForUseOfNotMappedReference(type);
-      return super.lookupDescriptor(type);
+      return super.internalLookupClassDescriptor(type);
     }
 
     private void checkForUseOfNotMappedReference(DexType type) {
diff --git a/src/main/java/com/android/tools/r8/relocator/SimplePackagesRewritingMapper.java b/src/main/java/com/android/tools/r8/relocator/SimplePackagesRewritingMapper.java
index 396d837..09ca5bd 100644
--- a/src/main/java/com/android/tools/r8/relocator/SimplePackagesRewritingMapper.java
+++ b/src/main/java/com/android/tools/r8/relocator/SimplePackagesRewritingMapper.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.relocator;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItem;
@@ -16,6 +15,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.naming.NamingLens.NonIdentityNamingLens;
 import com.android.tools.r8.references.PackageReference;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions;
@@ -96,23 +96,18 @@
     return new RelocatorNamingLens(typeMappings, packingMappings.build(), appView.dexItemFactory());
   }
 
-  Map<DexType, DexString> getTypeMappings() {
-    return typeMappings;
-  }
-
-  private static class RelocatorNamingLens extends NamingLens {
+  private static class RelocatorNamingLens extends NonIdentityNamingLens {
 
     private final Map<DexType, DexString> typeMappings;
     private final Map<String, String> packageMappings;
-    private final DexItemFactory factory;
 
     private RelocatorNamingLens(
         Map<DexType, DexString> typeMappings,
         Map<String, String> packageMappings,
         DexItemFactory factory) {
+      super(factory);
       this.typeMappings = typeMappings;
       this.packageMappings = packageMappings;
-      this.factory = factory;
     }
 
     @Override
@@ -121,20 +116,7 @@
     }
 
     @Override
-    public DexString lookupDescriptor(DexType type) {
-      if (type.isPrimitiveType() || type.isVoidType()) {
-        return type.descriptor;
-      }
-      if (type.isArrayType()) {
-        DexType baseType = type.toBaseType(factory);
-        if (baseType == null || baseType.isPrimitiveType()) {
-          return type.descriptor;
-        }
-        String baseDescriptor = typeMappings.getOrDefault(baseType, baseType.descriptor).toString();
-        return factory.createString(
-            DescriptorUtils.toArrayDescriptor(
-                type.getNumberOfLeadingSquareBrackets(), baseDescriptor));
-      }
+    protected DexString internalLookupClassDescriptor(DexType type) {
       return typeMappings.getOrDefault(type, type.descriptor);
     }
 
@@ -149,11 +131,6 @@
     }
 
     @Override
-    public DexString lookupMethodName(DexCallSite callSite) {
-      return callSite.methodName;
-    }
-
-    @Override
     public DexString lookupName(DexField field) {
       return field.name;
     }
diff --git a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
index 5868aa8..95ee828 100644
--- a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
+++ b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.repackaging;
 
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+import static com.android.tools.r8.utils.DescriptorUtils.DESCRIPTOR_PACKAGE_SEPARATOR;
 import static com.android.tools.r8.utils.DescriptorUtils.INNER_CLASS_SEPARATOR;
 
 import com.android.tools.r8.graph.AppView;
@@ -18,7 +19,7 @@
 import com.android.tools.r8.graph.SortedProgramPackageCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.ProguardConfiguration;
-import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.BiMap;
 import com.google.common.collect.HashBiMap;
@@ -43,13 +44,14 @@
 public class Repackaging {
 
   private final AppView<AppInfoWithLiveness> appView;
-  private final DexItemFactory dexItemFactory;
   private final ProguardConfiguration proguardConfiguration;
+  private final RepackagingConfiguration repackagingConfiguration;
 
   public Repackaging(AppView<AppInfoWithLiveness> appView) {
     this.appView = appView;
-    this.dexItemFactory = appView.dexItemFactory();
     this.proguardConfiguration = appView.options().getProguardConfiguration();
+    this.repackagingConfiguration =
+        appView.options().testing.repackagingConfigurationFactory.apply(appView);
   }
 
   public RepackagingLens run(
@@ -90,10 +92,16 @@
     Iterator<ProgramPackage> iterator = packages.iterator();
     while (iterator.hasNext()) {
       ProgramPackage pkg = iterator.next();
-      String newPackageDescriptor = getNewPackageDescriptor(pkg, seenPackageDescriptors);
+      String newPackageDescriptor =
+          repackagingConfiguration.getNewPackageDescriptor(pkg, seenPackageDescriptors);
       if (pkg.getPackageDescriptor().equals(newPackageDescriptor)) {
         for (DexProgramClass alreadyRepackagedClass : pkg) {
-          mappings.put(alreadyRepackagedClass.getType(), alreadyRepackagedClass.getType());
+          if (!appView.appInfo().isRepackagingAllowed(alreadyRepackagedClass.getType())) {
+            mappings.put(alreadyRepackagedClass.getType(), alreadyRepackagedClass.getType());
+          }
+        }
+        for (DexProgramClass alreadyRepackagedClass : pkg) {
+          processClass(alreadyRepackagedClass, pkg, newPackageDescriptor, mappings);
         }
         seenPackageDescriptors.add(newPackageDescriptor);
         iterator.remove();
@@ -111,7 +119,8 @@
     // desired package.
     for (ProgramPackage pkg : packages) {
       // Already processed packages should have been removed.
-      String newPackageDescriptor = getNewPackageDescriptor(pkg, seenPackageDescriptors);
+      String newPackageDescriptor =
+          repackagingConfiguration.getNewPackageDescriptor(pkg, seenPackageDescriptors);
       assert !pkg.getPackageDescriptor().equals(newPackageDescriptor);
 
       Iterable<DexProgramClass> classesToRepackage =
@@ -151,7 +160,8 @@
     }
     mappings.put(
         classToRepackage.getType(),
-        getRepackagedType(classToRepackage, outerClass, newPackageDescriptor, mappings));
+        repackagingConfiguration.getRepackagedType(
+            classToRepackage, outerClass, newPackageDescriptor, mappings));
   }
 
   private Iterable<DexProgramClass> computeClassesToRepackage(
@@ -165,46 +175,129 @@
     return constraintGraph.computeClassesToRepackage();
   }
 
-  private String getNewPackageDescriptor(ProgramPackage pkg, Set<String> seenPackageDescriptors) {
-    String newPackageDescriptor =
-        StringUtils.replaceAll(proguardConfiguration.getPackagePrefix(), ".", "/");
-    if (proguardConfiguration.getPackageObfuscationMode().isRepackageClasses()) {
-      return newPackageDescriptor;
-    }
-    if (!newPackageDescriptor.isEmpty()) {
-      newPackageDescriptor += "/";
-    }
-    newPackageDescriptor += pkg.getLastPackageName();
-    String finalPackageDescriptor = newPackageDescriptor;
-    for (int i = 1; seenPackageDescriptors.contains(finalPackageDescriptor); i++) {
-      finalPackageDescriptor = newPackageDescriptor + INNER_CLASS_SEPARATOR + i;
-    }
-    return finalPackageDescriptor;
+  public interface RepackagingConfiguration {
+
+    String getNewPackageDescriptor(ProgramPackage pkg, Set<String> seenPackageDescriptors);
+
+    DexType getRepackagedType(
+        DexProgramClass clazz,
+        DexProgramClass outerClass,
+        String newPackageDescriptor,
+        BiMap<DexType, DexType> mappings);
   }
 
-  private DexType getRepackagedType(
-      DexProgramClass clazz,
-      DexProgramClass outerClass,
-      String newPackageDescriptor,
-      BiMap<DexType, DexType> mappings) {
-    DexType repackagedDexType =
-        clazz.getType().replacePackage(newPackageDescriptor, dexItemFactory);
-    if (outerClass != null) {
-      String simpleName = clazz.getType().getSimpleName();
-      String outerClassSimpleName = outerClass.getType().getSimpleName();
-      if (simpleName.startsWith(outerClassSimpleName + INNER_CLASS_SEPARATOR)) {
-        String newSimpleName =
-            mappings.get(outerClass.getType()).getSimpleName()
-                + simpleName.substring(outerClassSimpleName.length());
-        repackagedDexType = repackagedDexType.withSimpleName(newSimpleName, dexItemFactory);
+  public static class DefaultRepackagingConfiguration implements RepackagingConfiguration {
+
+    private final DexItemFactory dexItemFactory;
+    private final ProguardConfiguration proguardConfiguration;
+
+    public DefaultRepackagingConfiguration(
+        DexItemFactory dexItemFactory, ProguardConfiguration proguardConfiguration) {
+      this.dexItemFactory = dexItemFactory;
+      this.proguardConfiguration = proguardConfiguration;
+    }
+
+    @Override
+    public String getNewPackageDescriptor(ProgramPackage pkg, Set<String> seenPackageDescriptors) {
+      String newPackageDescriptor =
+          DescriptorUtils.getBinaryNameFromJavaType(proguardConfiguration.getPackagePrefix());
+      if (proguardConfiguration.getPackageObfuscationMode().isRepackageClasses()) {
+        return newPackageDescriptor;
       }
+      if (!newPackageDescriptor.isEmpty()) {
+        newPackageDescriptor += DESCRIPTOR_PACKAGE_SEPARATOR;
+      }
+      newPackageDescriptor += pkg.getLastPackageName();
+      String finalPackageDescriptor = newPackageDescriptor;
+      for (int i = 1; seenPackageDescriptors.contains(finalPackageDescriptor); i++) {
+        finalPackageDescriptor = newPackageDescriptor + INNER_CLASS_SEPARATOR + i;
+      }
+      return finalPackageDescriptor;
     }
-    DexType finalRepackagedDexType = repackagedDexType;
-    for (int i = 1; mappings.inverse().containsKey(finalRepackagedDexType); i++) {
-      finalRepackagedDexType =
-          repackagedDexType.addSuffix(
-              Character.toString(INNER_CLASS_SEPARATOR) + i, dexItemFactory);
+
+    @Override
+    public DexType getRepackagedType(
+        DexProgramClass clazz,
+        DexProgramClass outerClass,
+        String newPackageDescriptor,
+        BiMap<DexType, DexType> mappings) {
+      DexType repackagedDexType =
+          clazz.getType().replacePackage(newPackageDescriptor, dexItemFactory);
+      // Rename the class consistently with its outer class.
+      if (outerClass != null) {
+        String simpleName = clazz.getType().getSimpleName();
+        String outerClassSimpleName = outerClass.getType().getSimpleName();
+        if (simpleName.startsWith(outerClassSimpleName + INNER_CLASS_SEPARATOR)) {
+          String newSimpleName =
+              mappings.get(outerClass.getType()).getSimpleName()
+                  + simpleName.substring(outerClassSimpleName.length());
+          repackagedDexType = repackagedDexType.withSimpleName(newSimpleName, dexItemFactory);
+        } else {
+          assert false
+              : "Unexpected name for inner class: "
+                  + clazz.getType().toSourceString()
+                  + " (outer class: "
+                  + outerClass.getType().toSourceString()
+                  + ")";
+        }
+      }
+      // Ensure that the generated name is unique.
+      DexType finalRepackagedDexType = repackagedDexType;
+      for (int i = 1; mappings.inverse().containsKey(finalRepackagedDexType); i++) {
+        finalRepackagedDexType =
+            repackagedDexType.addSuffix(
+                Character.toString(INNER_CLASS_SEPARATOR) + i, dexItemFactory);
+      }
+      return finalRepackagedDexType;
     }
-    return finalRepackagedDexType;
+  }
+
+  /** Testing only. */
+  public static class SuffixRenamingRepackagingConfiguration implements RepackagingConfiguration {
+
+    private final String classNameSuffix;
+    private final DexItemFactory dexItemFactory;
+
+    public SuffixRenamingRepackagingConfiguration(
+        String classNameSuffix, DexItemFactory dexItemFactory) {
+      this.classNameSuffix = classNameSuffix;
+      this.dexItemFactory = dexItemFactory;
+    }
+
+    @Override
+    public String getNewPackageDescriptor(ProgramPackage pkg, Set<String> seenPackageDescriptors) {
+      // Don't change the package of classes.
+      return pkg.getPackageDescriptor();
+    }
+
+    @Override
+    public DexType getRepackagedType(
+        DexProgramClass clazz,
+        DexProgramClass outerClass,
+        String newPackageDescriptor,
+        BiMap<DexType, DexType> mappings) {
+      DexType repackagedDexType = clazz.getType();
+      // Rename the class consistently with its outer class.
+      if (outerClass != null) {
+        String simpleName = clazz.getType().getSimpleName();
+        String outerClassSimpleName = outerClass.getType().getSimpleName();
+        if (simpleName.startsWith(outerClassSimpleName + INNER_CLASS_SEPARATOR)) {
+          String newSimpleName =
+              mappings.get(outerClass.getType()).getSimpleName()
+                  + simpleName.substring(outerClassSimpleName.length());
+          repackagedDexType = repackagedDexType.withSimpleName(newSimpleName, dexItemFactory);
+        }
+      }
+      // Append the class name suffix to all classes.
+      repackagedDexType = repackagedDexType.addSuffix(classNameSuffix, dexItemFactory);
+      // Ensure that the generated name is unique.
+      DexType finalRepackagedDexType = repackagedDexType;
+      for (int i = 1; mappings.inverse().containsKey(finalRepackagedDexType); i++) {
+        finalRepackagedDexType =
+            repackagedDexType.addSuffix(
+                Character.toString(INNER_CLASS_SEPARATOR) + i, dexItemFactory);
+      }
+      return finalRepackagedDexType;
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
index 4ca10b6..945aa0f 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
@@ -44,7 +44,7 @@
     return lookup(
         fieldName,
         (mapper, name) -> {
-          List<MemberNaming> memberNamings = mapper.mappedNamingsByName.get(name);
+          List<MemberNaming> memberNamings = mapper.mappedFieldNamingsByName.get(name);
           if (memberNamings == null || memberNamings.isEmpty()) {
             return null;
           }
@@ -163,7 +163,7 @@
       return lookup(
           fieldName,
           (mapper, name) -> {
-            List<MemberNaming> memberNamings = mapper.mappedNamingsByName.get(name);
+            List<MemberNaming> memberNamings = mapper.mappedFieldNamingsByName.get(name);
             if (memberNamings == null || memberNamings.isEmpty()) {
               return null;
             }
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 15183a1..af11559 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -43,6 +43,8 @@
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.Position;
 import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.repackaging.Repackaging.DefaultRepackagingConfiguration;
+import com.android.tools.r8.repackaging.Repackaging.RepackagingConfiguration;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.Enqueuer;
 import com.android.tools.r8.shaking.GlobalKeepInfoConfiguration;
@@ -75,6 +77,7 @@
 import java.util.function.BiConsumer;
 import java.util.function.BiPredicate;
 import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.function.Predicate;
 import org.objectweb.asm.Opcodes;
 
@@ -1213,6 +1216,12 @@
 
     public BiConsumer<ProgramMethod, MethodProcessingId> methodProcessingIdConsumer = null;
 
+    public Function<AppView<AppInfoWithLiveness>, RepackagingConfiguration>
+        repackagingConfigurationFactory =
+            appView ->
+                new DefaultRepackagingConfiguration(
+                    appView.dexItemFactory(), appView.options().getProguardConfiguration());
+
     public Consumer<Deque<SortedProgramMethodSet>> waveModifier = waves -> {};
 
     /**
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index 17c2fd2..2272f50 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -303,7 +303,8 @@
       addClassToClassNaming(originalType, renamedClassName, onDemandClassNamingBuilder);
 
       // First transfer renamed fields to classNamingBuilder.
-      addFieldsToClassNaming(appView.graphLens(), namingLens, clazz, onDemandClassNamingBuilder);
+      addFieldsToClassNaming(
+          appView.graphLens(), namingLens, clazz, originalType, onDemandClassNamingBuilder);
 
       // Then process the methods, ordered by renamed name.
       List<DexString> renamedMethodNames = new ArrayList<>(methodsByRenamedName.keySet());
@@ -358,7 +359,7 @@
 
           DexMethod originalMethod = appView.graphLens().getOriginalMethodSignature(method.method);
           MethodSignature originalSignature =
-              MethodSignature.fromDexMethod(originalMethod, originalMethod.holder != clazz.type);
+              MethodSignature.fromDexMethod(originalMethod, originalMethod.holder != originalType);
 
           DexString obfuscatedNameDexString = namingLens.lookupName(method.method);
           String obfuscatedName = obfuscatedNameDexString.toString();
@@ -367,7 +368,7 @@
           if (mappedPositions.isEmpty()) {
             // But only if it's been renamed.
             if (obfuscatedNameDexString != originalMethod.name
-                || originalMethod.holder != clazz.type) {
+                || originalMethod.holder != originalType) {
               onDemandClassNamingBuilder
                   .get()
                   .addMappedRange(null, originalSignature, null, obfuscatedName);
@@ -539,15 +540,16 @@
       GraphLens graphLens,
       NamingLens namingLens,
       DexProgramClass clazz,
+      DexType originalType,
       Supplier<Builder> onDemandClassNamingBuilder) {
     clazz.forEachField(
         dexEncodedField -> {
           DexField dexField = dexEncodedField.field;
           DexField originalField = graphLens.getOriginalFieldSignature(dexField);
           DexString renamedName = namingLens.lookupName(dexField);
-          if (renamedName != originalField.name || originalField.holder != clazz.type) {
+          if (renamedName != originalField.name || originalField.holder != originalType) {
             FieldSignature originalSignature =
-                FieldSignature.fromDexField(originalField, originalField.holder != clazz.type);
+                FieldSignature.fromDexField(originalField, originalField.holder != originalType);
             MemberNaming memberNaming = new MemberNaming(originalSignature, renamedName.toString());
             onDemandClassNamingBuilder.get().addMemberEntry(memberNaming);
           }
diff --git a/src/test/java/com/android/tools/r8/D8TestBuilder.java b/src/test/java/com/android/tools/r8/D8TestBuilder.java
index 1496847..44fe743 100644
--- a/src/test/java/com/android/tools/r8/D8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/D8TestBuilder.java
@@ -64,7 +64,7 @@
       Builder builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
       throws CompilationFailedException {
     ToolHelper.runD8(builder, optionsConsumer);
-    return new D8TestCompileResult(getState(), app.get(), getOutputMode());
+    return new D8TestCompileResult(getState(), app.get(), minApiLevel, getOutputMode());
   }
 
   public D8TestBuilder setIntermediate(boolean intermediate) {
diff --git a/src/test/java/com/android/tools/r8/D8TestCompileResult.java b/src/test/java/com/android/tools/r8/D8TestCompileResult.java
index 8b91d57..ea8ff8b 100644
--- a/src/test/java/com/android/tools/r8/D8TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/D8TestCompileResult.java
@@ -4,11 +4,13 @@
 package com.android.tools.r8;
 
 import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 
 public class D8TestCompileResult extends TestCompileResult<D8TestCompileResult, D8TestRunResult> {
-  D8TestCompileResult(TestState state, AndroidApp app, OutputMode outputMode) {
-    super(state, app, outputMode);
+  D8TestCompileResult(
+      TestState state, AndroidApp app, AndroidApiLevel minApiLevel, OutputMode outputMode) {
+    super(state, app, minApiLevel, outputMode);
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/DXTestBuilder.java b/src/test/java/com/android/tools/r8/DXTestBuilder.java
index 9e26ecd..49055a1 100644
--- a/src/test/java/com/android/tools/r8/DXTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/DXTestBuilder.java
@@ -29,8 +29,6 @@
   // Ordered list of injar entries.
   private List<Path> injars = new ArrayList<>();
 
-  private int minApiLevel = -1;
-
   private DXTestBuilder(TestState state) {
     super(state, D8Command.builder(), Backend.DEX);
   }
@@ -53,9 +51,7 @@
       Path outJar = dxOutputFolder.resolve("output.jar");
 
       List<String> args = new ArrayList<>();
-      if (minApiLevel >= 0) {
-        args.add("--min-sdk-version=" + minApiLevel);
-      }
+      args.add("--min-sdk-version=" + minApiLevel.getLevel());
       args.add("--output=" + outJar.toString());
       args.addAll(injars.stream().map(Path::toString).collect(Collectors.toList()));
       ProcessResult result =
@@ -66,7 +62,7 @@
         throw new CompilationFailedException(result.toString());
       }
       return new DXTestCompileResult(
-          getState(), AndroidApp.builder().addProgramFile(outJar).build());
+          getState(), AndroidApp.builder().addProgramFile(outJar).build(), minApiLevel);
     } catch (IOException e) {
       throw new CompilationFailedException(e);
     }
@@ -123,10 +119,4 @@
     injars.addAll(files);
     return self();
   }
-
-  @Override
-  public DXTestBuilder setMinApi(int minApiLevel) {
-    this.minApiLevel = minApiLevel;
-    return self();
-  }
 }
diff --git a/src/test/java/com/android/tools/r8/DXTestCompileResult.java b/src/test/java/com/android/tools/r8/DXTestCompileResult.java
index e362f78..9cb6482 100644
--- a/src/test/java/com/android/tools/r8/DXTestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/DXTestCompileResult.java
@@ -5,12 +5,13 @@
 
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 
 public class DXTestCompileResult extends TestCompileResult<DXTestCompileResult, DXTestRunResult> {
 
-  DXTestCompileResult(TestState state, AndroidApp app) {
-    super(state, app, OutputMode.DexIndexed);
+  DXTestCompileResult(TestState state, AndroidApp app, AndroidApiLevel minApiLevel) {
+    super(state, app, minApiLevel, OutputMode.DexIndexed);
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java b/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
index 08ce5be..b6fe80d 100644
--- a/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
@@ -142,7 +142,7 @@
               ? FileUtils.readTextFile(proguardMapFile, Charsets.UTF_8)
               : "";
       return new ExternalR8TestCompileResult(
-          getState(), outputJar, processResult, proguardMap, getOutputMode());
+          getState(), outputJar, processResult, proguardMap, minApiLevel, getOutputMode());
     } catch (IOException e) {
       throw new CompilationFailedException(e);
     }
diff --git a/src/test/java/com/android/tools/r8/ExternalR8TestCompileResult.java b/src/test/java/com/android/tools/r8/ExternalR8TestCompileResult.java
index 75cd5526..73fe9b4 100644
--- a/src/test/java/com/android/tools/r8/ExternalR8TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/ExternalR8TestCompileResult.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import java.io.IOException;
@@ -24,8 +25,9 @@
       Path outputJar,
       ProcessResult processResult,
       String proguardMap,
+      AndroidApiLevel minApiLevel,
       OutputMode outputMode) {
-    super(state, AndroidApp.builder().addProgramFiles(outputJar).build(), outputMode);
+    super(state, AndroidApp.builder().addProgramFiles(outputJar).build(), minApiLevel, outputMode);
     assert processResult.exitCode == 0;
     this.outputJar = outputJar;
     this.processResult = processResult;
diff --git a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
index ba1d485..27d4655 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
@@ -106,7 +106,7 @@
       }
       String proguardMap =
           Files.exists(mapFile) ? FileUtils.readTextFile(mapFile, Charsets.UTF_8) : "";
-      return new ProguardTestCompileResult(getState(), outJar, proguardMap);
+      return new ProguardTestCompileResult(getState(), outJar, minApiLevel, proguardMap);
     } catch (IOException e) {
       throw new CompilationFailedException(e);
     }
diff --git a/src/test/java/com/android/tools/r8/ProguardTestCompileResult.java b/src/test/java/com/android/tools/r8/ProguardTestCompileResult.java
index dbb3c6e..b51c598 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestCompileResult.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import java.io.IOException;
@@ -17,8 +18,13 @@
   private final Path outputJar;
   private final String proguardMap;
 
-  ProguardTestCompileResult(TestState state, Path outputJar, String proguardMap) {
-    super(state, AndroidApp.builder().addProgramFiles(outputJar).build(), OutputMode.ClassFile);
+  ProguardTestCompileResult(
+      TestState state, Path outputJar, AndroidApiLevel minApiLevel, String proguardMap) {
+    super(
+        state,
+        AndroidApp.builder().addProgramFiles(outputJar).build(),
+        minApiLevel,
+        OutputMode.ClassFile);
     this.outputJar = outputJar;
     this.proguardMap = proguardMap;
   }
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
index 7c68c50..5e2f078 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
@@ -143,7 +143,9 @@
   @Test
   @IgnoreIfVmOlderThan(Version.V7_0_0)
   public void lambdaDesugaringWithDefaultMethods() throws Throwable {
+    // This should be fixed by horizontal class merging field mapping.
     expectThrowsWithHorizontalClassMerging();
+
     test("lambdadesugaring", "lambdadesugaring", "LambdaDesugaring")
         .withMinApiLevel(AndroidApiLevel.N)
         .withOptionConsumer(opts -> opts.enableClassInlining = false)
@@ -189,7 +191,6 @@
   @Test
   @IgnoreIfVmOlderThan(Version.V7_0_0)
   public void lambdaDesugaringNPlusWithDefaultMethods() throws Throwable {
-    expectThrowsWithHorizontalClassMerging();
     test("lambdadesugaringnplus", "lambdadesugaringnplus", "LambdasWithStaticAndDefaultMethods")
         .withMinApiLevel(AndroidApiLevel.N)
         .withInterfaceMethodDesugaring(OffOrAuto.Auto)
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 86776a3..1ad8f28 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -150,7 +150,7 @@
             box.syntheticProguardRules,
             proguardMapBuilder.toString(),
             graphConsumer,
-            builder.getMinApiLevel(),
+            minApiLevel,
             features);
     switch (allowedDiagnosticMessages) {
       case ALL:
diff --git a/src/test/java/com/android/tools/r8/R8TestCompileResult.java b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
index c2a1dac..0deb4f5 100644
--- a/src/test/java/com/android/tools/r8/R8TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.shaking.CollectingGraphConsumer;
 import com.android.tools.r8.shaking.ProguardConfiguration;
 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.FileUtils;
 import com.android.tools.r8.utils.ThrowingConsumer;
@@ -29,7 +30,6 @@
   private final List<ProguardConfigurationRule> syntheticProguardRules;
   private final String proguardMap;
   private final CollectingGraphConsumer graphConsumer;
-  private final int minApiLevel;
   private final List<Path> features;
 
   R8TestCompileResult(
@@ -40,14 +40,13 @@
       List<ProguardConfigurationRule> syntheticProguardRules,
       String proguardMap,
       CollectingGraphConsumer graphConsumer,
-      int minApiLevel,
+      AndroidApiLevel minApiLevel,
       List<Path> features) {
-    super(state, app, outputMode);
+    super(state, app, minApiLevel, outputMode);
     this.proguardConfiguration = proguardConfiguration;
     this.syntheticProguardRules = syntheticProguardRules;
     this.proguardMap = proguardMap;
     this.graphConsumer = graphConsumer;
-    this.minApiLevel = minApiLevel;
     this.features = features;
   }
 
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index c3c51de..d7bebd8 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -133,6 +133,10 @@
     CF,
     DEX;
 
+    public boolean isDex() {
+      return this == DEX;
+    }
+
     public static Backend fromConsumer(ProgramConsumer consumer) {
       return consumer instanceof ClassFileConsumer ? CF : DEX;
     }
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index 3294828..7dfe4b5 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -5,6 +5,7 @@
 
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
 import static com.android.tools.r8.TestBase.Backend.DEX;
+import static com.android.tools.r8.TestBase.testForD8;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -48,15 +49,18 @@
     extends TestBaseResult<CR, RR> {
 
   public final AndroidApp app;
+  public final AndroidApiLevel minApiLevel;
   private final OutputMode outputMode;
   final List<Path> additionalRunClassPath = new ArrayList<>();
   final List<String> vmArguments = new ArrayList<>();
   private boolean withArt6Plus64BitsLib = false;
   private boolean withArtFrameworks = true;
 
-  TestCompileResult(TestState state, AndroidApp app, OutputMode outputMode) {
+  TestCompileResult(
+      TestState state, AndroidApp app, AndroidApiLevel minApiLevel, OutputMode outputMode) {
     super(state);
     this.app = app;
+    this.minApiLevel = minApiLevel;
     this.outputMode = outputMode;
   }
 
@@ -167,11 +171,19 @@
     return self();
   }
 
-  public CR addRunClasspathClasses(Class<?>... classpath) {
+  public CR addRunClasspathClasses(Class<?>... classpath) throws Exception {
     return addRunClasspathClasses(Arrays.asList(classpath));
   }
 
-  public CR addRunClasspathClasses(List<Class<?>> classpath) {
+  public CR addRunClasspathClasses(List<Class<?>> classpath) throws Exception {
+    if (getBackend() == Backend.DEX) {
+      return addRunClasspathFiles(
+          testForD8(state.getTempFolder())
+              .addProgramClasses(classpath)
+              .setMinApi(minApiLevel)
+              .compile()
+              .writeToZip());
+    }
     assert getBackend() == Backend.CF;
     try {
       Path path = state.getNewTempFolder().resolve("runtime-classes.jar");
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index 43b5478..590f10a 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -53,7 +53,7 @@
   private final List<Path> additionalRunClassPath = new ArrayList<>();
   private ProgramConsumer programConsumer;
   private StringConsumer mainDexListConsumer;
-  private AndroidApiLevel defaultMinApiLevel = ToolHelper.getMinApiLevelForDexVm();
+  protected AndroidApiLevel minApiLevel = ToolHelper.getMinApiLevelForDexVm();
   private Consumer<InternalOptions> optionsConsumer = DEFAULT_OPTIONS;
   private ByteArrayOutputStream stdout = null;
   private PrintStream oldStdout = null;
@@ -63,6 +63,10 @@
 
   private boolean isAndroidBuildVersionAdded = false;
 
+  public boolean isTestShrinkerBuilder() {
+    return false;
+  }
+
   public T addAndroidBuildVersion() {
     addProgramClasses(AndroidBuildVersion.class);
     isAndroidBuildVersionAdded = true;
@@ -103,13 +107,14 @@
     AndroidAppConsumers sink = new AndroidAppConsumers();
     builder.setProgramConsumer(sink.wrapProgramConsumer(programConsumer));
     builder.setMainDexListConsumer(mainDexListConsumer);
-    if (backend == Backend.DEX && defaultMinApiLevel != null) {
+    if (backend.isDex() || !isTestShrinkerBuilder()) {
       assert !builder.isMinApiLevelSet()
           : "Don't set the API level directly through BaseCompilerCommand.Builder in tests";
-      builder.setMinApiLevel(defaultMinApiLevel.getLevel());
+      builder.setMinApiLevel(minApiLevel.getLevel());
     }
     if (useDefaultRuntimeLibrary) {
-      if (backend == Backend.DEX && builder.isMinApiLevelSet()) {
+      if (backend == Backend.DEX) {
+        assert builder.isMinApiLevelSet();
         builder.addLibraryFiles(
             ToolHelper.getFirstSupportedAndroidJar(
                 AndroidApiLevel.getAndroidApiLevel(builder.getMinApiLevel())));
@@ -233,11 +238,7 @@
   }
 
   public T setMinApi(int minApiLevel) {
-    assert builder.getMinApiLevel() > 0 || this.defaultMinApiLevel != null
-        : "Tests must use this method to set min API level, and not"
-            + " BaseCompilerCommand.Builder.setMinApiLevel()";
-    this.defaultMinApiLevel = null;
-    builder.setMinApiLevel(minApiLevel);
+    this.minApiLevel = AndroidApiLevel.getAndroidApiLevel(minApiLevel);
     return self();
   }
 
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index 69a42a4..6d3590d 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -35,17 +35,14 @@
   }
 
   @Override
-  public T setMinApi(AndroidApiLevel minApiLevel) {
-    if (backend == Backend.DEX) {
-      return super.setMinApi(minApiLevel.getLevel());
-    }
-    return self();
+  public boolean isTestShrinkerBuilder() {
+    return true;
   }
 
   @Override
-  public T setMinApi(int minApiLevel) {
+  public T setMinApi(AndroidApiLevel minApiLevel) {
     if (backend == Backend.DEX) {
-      return super.setMinApi(minApiLevel);
+      return super.setMinApi(minApiLevel.getLevel());
     }
     return self();
   }
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/BridgeHoistingAccessibilityTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/BridgeHoistingAccessibilityTest.java
index fc125dc..c9f7d21 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/BridgeHoistingAccessibilityTest.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/BridgeHoistingAccessibilityTest.java
@@ -38,7 +38,6 @@
 
   @Test
   public void test() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     testForR8(parameters.getBackend())
         .addProgramClasses(TestClass.class)
         .addInnerClasses(BridgeHoistingAccessibilityTestClasses.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NoAbstractClassesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoAbstractClassesTest.java
new file mode 100644
index 0000000..039a65b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoAbstractClassesTest.java
@@ -0,0 +1,94 @@
+// Copyright (c) 2020, 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.classmerging.horizontal;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.TestParameters;
+import org.junit.Test;
+
+public class NoAbstractClassesTest extends HorizontalClassMergingTestBase {
+  public NoAbstractClassesTest(TestParameters parameters, boolean enableHorizontalClassMerging) {
+    super(parameters, enableHorizontalClassMerging);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
+        .addOptionsModification(
+            options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+        .enableInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
+        .enableNoVerticalClassMergingAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("bar", "foo c", "foo d", "foo c")
+        .inspect(
+            codeInspector -> {
+              assertThat(codeInspector.clazz(A.class), isPresent());
+              assertThat(codeInspector.clazz(B.class), isPresent());
+              assertThat(codeInspector.clazz(C.class), isPresent());
+              assertThat(
+                  codeInspector.clazz(D.class), notIf(isPresent(), enableHorizontalClassMerging));
+            });
+  }
+
+  @NoVerticalClassMerging
+  public abstract static class A {
+    public abstract void foo();
+  }
+
+  @NeverClassInline
+  public static class B {
+    @NeverInline
+    public void bar() {
+      System.out.println("bar");
+    }
+  }
+
+  @NeverClassInline
+  public static class C extends A {
+
+    @Override
+    @NeverInline
+    public void foo() {
+      System.out.println("foo c");
+    }
+  }
+
+  @NeverClassInline
+  public static class D extends A {
+
+    @Override
+    @NeverInline
+    public void foo() {
+      System.out.println("foo d");
+    }
+  }
+
+  public static class Main {
+    @NeverInline
+    public static void foo(A a) {
+      a.foo();
+    }
+
+    public static void main(String[] args) {
+      new B().bar();
+      C c = new C();
+
+      // This test also checks that the synthesized C#foo does not try to call the abstract A#foo.
+      foo(c);
+      foo(new D());
+      c.foo();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/StaticClassMergerVisibilityTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/StaticClassMergerVisibilityTest.java
index 937953a..9d545e5 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/StaticClassMergerVisibilityTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/StaticClassMergerVisibilityTest.java
@@ -37,7 +37,6 @@
 
   @Test
   public void testStaticClassIsRemoved() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     CodeInspector inspector =
         testForR8(parameters.getBackend())
             .addInnerClasses(StaticClassMergerVisibilityTest.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/IncorrectRewritingOfInvokeSuperTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/IncorrectRewritingOfInvokeSuperTest.java
index 156836d..505aa07 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/IncorrectRewritingOfInvokeSuperTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/IncorrectRewritingOfInvokeSuperTest.java
@@ -30,7 +30,6 @@
 
   @Test
   public void test() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     testForR8(parameters.getBackend())
         .addInnerClasses(IncorrectRewritingOfInvokeSuperTest.class)
         .addKeepMainRule(TestClass.class)
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 4c5d998..e831c02 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
@@ -411,7 +411,6 @@
 
   @Test
   public void testMethodCollision() throws Throwable {
-    expectThrowsWithHorizontalClassMerging();
     String main = "classmerging.MethodCollisionTest";
     Path[] programFiles =
         new Path[] {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassTest.java
index 0fcb214..a01a59a 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassTest.java
@@ -44,8 +44,6 @@
 
   @Test
   public void testCustomCollectionD8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     Assume.assumeTrue(parameters.getRuntime().isDex());
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
@@ -103,8 +101,6 @@
   @Test
   public void testCustomCollectionR8() throws Exception {
     Assume.assumeTrue(parameters.getRuntime().isDex());
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(Backend.DEX)
         .addInnerClasses(ConcurrentHashMapSubclassTest.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionInterfaceSuperTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionInterfaceSuperTest.java
index 111ad12..4bd591e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionInterfaceSuperTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionInterfaceSuperTest.java
@@ -57,8 +57,6 @@
           .assertSuccessWithOutput(EXPECTED_OUTPUT);
       return;
     }
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
         .addInnerClasses(CustomCollectionInterfaceSuperTest.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionSuperCallsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionSuperCallsTest.java
index ac353f4..ce07cbf 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionSuperCallsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionSuperCallsTest.java
@@ -37,8 +37,6 @@
 
   @Test
   public void testCustomCollectionSuperCallsD8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     D8TestRunResult d8TestRunResult =
         testForD8()
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java
index 92ec5ee..ff0141f 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java
@@ -43,8 +43,6 @@
 
   @Test
   public void testD8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
         .addInnerClasses(DesugaredGenericSignatureTest.class)
@@ -64,8 +62,6 @@
 
   @Test
   public void testR8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
         .addInnerClasses(DesugaredGenericSignatureTest.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectedTypePassedToStaticType.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectedTypePassedToStaticType.java
index ef92b08..593c003 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectedTypePassedToStaticType.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectedTypePassedToStaticType.java
@@ -40,8 +40,6 @@
 
   @Test
   public void testD8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     D8TestRunResult runResult =
         testForD8()
@@ -66,8 +64,6 @@
 
   @Test
   public void testR8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     R8TestRunResult runResult =
         testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredReflectedDesugaredTypePassedToStaticTypeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredReflectedDesugaredTypePassedToStaticTypeTest.java
index ccf43f0..bedf904 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredReflectedDesugaredTypePassedToStaticTypeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredReflectedDesugaredTypePassedToStaticTypeTest.java
@@ -41,8 +41,6 @@
 
   @Test
   public void testD8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     D8TestRunResult runResult =
         testForD8()
@@ -67,8 +65,6 @@
 
   @Test
   public void testR8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     R8TestRunResult runResult =
         testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FeatureSplitTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FeatureSplitTest.java
index 831d83a..d4f08fc 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FeatureSplitTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FeatureSplitTest.java
@@ -50,8 +50,6 @@
 
   @Test
   public void testTwoFeatures() throws CompilationFailedException, IOException, ExecutionException {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     CompiledWithFeature compiledWithFeature = new CompiledWithFeature().invoke(this);
     Path basePath = compiledWithFeature.getBasePath();
     Path feature1Path = compiledWithFeature.getFeature1Path();
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InvalidLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InvalidLibraryTest.java
index 7c1f6a1..0490d71 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InvalidLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InvalidLibraryTest.java
@@ -65,11 +65,6 @@
 
   @Test
   public void testProgramSupertype() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary
-            && parameters.getApiLevel().isLessThan(AndroidApiLevel.N)
-            && parameters.getDexRuntimeVersion() != Version.V5_1_1
-            && parameters.getDexRuntimeVersion() != Version.V6_0_1);
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
         .setMinApi(parameters.getApiLevel())
@@ -90,11 +85,6 @@
 
   @Test
   public void testClasspathSupertype() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary
-            && parameters.getApiLevel().isLessThan(AndroidApiLevel.N)
-            && parameters.getDexRuntimeVersion() != Version.V5_1_1
-            && parameters.getDexRuntimeVersion() != Version.V6_0_1);
     Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
index bca838b..70b46ae 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
@@ -191,10 +191,6 @@
   @Test
   public void testTimeD8Cf() throws Exception {
     Assume.assumeTrue(shrinkDesugaredLibrary || !traceReferencesKeepRules);
-    expectThrowsWithHorizontalClassMergingIf(
-        parameters.isDexRuntime()
-            && traceReferencesKeepRules
-            && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
 
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     // Use D8 to desugar with Java classfile output.
@@ -245,8 +241,6 @@
   public void testTimeD8() throws Exception {
     Assume.assumeTrue(parameters.getRuntime().isDex());
     Assume.assumeTrue(shrinkDesugaredLibrary || !traceReferencesKeepRules);
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
 
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     TestCompileResult<?, ?> result =
@@ -268,8 +262,6 @@
 
   @Test
   public void testTimeR8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     Assume.assumeTrue(parameters.getRuntime().isDex());
     Assume.assumeTrue(shrinkDesugaredLibrary || !traceReferencesKeepRules);
 
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibraryEmptySubclassInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibraryEmptySubclassInterfaceTest.java
index c66ff1d..98e1917 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibraryEmptySubclassInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibraryEmptySubclassInterfaceTest.java
@@ -37,8 +37,6 @@
 
   @Test
   public void testD8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
         .addInnerClasses(LibraryEmptySubclassInterfaceTest.class)
@@ -67,8 +65,6 @@
 
   @Test
   public void testR8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(Backend.DEX)
         .addInnerClasses(LibraryEmptySubclassInterfaceTest.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibrarySubclassInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibrarySubclassInterfaceTest.java
index d69b28c..29bb1cf 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibrarySubclassInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibrarySubclassInterfaceTest.java
@@ -50,8 +50,6 @@
 
   @Test
   public void testCustomCollectionD8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     String stdOut =
         testForD8()
@@ -72,8 +70,6 @@
 
   @Test
   public void testCustomCollectionR8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     String stdOut =
         testForR8(Backend.DEX)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
index b0c3645..69f366f 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
@@ -54,8 +54,6 @@
 
   @Test
   public void testProgramD8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     ArrayList<Path> coreLambdaStubs = new ArrayList<>();
     coreLambdaStubs.add(ToolHelper.getCoreLambdaStubs());
     for (Boolean coreLambdaStubsActive : BooleanUtils.values()) {
@@ -113,8 +111,6 @@
 
   @Test
   public void testProgramR8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     Assume.assumeTrue(
         "TODO(b/139451198): Make the test run with new SDK.",
         parameters.getApiLevel().getLevel() < AndroidApiLevel.O.getLevel());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
index 7c65b9e..59dbd1b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
@@ -39,11 +39,6 @@
 
   @Test
   public void testRetargetOverrideD8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary
-            && parameters.getApiLevel().isLessThanOrEqualTo(AndroidApiLevel.K)
-            && parameters.getDexRuntimeVersion() != Version.V5_1_1
-            && parameters.getDexRuntimeVersion() != Version.V6_0_1);
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     String stdout =
         testForD8()
@@ -64,11 +59,6 @@
 
   @Test
   public void testRetargetOverrideR8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary
-            && parameters.getApiLevel().isLessThanOrEqualTo(AndroidApiLevel.K)
-            && parameters.getDexRuntimeVersion() != Version.V5_1_1
-            && parameters.getDexRuntimeVersion() != Version.V6_0_1);
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     String stdout =
         testForR8(Backend.DEX)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/StaticInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/StaticInterfaceMethodTest.java
index 5d50648..c663489 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/StaticInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/StaticInterfaceMethodTest.java
@@ -45,8 +45,6 @@
           .assertSuccessWithOutput(EXPECTED_OUTPUT);
       return;
     }
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
         .addInnerClasses(StaticInterfaceMethodTest.class)
@@ -67,8 +65,6 @@
     // Desugared library tests do not make sense in the Cf to Cf, and the JVM is already tested
     // in the D8 test. Just return.
     Assume.assumeFalse(parameters.isCfRuntime());
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
         .addKeepMainRule(Executor.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java
index 9e23d5d..f9d1828 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java
@@ -53,8 +53,6 @@
 
   @Test
   public void testFinalMethod() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
         .setMinApi(AndroidApiLevel.B)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AllTimeConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AllTimeConversionTest.java
index 2726e3e..5a03f73 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AllTimeConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AllTimeConversionTest.java
@@ -69,8 +69,6 @@
 
   @Test
   public void testRewrittenAPICallsD8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
         .setMinApi(parameters.getApiLevel())
@@ -92,8 +90,6 @@
 
   @Test
   public void testRewrittenAPICallsR8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/BasicLongDoubleConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/BasicLongDoubleConversionTest.java
index dfa62f1..4ac3ccc 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/BasicLongDoubleConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/BasicLongDoubleConversionTest.java
@@ -55,8 +55,6 @@
 
   @Test
   public void testRewrittenAPICallsD8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.K));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
         .setMinApi(parameters.getApiLevel())
@@ -76,8 +74,6 @@
 
   @Test
   public void testRewrittenAPICallsR8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.K));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ClockAPIConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ClockAPIConversionTest.java
index 8583e29..382f55d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ClockAPIConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ClockAPIConversionTest.java
@@ -50,8 +50,6 @@
 
   @Test
   public void testClockD8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
         .setMinApi(parameters.getApiLevel())
@@ -72,8 +70,6 @@
 
   @Test
   public void testClockR8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
         .addKeepMainRule(Executor.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
index 572f5b3..14f3ded 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
@@ -68,7 +68,6 @@
 
   @Test
   public void testNoInterfaceMethodsD8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(shrinkDesugaredLibrary);
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java
index d983dfa..4dbcccb 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java
@@ -54,8 +54,6 @@
 
   @Test
   public void testBaselineD8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
         .setMinApi(parameters.getApiLevel())
@@ -75,8 +73,6 @@
 
   @Test
   public void testBaselineR8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
         .setMinApi(parameters.getApiLevel())
@@ -97,8 +93,6 @@
 
   @Test
   public void testTryCatchD8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
         .setMinApi(parameters.getApiLevel())
@@ -118,8 +112,6 @@
 
   @Test
   public void testTryCatchR8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11AtomicTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11AtomicTests.java
index 8e96ae1..03995ac 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11AtomicTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11AtomicTests.java
@@ -73,8 +73,6 @@
 
   @Test
   public void testD8AtomicReference() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     String verbosity = "2";
     testForD8()
@@ -98,8 +96,6 @@
 
   @Test
   public void testD8AtomicUpdaters() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     String verbosity = "2";
     testForD8()
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ConcurrentMapTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ConcurrentMapTests.java
index 19b1b1e..7d0fc6b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ConcurrentMapTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ConcurrentMapTests.java
@@ -98,8 +98,6 @@
 
   @Test
   public void testD8Concurrent() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     // TODO(b/134732760): Support Java 9+ libraries.
     // We skip the ConcurrentRemoveIf test because of the  non desugared class CompletableFuture.
     Assume.assumeFalse("b/144975341",
@@ -159,8 +157,6 @@
 
   @Test
   public void testD8ConcurrentHash() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     Assume.assumeFalse("b/144975341",
         parameters.getRuntime().asDex().getVm().getVersion() == Version.V10_0_0);
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java
index 4ad9faa..6288598 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java
@@ -133,8 +133,6 @@
 
   @Test
   public void testTime() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     String verbosity = "2";
     D8TestCompileResult compileResult =
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
index 61e7c03..ebf503a 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
@@ -132,10 +132,6 @@
   @Test
   public void testTimeR8() throws Exception {
     boolean desugarLibrary = parameters.isDexRuntime() && requiresAnyCoreLibDesugaring(parameters);
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary
-            && parameters.isDexRuntime()
-            && parameters.getApiLevel().isLessThanOrEqualTo(AndroidApiLevel.N));
     final R8FullTestBuilder testBuilder =
         testForR8(parameters.getBackend())
             .addProgramFiles(compiledJars.get(targetVersion))
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/FieldAccessTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/FieldAccessTest.java
index 6c48313..aabd492 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/FieldAccessTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/FieldAccessTest.java
@@ -35,8 +35,6 @@
 
   @Test
   public void testField() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
         .addProgramClasses(Executor.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/InheritanceTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/InheritanceTest.java
index da15390..5d9e5e7 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/InheritanceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/InheritanceTest.java
@@ -37,8 +37,6 @@
 
   @Test
   public void testInheritance() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
         .addProgramClasses(Impl.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/KeepRuleShrinkTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/KeepRuleShrinkTest.java
index 2295e35..391cd8d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/KeepRuleShrinkTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/KeepRuleShrinkTest.java
@@ -38,8 +38,6 @@
 
   @Test
   public void testMapProblem() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     D8TestRunResult d8TestRunResult =
         testForD8()
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
index e45ef92..9a188cf 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
@@ -60,7 +60,6 @@
 
   @Test
   public void testClassMergeAcrossNestAndNonNest() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     // Potentially merge classes from a nest with non nest classes.
     testClassMergeAcrossNest(
         new String[] {
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMergeRegression.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMergeRegression.java
index 9431067..c9dd274 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMergeRegression.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMergeRegression.java
@@ -49,7 +49,6 @@
 
   @Test
   public void testInliningFromFeature() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     // Static merging is based on sorting order, we assert that we merged to the feature.
     ThrowingConsumer<R8TestCompileResult, Exception> ensureMergingToFeature =
         r8TestCompileResult -> {
diff --git a/src/test/java/com/android/tools/r8/graph/GenericSignatureTest.java b/src/test/java/com/android/tools/r8/graph/GenericSignatureTest.java
index 5001645..366e98b 100644
--- a/src/test/java/com/android/tools/r8/graph/GenericSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/graph/GenericSignatureTest.java
@@ -19,11 +19,11 @@
 import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
 import com.android.tools.r8.graph.GenericSignature.FormalTypeParameter;
 import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
-import com.android.tools.r8.graph.GenericSignature.Parser;
 import com.android.tools.r8.graph.GenericSignature.ReturnType;
 import com.android.tools.r8.graph.GenericSignature.TypeSignature;
 import com.android.tools.r8.graph.GenericSignature.WildcardIndicator;
 import com.android.tools.r8.graph.GenericSignatureTestClassA.I;
+import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.DescriptorUtils;
@@ -103,7 +103,13 @@
     // class <T:GenericSignatureTestClassA<T>.Y>CYY<T extends A<T>.Y> extends CY<T>
     DexClass clazz = cyy.getDexProgramClass();
     assertNotNull(clazz);
-    classSignature = Parser.toClassSignature(clazz, appView);
+    classSignature =
+        GenericSignature.parseClassSignature(
+            clazz.getType().getName(),
+            getGenericSignature(clazz, appView),
+            clazz.origin,
+            appView.dexItemFactory(),
+            appView.options().reporter);
     assertNotNull(classSignature);
 
     assertEquals(1, classSignature.formalTypeParameters.size());
@@ -135,7 +141,13 @@
     DexEncodedField field = yyInZZ.getField();
     assertNotNull(field);
 
-    fieldTypeSignature = Parser.toFieldTypeSignature(field, appView);
+    fieldTypeSignature =
+        GenericSignature.parseFieldTypeSignature(
+            field.field.qualifiedName(),
+            getGenericSignature(field, appView),
+            Origin.unknown(),
+            appView.dexItemFactory(),
+            appView.options().reporter);
     assertNotNull(fieldTypeSignature);
 
     // field type: A$Y$YY
@@ -152,7 +164,13 @@
     method = newYY.getMethod();
     assertNotNull(method);
 
-    methodTypeSignature = Parser.toMethodTypeSignature(method, appView);
+    methodTypeSignature =
+        GenericSignature.parseMethodSignature(
+            method.qualifiedName(),
+            getGenericSignature(method, appView),
+            Origin.unknown(),
+            appView.dexItemFactory(),
+            appView.options().reporter);
     assertNotNull(methodTypeSignature);
 
     assertEquals(1, methodTypeSignature.formalTypeParameters.size());
@@ -194,7 +212,13 @@
     method = convertToYY.getMethod();
     assertNotNull(method);
 
-    methodTypeSignature = GenericSignature.Parser.toMethodTypeSignature(method, appView);
+    methodTypeSignature =
+        GenericSignature.parseMethodSignature(
+            method.qualifiedName(),
+            getGenericSignature(method, appView),
+            Origin.unknown(),
+            appView.dexItemFactory(),
+            appView.options().reporter);
     assertNotNull(methodTypeSignature);
 
     // return type: Function<A$Y$ZZ<TT>, A$Y$YY>
@@ -231,7 +255,13 @@
     assertNotNull(method);
 
     // return type: void
-    methodTypeSignature = Parser.toMethodTypeSignature(method, appView);
+    methodTypeSignature =
+        GenericSignature.parseMethodSignature(
+            method.qualifiedName(),
+            getGenericSignature(method, appView),
+            Origin.unknown(),
+            appView.dexItemFactory(),
+            appView.options().reporter);
     assertNotNull(methodTypeSignature);
     returnType = methodTypeSignature.returnType();
     assertTrue(returnType.isVoidDescriptor());
@@ -304,7 +334,12 @@
       AppView<AppInfoWithLiveness> appView,
       Consumer<FieldTypeSignature> fieldTypeConsumer) {
     MethodTypeSignature methodTypeSignature =
-        Parser.toMethodTypeSignature(methodSubject.getMethod(), appView);
+        GenericSignature.parseMethodSignature(
+            methodSubject.getOriginalName(),
+            getGenericSignature(methodSubject.getMethod(), appView),
+            Origin.unknown(),
+            appView.dexItemFactory(),
+            appView.options().reporter);
     TypeSignature typeSignature = methodTypeSignature.returnType.typeSignature;
     FieldTypeSignature fieldTypeSignature = typeSignature.asFieldTypeSignature();
     assertTrue(fieldTypeSignature.isClassTypeSignature());
@@ -334,6 +369,22 @@
     assertTrue(typeArgument.isClassTypeSignature());
     check_A_Y_ZZ(a, y, zz, typeArgument.asClassTypeSignature());
   }
+
+  private static String getGenericSignature(
+      DexDefinition definition, AppView<AppInfoWithLiveness> appView) {
+    DexAnnotationSet annotations = definition.annotations();
+    if (annotations.annotations.length == 0) {
+      return null;
+    }
+    for (int i = 0; i < annotations.annotations.length; i++) {
+      DexAnnotation annotation = annotations.annotations[i];
+      if (!DexAnnotation.isSignatureAnnotation(annotation, appView.dexItemFactory())) {
+        continue;
+      }
+      return DexAnnotation.getSignature(annotation);
+    }
+    return null;
+  }
 }
 
 //
diff --git a/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java b/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java
index d191976..c73b948 100644
--- a/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java
+++ b/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java
@@ -6,7 +6,6 @@
 
 import static org.hamcrest.core.StringContains.containsString;
 
-import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NoStaticClassMerging;
 import com.android.tools.r8.TestBase;
@@ -14,7 +13,6 @@
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfVm;
 import java.io.IOException;
-import java.util.concurrent.ExecutionException;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -65,8 +63,7 @@
 
   @Ignore("b/128885552")
   @Test
-  public void testSuperTypeOfExceptions()
-      throws ExecutionException, CompilationFailedException, IOException {
+  public void testSuperTypeOfExceptions() throws Exception {
     testForR8(parameters.getBackend())
         .addProgramClasses(Program.class)
         .noMinification()
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/sideeffect/InvokeMultiNewArraySideEffectTest.java b/src/test/java/com/android/tools/r8/ir/analysis/sideeffect/InvokeMultiNewArraySideEffectTest.java
index 11268e8..487d60a 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/sideeffect/InvokeMultiNewArraySideEffectTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/sideeffect/InvokeMultiNewArraySideEffectTest.java
@@ -34,7 +34,6 @@
 
   @Test
   public void test() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(parameters.isCfRuntime());
     testForR8(parameters.getBackend())
         .addInnerClasses(InvokeMultiNewArraySideEffectTest.class)
         .addKeepMainRule(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
index 4429dc9..964848a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
@@ -171,7 +171,6 @@
 
   @Test
   public void testNonNullParamAfterInvokeVirtual() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     Class<?> mainClass = NonNullParamAfterInvokeVirtualMain.class;
     CodeInspector inspector =
         buildAndRun(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
index 1f8b7c1..39bfa4c 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
@@ -41,7 +41,6 @@
 
   @Test
   public void testR8() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     testForR8(parameters.getBackend())
         .addInnerClasses(InvokeVirtualNegativeTest.class)
         .addKeepMainRule(MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
index 32d0307..2595df5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
@@ -41,7 +41,6 @@
 
   @Test
   public void testR8() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     testForR8(parameters.getBackend())
         .addInnerClasses(InvokeVirtualPositiveTest.class)
         .addKeepMainRule(MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningOracleTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningOracleTest.java
index 2ed13fa..e0bd65e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningOracleTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningOracleTest.java
@@ -41,7 +41,6 @@
 
   @Test
   public void test() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(enableInvokeSuperToInvokeVirtualRewriting);
     testForR8(parameters.getBackend())
         .addInnerClasses(ClassInliningOracleTest.class)
         .addKeepMainRule(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InvokeInterfaceToInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InvokeInterfaceToInvokeVirtualTest.java
index efb4422..32ea22a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InvokeInterfaceToInvokeVirtualTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InvokeInterfaceToInvokeVirtualTest.java
@@ -53,6 +53,7 @@
             .addKeepMainRule(Main.class)
             .addOptionsModification(
                 options -> options.enableInliningOfInvokesWithNullableReceivers = false)
+            .enableNoHorizontalClassMergingAnnotations()
             .setMinApi(parameters.getApiLevel())
             .run(parameters.getRuntime(), Main.class)
             .assertSuccessWithOutputLines(EXPECTED_OUTPUT)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/invokeinterface/A0.java b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/invokeinterface/A0.java
index 67de6f1..8551247 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/invokeinterface/A0.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/invokeinterface/A0.java
@@ -3,6 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize.devirtualize.invokeinterface;
 
+import com.android.tools.r8.NoHorizontalClassMerging;
+
+@NoHorizontalClassMerging
 public class A0 extends A {
   @Override
   public int get() {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/invokeinterface/I.java b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/invokeinterface/I.java
index 48fb0b6..4b83bf3 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/invokeinterface/I.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/invokeinterface/I.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize.devirtualize.invokeinterface;
 
+
 public interface I {
   int get() throws RuntimeException;
 }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithNonNullParamCheckTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithNonNullParamCheckTest.java
index d6ef4b2..828f4c0 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithNonNullParamCheckTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithNonNullParamCheckTest.java
@@ -48,7 +48,6 @@
 
   @Test
   public void test() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     String expected =
         StringUtils.joinLines(
             "Caught NullPointerException from testRewriteInvokeStaticToThrowNull",
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/SynchronizedMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/SynchronizedMethodTest.java
index 946523e..88459a5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/SynchronizedMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/SynchronizedMethodTest.java
@@ -23,7 +23,6 @@
 
   @Test
   public void test() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     String expectedOutput = StringUtils.lines("In A.m()", "Got NullPointerException");
     CodeInspector inspector =
         testForR8(Backend.DEX)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
index b3425b8..7d3eb83 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
@@ -37,7 +37,6 @@
 
   @Test
   public void test() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     String expected =
         StringUtils.lines(
             "Factory.createStatic() -> null",
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java
index b453359..af6296b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java
@@ -34,7 +34,6 @@
 
   @Test
   public void testUnusedAndUninstantiatedTypes() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     testForR8(parameters.getBackend())
         .addInnerClasses(UnusedAndUninstantiatedTypesTest.class)
         .addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
index 33ffbca..e5ce02c 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
@@ -82,7 +82,6 @@
 
   @Test
   public void testCompanionProperty_primitivePropertyIsAlwaysInlined() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(allowAccessModification);
     final TestKotlinCompanionClass testedClass = COMPANION_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionPropertiesKt",
         "companionProperties_usePrimitiveProp");
@@ -117,7 +116,6 @@
 
   @Test
   public void testCompanionProperty_privatePropertyIsAlwaysInlined() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(allowAccessModification);
     final TestKotlinCompanionClass testedClass = COMPANION_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionPropertiesKt",
         "companionProperties_usePrivateProp");
@@ -153,7 +151,6 @@
 
   @Test
   public void testCompanionProperty_internalPropertyIsAlwaysInlined() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(allowAccessModification);
     final TestKotlinCompanionClass testedClass = COMPANION_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionPropertiesKt",
         "companionProperties_useInternalProp");
@@ -188,7 +185,6 @@
 
   @Test
   public void testCompanionProperty_publicPropertyIsAlwaysInlined() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(allowAccessModification);
     final TestKotlinCompanionClass testedClass = COMPANION_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionPropertiesKt",
         "companionProperties_usePublicProp");
@@ -223,7 +219,6 @@
 
   @Test
   public void testCompanionLateInitProperty_privatePropertyIsAlwaysInlined() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(allowAccessModification);
     final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt",
         "companionLateInitProperties_usePrivateLateInitProp");
@@ -257,7 +252,6 @@
 
   @Test
   public void testCompanionLateInitProperty_internalPropertyIsAlwaysInlined() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(allowAccessModification);
     final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt",
         "companionLateInitProperties_useInternalLateInitProp");
@@ -282,7 +276,6 @@
 
   @Test
   public void testCompanionLateInitProperty_publicPropertyIsAlwaysInlined() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(allowAccessModification);
     final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt",
         "companionLateInitProperties_usePublicLateInitProp");
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
index ec7d173..f572789 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
@@ -418,7 +418,6 @@
 
   @Test
   public void testCompanionProperty_primitivePropertyCannotBeInlined() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(allowAccessModification);
     String mainClass = addMainToClasspath(
         "properties.CompanionPropertiesKt", "companionProperties_usePrimitiveProp");
     runTest(
@@ -452,7 +451,6 @@
 
   @Test
   public void testCompanionProperty_privatePropertyIsAlwaysInlined() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(allowAccessModification);
     String mainClass = addMainToClasspath(
         "properties.CompanionPropertiesKt", "companionProperties_usePrivateProp");
     runTest(
@@ -491,7 +489,6 @@
 
   @Test
   public void testCompanionProperty_internalPropertyCannotBeInlined() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(allowAccessModification);
     String mainClass = addMainToClasspath(
         "properties.CompanionPropertiesKt", "companionProperties_useInternalProp");
     runTest(
@@ -524,7 +521,6 @@
 
   @Test
   public void testCompanionProperty_publicPropertyCannotBeInlined() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(allowAccessModification);
     String mainClass = addMainToClasspath(
         "properties.CompanionPropertiesKt", "companionProperties_usePublicProp");
     runTest(
@@ -558,7 +554,6 @@
 
   @Test
   public void testCompanionProperty_privateLateInitPropertyIsAlwaysInlined() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(allowAccessModification);
     final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt",
         "companionLateInitProperties_usePrivateLateInitProp");
@@ -595,7 +590,6 @@
 
   @Test
   public void testCompanionProperty_internalLateInitPropertyCannotBeInlined() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(allowAccessModification);
     final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt",
         "companionLateInitProperties_useInternalLateInitProp");
@@ -623,7 +617,6 @@
 
   @Test
   public void testCompanionProperty_publicLateInitPropertyCannotBeInlined() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(allowAccessModification);
     final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt",
         "companionLateInitProperties_usePublicLateInitProp");
diff --git a/src/test/java/com/android/tools/r8/naming/AbstractMethodRenamingTest.java b/src/test/java/com/android/tools/r8/naming/AbstractMethodRenamingTest.java
index 9f44e4b..9038f76 100644
--- a/src/test/java/com/android/tools/r8/naming/AbstractMethodRenamingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/AbstractMethodRenamingTest.java
@@ -8,6 +8,7 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -33,12 +34,14 @@
     }
   }
 
+  @NoHorizontalClassMerging
   static final class Sub1 extends Base {
     public final void foo() {
       System.out.println("Sub1::foo");
     }
   }
 
+  @NoHorizontalClassMerging
   static final class Sub2 extends Base {
     public final void foo() {
       System.out.println("Sub2::foo");
@@ -72,6 +75,7 @@
         .addInnerClasses(AbstractMethodRenamingTest.class)
         .addKeepMainRule(TestMain.class)
         .enableInliningAnnotations()
+        .enableNoHorizontalClassMergingAnnotations()
         .setMinApi(parameters.getRuntime())
         .run(parameters.getRuntime(), TestMain.class)
         .assertSuccessWithOutput(StringUtils.lines("Sub1::foo"))
diff --git a/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java b/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
index 07dad43..b2ec374 100644
--- a/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
@@ -4,13 +4,16 @@
 
 package com.android.tools.r8.naming;
 
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticOrigin;
 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.allOf;
+import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
 import static org.objectweb.asm.Opcodes.ACC_FINAL;
 import static org.objectweb.asm.Opcodes.ACC_SUPER;
 import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
@@ -20,15 +23,16 @@
 import static org.objectweb.asm.Opcodes.RETURN;
 import static org.objectweb.asm.Opcodes.V1_8;
 
-import com.android.tools.r8.DiagnosticsChecker;
-import com.android.tools.r8.R8Command;
-import com.android.tools.r8.StringConsumer;
+import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestDiagnosticMessages;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.ThrowingConsumer;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import java.util.function.Consumer;
 import org.junit.Test;
@@ -64,15 +68,16 @@
   String outerSignature = "<T:Ljava/lang/Object;>Ljava/lang/Object;";
   String extendsInnerSignature = "LOuter<TT;>.Inner;";
   String extendsInnerInnerSignature = "LOuter<TT;>.Inner.InnerInner;";
-  private Backend backend;
 
-  @Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public MinifierClassSignatureTest(Backend backend) {
-    this.backend = backend;
+  public MinifierClassSignatureTest(TestParameters parameters) {
+    this.parameters = parameters;
   }
 
   private byte[] dumpSimple(String classSignature) throws Exception {
@@ -298,34 +303,32 @@
 
   public void runTest(
       ImmutableMap<String, String> signatures,
-      Consumer<DiagnosticsChecker> diagnostics,
-      Consumer<CodeInspector> inspect)
+      Consumer<TestDiagnosticMessages> diagnostics,
+      ThrowingConsumer<CodeInspector, Exception> inspect)
       throws Exception {
-    DiagnosticsChecker checker = new DiagnosticsChecker();
-    CodeInspector inspector =
-        new CodeInspector(
-            ToolHelper.runR8(
-                R8Command.builder(checker)
-                    .addClassProgramData(dumpSimple(signatures.get("Simple")), Origin.unknown())
-                    .addClassProgramData(dumpBase(signatures.get("Base")), Origin.unknown())
-                    .addClassProgramData(dumpOuter(signatures.get("Outer")), Origin.unknown())
-                    .addClassProgramData(dumpInner(signatures.get("Outer$Inner")), Origin.unknown())
-                    .addClassProgramData(
-                        dumpExtendsInner(signatures.get("Outer$ExtendsInner")), Origin.unknown())
-                    .addClassProgramData(
-                        dumpInnerInner(signatures.get("Outer$Inner$InnerInner")), Origin.unknown())
-                    .addClassProgramData(
-                        dumpExtendsInnerInner(signatures.get("Outer$Inner$ExtendsInnerInner")),
-                        Origin.unknown())
-                    .addProguardConfiguration(
-                        ImmutableList.of(
-                            "-keepattributes InnerClasses,EnclosingMethod,Signature",
-                            "-keep,allowobfuscation class **"),
-                        Origin.unknown())
-                    .setProgramConsumer(emptyConsumer(backend))
-                    .addLibraryFiles(runtimeJar(backend))
-                    .setProguardMapConsumer(StringConsumer.emptyConsumer())
-                    .build()));
+    R8TestCompileResult compileResult =
+        testForR8(parameters.getBackend())
+            .addProgramClassFileData(dumpSimple(signatures.get("Simple")))
+            .addProgramClassFileData(dumpBase(signatures.get("Base")))
+            .addProgramClassFileData(dumpOuter(signatures.get("Outer")))
+            .addProgramClassFileData(dumpInner(signatures.get("Outer$Inner")))
+            .addProgramClassFileData(dumpExtendsInner(signatures.get("Outer$ExtendsInner")))
+            .addProgramClassFileData(dumpInnerInner(signatures.get("Outer$Inner$InnerInner")))
+            .addProgramClassFileData(
+                dumpExtendsInnerInner(signatures.get("Outer$Inner$ExtendsInnerInner")))
+            .addKeepAttributes(
+                ProguardKeepAttributes.INNER_CLASSES,
+                ProguardKeepAttributes.ENCLOSING_METHOD,
+                ProguardKeepAttributes.SIGNATURE)
+            .addKeepAllClassesRuleWithAllowObfuscation()
+            .allowDiagnosticMessages()
+            .compile();
+
+    compileResult.assertNoInfoMessages();
+    compileResult.assertNoErrorMessages();
+
+    CodeInspector inspector = compileResult.inspector();
+
     // All classes are kept, and renamed.
     assertThat(inspector.clazz("Simple"), isPresentAndRenamed());
     assertThat(inspector.clazz("Base"), isPresentAndRenamed());
@@ -360,26 +363,20 @@
           inspector.clazz("Outer$Inner$ExtendsInnerInner").getOriginalSignatureAttribute());
     }
 
-    diagnostics.accept(checker);
-    inspect.accept(inspector);
+    diagnostics.accept(compileResult.getDiagnosticMessages());
+    compileResult.inspect(inspect);
   }
 
-  private void testSingleClass(String name, String signature,
-      Consumer<DiagnosticsChecker> diagnostics,
-      Consumer<CodeInspector> inspector)
+  private void testSingleClass(
+      String name,
+      String signature,
+      Consumer<TestDiagnosticMessages> diagnostics,
+      ThrowingConsumer<CodeInspector, Exception> inspector)
       throws Exception {
     ImmutableMap<String, String> signatures = ImmutableMap.of(name, signature);
     runTest(signatures, diagnostics, inspector);
   }
 
-  private void isOriginUnknown(Origin origin) {
-    assertSame(Origin.unknown(), origin);
-  }
-
-  private void noWarnings(DiagnosticsChecker checker) {
-    assertEquals(0, checker.warnings.size());
-  }
-
   private void noInspection(CodeInspector inspector) {
   }
 
@@ -391,165 +388,237 @@
   @Test
   public void originalJavacSignatures() throws Exception {
     // Test using the signatures generated by javac.
-    runTest(ImmutableMap.of(), this::noWarnings, this::noInspection);
+    runTest(ImmutableMap.of(), TestDiagnosticMessages::assertNoWarnings, this::noInspection);
   }
 
   @Test
   public void classSignature_empty() throws Exception {
-    testSingleClass("Outer", "", this::noWarnings, inspector -> {
-      ClassSubject outer = inspector.clazz("Outer");
-      assertNull(outer.getFinalSignatureAttribute());
-      assertNull(outer.getOriginalSignatureAttribute());
-    });
+    testSingleClass(
+        "Outer",
+        "",
+        TestDiagnosticMessages::assertNoWarnings,
+        inspector -> {
+          ClassSubject outer = inspector.clazz("Outer");
+          assertNull(outer.getFinalSignatureAttribute());
+          assertNull(outer.getOriginalSignatureAttribute());
+        });
   }
 
   @Test
   public void classSignatureOuter_valid() throws Exception {
     // class Outer<T extends Simple> extends Base<T>
     String signature = "<T:LSimple;>LBase<TT;>;";
-    testSingleClass("Outer", signature, this::noWarnings, inspector -> {
-      ClassSubject outer = inspector.clazz("Outer");
-      ClassSubject simple = inspector.clazz("Simple");
-      ClassSubject base = inspector.clazz("Base");
-      String baseDescriptorWithoutSemicolon =
-          base.getFinalDescriptor().substring(0, base.getFinalDescriptor().length() - 1);
-      String minifiedSignature =
-          "<T:" +  simple.getFinalDescriptor() + ">" + baseDescriptorWithoutSemicolon + "<TT;>;";
-      assertEquals(minifiedSignature, outer.getFinalSignatureAttribute());
-      assertEquals(signature, outer.getOriginalSignatureAttribute());
-    });
+    testSingleClass(
+        "Outer",
+        signature,
+        TestDiagnosticMessages::assertNoWarnings,
+        inspector -> {
+          ClassSubject outer = inspector.clazz("Outer");
+          ClassSubject simple = inspector.clazz("Simple");
+          ClassSubject base = inspector.clazz("Base");
+          String baseDescriptorWithoutSemicolon =
+              base.getFinalDescriptor().substring(0, base.getFinalDescriptor().length() - 1);
+          String minifiedSignature =
+              "<T:" + simple.getFinalDescriptor() + ">" + baseDescriptorWithoutSemicolon + "<TT;>;";
+          assertEquals(minifiedSignature, outer.getFinalSignatureAttribute());
+          assertEquals(signature, outer.getOriginalSignatureAttribute());
+        });
   }
 
   @Test
   public void classSignatureExtendsInner_valid() throws Exception {
     String signature = "LOuter<TT;>.Inner;";
-    testSingleClass("Outer$ExtendsInner", signature, this::noWarnings, inspector -> {
-      ClassSubject extendsInner = inspector.clazz("Outer$ExtendsInner");
-      ClassSubject outer = inspector.clazz("Outer");
-      ClassSubject inner = inspector.clazz("Outer$Inner");
-      String outerDescriptorWithoutSemicolon =
-          outer.getFinalDescriptor().substring(0, outer.getFinalDescriptor().length() - 1);
-      String innerFinalDescriptor = inner.getFinalDescriptor();
-      String innerLastPart =
-          innerFinalDescriptor.substring(innerFinalDescriptor.indexOf("$") + 1);
-      String minifiedSignature = outerDescriptorWithoutSemicolon + "<TT;>." + innerLastPart;
-      assertEquals(minifiedSignature, extendsInner.getFinalSignatureAttribute());
-      assertEquals(signature, extendsInner.getOriginalSignatureAttribute());
-    });
+    testSingleClass(
+        "Outer$ExtendsInner",
+        signature,
+        TestDiagnosticMessages::assertNoWarnings,
+        inspector -> {
+          ClassSubject extendsInner = inspector.clazz("Outer$ExtendsInner");
+          ClassSubject outer = inspector.clazz("Outer");
+          ClassSubject inner = inspector.clazz("Outer$Inner");
+          String outerDescriptorWithoutSemicolon =
+              outer.getFinalDescriptor().substring(0, outer.getFinalDescriptor().length() - 1);
+          String innerFinalDescriptor = inner.getFinalDescriptor();
+          String innerLastPart =
+              innerFinalDescriptor.substring(innerFinalDescriptor.indexOf("$") + 1);
+          String minifiedSignature = outerDescriptorWithoutSemicolon + "<TT;>." + innerLastPart;
+          assertEquals(minifiedSignature, extendsInner.getFinalSignatureAttribute());
+          assertEquals(signature, extendsInner.getOriginalSignatureAttribute());
+        });
   }
 
   @Test
   public void classSignatureOuter_classNotFound() throws Exception {
     String signature = "<T:LNotFound;>LAlsoNotFound;";
-    testSingleClass("Outer", signature, this::noWarnings, inspector -> {
-      assertThat(inspector.clazz("NotFound"), not(isPresent()));
-      ClassSubject outer = inspector.clazz("Outer");
-      assertEquals(signature, outer.getOriginalSignatureAttribute());
-    });
+    testSingleClass(
+        "Outer",
+        signature,
+        TestDiagnosticMessages::assertNoWarnings,
+        inspector -> {
+          assertThat(inspector.clazz("NotFound"), not(isPresent()));
+          ClassSubject outer = inspector.clazz("Outer");
+          assertEquals(signature, outer.getOriginalSignatureAttribute());
+        });
   }
 
   @Test
   public void classSignatureExtendsInner_innerClassNotFound() throws Exception {
     String signature = "LOuter<TT;>.NotFound;";
-    testSingleClass("Outer$ExtendsInner", signature, this::noWarnings, inspector -> {
-      assertThat(inspector.clazz("NotFound"), not(isPresent()));
-      ClassSubject outer = inspector.clazz("Outer$ExtendsInner");
-      assertEquals(signature, outer.getOriginalSignatureAttribute());
-    });
+    testSingleClass(
+        "Outer$ExtendsInner",
+        signature,
+        TestDiagnosticMessages::assertNoWarnings,
+        inspector -> {
+          assertThat(inspector.clazz("NotFound"), not(isPresent()));
+          ClassSubject outer = inspector.clazz("Outer$ExtendsInner");
+          assertEquals(signature, outer.getOriginalSignatureAttribute());
+        });
   }
 
   @Test
   public void classSignatureExtendsInner_outerAndInnerClassNotFound() throws Exception {
     String signature = "LNotFound<TT;>.AlsoNotFound;";
-    testSingleClass("Outer$ExtendsInner", signature, this::noWarnings, inspector -> {
-      assertThat(inspector.clazz("NotFound"), not(isPresent()));
-      ClassSubject outer = inspector.clazz("Outer$ExtendsInner");
-      assertEquals(signature, outer.getOriginalSignatureAttribute());
-    });
+    testSingleClass(
+        "Outer$ExtendsInner",
+        signature,
+        TestDiagnosticMessages::assertNoWarnings,
+        inspector -> {
+          assertThat(inspector.clazz("NotFound"), not(isPresent()));
+          ClassSubject outer = inspector.clazz("Outer$ExtendsInner");
+          assertEquals(signature, outer.getOriginalSignatureAttribute());
+        });
   }
 
   @Test
   public void classSignatureExtendsInner_nestedInnerClassNotFound() throws Exception {
     String signature = "LOuter<TT;>.Inner.NotFound;";
-    testSingleClass("Outer$ExtendsInner", signature, this::noWarnings, inspector -> {
-      assertThat(inspector.clazz("NotFound"), not(isPresent()));
-      ClassSubject outer = inspector.clazz("Outer$ExtendsInner");
-      assertEquals(signature, outer.getOriginalSignatureAttribute());
-    });
+    testSingleClass(
+        "Outer$ExtendsInner",
+        signature,
+        TestDiagnosticMessages::assertNoWarnings,
+        inspector -> {
+          assertThat(inspector.clazz("NotFound"), not(isPresent()));
+          ClassSubject outer = inspector.clazz("Outer$ExtendsInner");
+          assertEquals(signature, outer.getOriginalSignatureAttribute());
+        });
   }
 
   @Test
   public void classSignatureExtendsInner_multipleMestedInnerClassesNotFound() throws Exception {
     String signature = "LOuter<TT;>.NotFound.AlsoNotFound;";
-    testSingleClass("Outer$ExtendsInner", signature, this::noWarnings, inspector -> {
-      assertThat(inspector.clazz("NotFound"), not(isPresent()));
-      ClassSubject outer = inspector.clazz("Outer$ExtendsInner");
-      assertEquals(signature, outer.getOriginalSignatureAttribute());
-    });
+    testSingleClass(
+        "Outer$ExtendsInner",
+        signature,
+        TestDiagnosticMessages::assertNoWarnings,
+        inspector -> {
+          assertThat(inspector.clazz("NotFound"), not(isPresent()));
+          ClassSubject outer = inspector.clazz("Outer$ExtendsInner");
+          assertEquals(signature, outer.getOriginalSignatureAttribute());
+        });
   }
 
   @Test
   public void classSignatureOuter_invalid() throws Exception {
-    testSingleClass("Outer", "X", diagnostics -> {
-      assertEquals(1, diagnostics.warnings.size());
-      DiagnosticsChecker.checkDiagnostic(diagnostics.warnings.get(0), this::isOriginUnknown,
-          "Invalid signature 'X' for class Outer", "Expected L at position 1");
-    }, inspector -> noSignatureAttribute(inspector.clazz("Outer")));
+    testSingleClass(
+        "Outer",
+        "X",
+        diagnostics -> {
+          diagnostics.assertWarningsCount(1);
+          diagnostics.assertAllWarningsMatch(
+              allOf(
+                  diagnosticMessage(containsString("Invalid signature 'X' for class Outer")),
+                  diagnosticMessage(containsString("Expected L at position 1")),
+                  diagnosticOrigin(Origin.unknown())));
+        },
+        inspector -> noSignatureAttribute(inspector.clazz("Outer")));
   }
 
   @Test
   public void classSignatureOuter_invalidEnd() throws Exception {
-    testSingleClass("Outer", "<L", diagnostics -> {
-      assertEquals(1, diagnostics.warnings.size());
-      DiagnosticsChecker.checkDiagnostic(diagnostics.warnings.get(0), this::isOriginUnknown,
-          "Invalid signature '<L' for class Outer", "Unexpected end of signature at position 3");
-    }, inspector -> noSignatureAttribute(inspector.clazz("Outer")));
+    testSingleClass(
+        "Outer",
+        "<L",
+        diagnostics -> {
+          diagnostics.assertWarningsCount(1);
+          diagnostics.assertAllWarningsMatch(
+              allOf(
+                  diagnosticMessage(containsString("Invalid signature '<L' for class Outer")),
+                  diagnosticMessage(containsString("Unexpected end of signature at position 3")),
+                  diagnosticOrigin(Origin.unknown())));
+        },
+        inspector -> noSignatureAttribute(inspector.clazz("Outer")));
   }
 
   @Test
   public void classSignatureExtendsInner_invalid() throws Exception {
-    testSingleClass("Outer$ExtendsInner", "X", diagnostics -> {
-      assertEquals(1, diagnostics.warnings.size());
-      DiagnosticsChecker.checkDiagnostic(diagnostics.warnings.get(0), this::isOriginUnknown,
-          "Invalid signature 'X' for class Outer$ExtendsInner", "Expected L at position 1");
-    }, inspector -> noSignatureAttribute(inspector.clazz("Outer$ExtendsInner")));
+    testSingleClass(
+        "Outer$ExtendsInner",
+        "X",
+        diagnostics -> {
+          diagnostics.assertWarningsCount(1);
+          diagnostics.assertAllWarningsMatch(
+              allOf(
+                  diagnosticMessage(
+                      containsString("Invalid signature 'X' for class Outer$ExtendsInner")),
+                  diagnosticMessage(containsString("Expected L at position 1")),
+                  diagnosticOrigin(Origin.unknown())));
+        },
+        inspector -> noSignatureAttribute(inspector.clazz("Outer$ExtendsInner")));
   }
 
   @Test
   public void classSignatureExtendsInnerInner_invalid() throws Exception {
-    testSingleClass("Outer$Inner$ExtendsInnerInner", "X", diagnostics -> {
-      assertEquals(1, diagnostics.warnings.size());
-      DiagnosticsChecker.checkDiagnostic(diagnostics.warnings.get(0), this::isOriginUnknown,
-          "Invalid signature 'X' for class Outer$Inner$ExtendsInnerInner",
-          "Expected L at position 1");
-    }, inspector -> noSignatureAttribute(inspector.clazz("Outer$Inner$ExtendsInnerInner")));
+    testSingleClass(
+        "Outer$Inner$ExtendsInnerInner",
+        "X",
+        diagnostics -> {
+          diagnostics.assertWarningsCount(1);
+          diagnostics.assertAllWarningsMatch(
+              allOf(
+                  diagnosticMessage(
+                      containsString(
+                          "Invalid signature 'X' for class Outer$Inner$ExtendsInnerInner")),
+                  diagnosticMessage(containsString("Expected L at position 1")),
+                  diagnosticOrigin(Origin.unknown())));
+        },
+        inspector -> noSignatureAttribute(inspector.clazz("Outer$Inner$ExtendsInnerInner")));
   }
 
   @Test
   public void multipleWarnings() throws Exception {
-    runTest(ImmutableMap.of(
-        "Outer", "X",
-        "Outer$ExtendsInner", "X",
-        "Outer$Inner$ExtendsInnerInner", "X"), diagnostics -> {
-      assertEquals(3, diagnostics.warnings.size());
-    }, inspector -> {
-      noSignatureAttribute(inspector.clazz("Outer"));
-      noSignatureAttribute(inspector.clazz("Outer$ExtendsInner"));
-      noSignatureAttribute(inspector.clazz("Outer$Inner$ExtendsInnerInner"));
-    });
+    runTest(
+        ImmutableMap.of(
+            "Outer", "X",
+            "Outer$ExtendsInner", "X",
+            "Outer$Inner$ExtendsInnerInner", "X"),
+        diagnostics -> {
+          diagnostics.assertWarningsCount(3);
+        },
+        inspector -> {
+          noSignatureAttribute(inspector.clazz("Outer"));
+          noSignatureAttribute(inspector.clazz("Outer$ExtendsInner"));
+          noSignatureAttribute(inspector.clazz("Outer$Inner$ExtendsInnerInner"));
+        });
   }
+
   @Test
   public void regress80029761() throws Exception {
     String signature = "LOuter<TT;>.com/example/Inner;";
-    testSingleClass("Outer$ExtendsInner", signature, diagnostics -> {
-      assertEquals(1, diagnostics.warnings.size());
-      DiagnosticsChecker.checkDiagnostic(
-          diagnostics.warnings.get(0),
-          this::isOriginUnknown,
-          "Invalid signature '" + signature + "' for class Outer$ExtendsInner",
-          "Expected ; at position 16");
-    }, inspector -> {
-      noSignatureAttribute(inspector.clazz("Outer$ExtendsInner"));
-    });
+    testSingleClass(
+        "Outer$ExtendsInner",
+        signature,
+        diagnostics -> {
+          diagnostics.assertWarningsCount(1);
+          diagnostics.assertAllWarningsMatch(
+              allOf(
+                  diagnosticMessage(
+                      containsString(
+                          "Invalid signature '" + signature + "' for class Outer$ExtendsInner")),
+                  diagnosticMessage(containsString("Expected ; at position 16")),
+                  diagnosticOrigin(Origin.unknown())));
+        },
+        inspector -> {
+          noSignatureAttribute(inspector.clazz("Outer$ExtendsInner"));
+        });
   }
 }
diff --git a/src/test/java/com/android/tools/r8/naming/b133686361/AlreadyRenamedAbstractMethodRenamingTest.java b/src/test/java/com/android/tools/r8/naming/b133686361/AlreadyRenamedAbstractMethodRenamingTest.java
index 7cda3cd..8d07717 100644
--- a/src/test/java/com/android/tools/r8/naming/b133686361/AlreadyRenamedAbstractMethodRenamingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/b133686361/AlreadyRenamedAbstractMethodRenamingTest.java
@@ -9,6 +9,7 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -40,12 +41,14 @@
     }
   }
 
+  @NoHorizontalClassMerging
   static final class Sub1 extends Base {
     public final void a() {
       System.out.println("Sub1::a");
     }
   }
 
+  @NoHorizontalClassMerging
   static final class Sub2 extends Base {
     public final void a() {
       System.out.println("Sub2::a");
@@ -79,6 +82,7 @@
         .addInnerClasses(AlreadyRenamedAbstractMethodRenamingTest.class)
         .addKeepMainRule(TestMain.class)
         .enableInliningAnnotations()
+        .enableNoHorizontalClassMergingAnnotations()
         .setMinApi(parameters.getRuntime())
         .run(parameters.getRuntime(), TestMain.class)
         .assertSuccessWithOutput(StringUtils.lines("Sub1::a"))
diff --git a/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java b/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java
index d84c94c..d0cb2bf 100644
--- a/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java
+++ b/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java
@@ -70,7 +70,6 @@
 
   @Test
   public void innerConstructsOuter() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     Class<?> clazz = com.android.tools.r8.regress.b69825683.innerconstructsouter.Outer.class;
     CodeInspector inspector =
         testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageTest.java
index d912811..2f6574b 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageTest.java
@@ -98,7 +98,6 @@
 
   @Test
   public void testR8() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     testForR8(parameters.getBackend())
         .addProgramFiles(ToolHelper.getClassFilesForTestPackage(TestClass.class.getPackage()))
         .addKeepMainRule(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithArrayMethodTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithArrayMethodTest.java
new file mode 100644
index 0000000..0216990
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithArrayMethodTest.java
@@ -0,0 +1,54 @@
+// Copyright (c) 2020, 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.repackage;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RepackageWithArrayMethodTest extends RepackageTestBase {
+
+  public RepackageWithArrayMethodTest(
+      String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+    super(flattenPackageHierarchyOrRepackageClasses, parameters);
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(TestClass.class)
+        .apply(this::configureRepackaging)
+        .enableInliningAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspect(this::inspect)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("Hello world!");
+  }
+
+  private void inspect(CodeInspector inspector) {}
+
+  public static class TestClass {
+
+    public static void main(String[] args) {
+      A[] array = new A[1];
+      array[0] = new A();
+      array.clone()[0].greet();
+    }
+  }
+
+  public static class A {
+
+    @NeverInline
+    public void greet() {
+      System.out.println("Hello world!");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithInvokeDynamicTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithInvokeDynamicTest.java
new file mode 100644
index 0000000..a8581be
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithInvokeDynamicTest.java
@@ -0,0 +1,69 @@
+// Copyright (c) 2020, 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.repackage;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RepackageWithInvokeDynamicTest extends RepackageTestBase {
+
+  public RepackageWithInvokeDynamicTest(
+      String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+    super(flattenPackageHierarchyOrRepackageClasses, parameters);
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(TestClass.class)
+        .apply(this::configureRepackaging)
+        .enableInliningAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspect(this::inspect)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("Hello world!");
+  }
+
+  private void inspect(CodeInspector inspector) {}
+
+  public static class TestClass {
+
+    public static void main(String[] args) {
+      I greeterFactory = getGreeterFactory("Hello world!");
+      greeterFactory.create().greet();
+    }
+
+    @NeverInline
+    static I getGreeterFactory(String greeting) {
+      return () -> new A(greeting);
+    }
+  }
+
+  public interface I {
+
+    A create();
+  }
+
+  public static class A {
+
+    private final String greeting;
+
+    public A(String greeting) {
+      this.greeting = greeting;
+    }
+
+    @NeverInline
+    public void greet() {
+      System.out.println(greeting);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithSuffixRenamingConfigurationTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithSuffixRenamingConfigurationTest.java
new file mode 100644
index 0000000..b22042f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithSuffixRenamingConfigurationTest.java
@@ -0,0 +1,78 @@
+// Copyright (c) 2020, 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.repackage;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.repackaging.Repackaging.SuffixRenamingRepackagingConfiguration;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RepackageWithSuffixRenamingConfigurationTest extends RepackageTestBase {
+
+  public RepackageWithSuffixRenamingConfigurationTest(
+      String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+    super(flattenPackageHierarchyOrRepackageClasses, parameters);
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(TestClass.class)
+        .addKeepClassRules(GreeterFoo.class)
+        .addOptionsModification(
+            options ->
+                options.testing.repackagingConfigurationFactory =
+                    appView ->
+                        new SuffixRenamingRepackagingConfiguration("Foo", appView.dexItemFactory()))
+        .apply(this::configureRepackaging)
+        .enableInliningAnnotations()
+        .noMinification()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspect(this::inspect)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("Hello world!");
+  }
+
+  private void inspect(CodeInspector inspector) {
+    ClassSubject greeterSubject = inspector.clazz(Greeter.class);
+    assertEquals(GreeterFoo.class.getTypeName() + "$1", greeterSubject.getFinalName());
+
+    ClassSubject greeterFooSubject = inspector.clazz(GreeterFoo.class);
+    assertEquals(GreeterFoo.class.getTypeName(), greeterFooSubject.getFinalName());
+  }
+
+  public static class TestClass {
+
+    public static void main(String[] args) {
+      Greeter.greet();
+      GreeterFoo.greet();
+    }
+  }
+
+  public static class Greeter extends Exception {
+
+    @NeverInline
+    public static void greet() {
+      System.out.print("Hello");
+    }
+  }
+
+  public static class GreeterFoo extends Exception {
+
+    @NeverInline
+    public static void greet() {
+      System.out.println(" world!");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java
index 7435fe1..2000456 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java
@@ -85,7 +85,6 @@
 
   @Test
   public void testR8() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     testForR8(parameters.getBackend())
         .addProgramClasses(getClasses())
         .addProgramClassFileData(getTransformedClasses())
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 6e9ddce..9ceaddc 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
@@ -84,7 +84,6 @@
 
   @Test
   public void testR8() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     testForR8(parameters.getBackend())
         .addProgramClasses(getClasses())
         .addProgramClassFileData(getTransformedClasses())
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java
index bc9973b..e172db4 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java
@@ -7,6 +7,7 @@
 import static org.hamcrest.core.StringContains.containsString;
 import static org.junit.Assert.assertEquals;
 
+import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRunResult;
@@ -87,12 +88,12 @@
 
   @Test
   public void testR8() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(!inSameNest);
     testForR8(parameters.getBackend())
         .addProgramClasses(getClasses())
         .addProgramClassFileData(getTransformedClasses())
         .setMinApi(parameters.getApiLevel())
         .addKeepMainRule(Main.class)
+        .enableNoHorizontalClassMergingAnnotations()
         .run(parameters.getRuntime(), Main.class)
         .apply(this::checkExpectedResult);
   }
@@ -114,6 +115,7 @@
     return transformer(clazz).setNest(clazz);
   }
 
+  @NoHorizontalClassMerging
   static class A {
     /* will be private */ void bar() {
       System.out.println("A::bar");
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 0deacd4..da00722 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
@@ -83,7 +83,6 @@
 
   @Test
   public void testR8() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     testForR8(parameters.getBackend())
         .addProgramClasses(getClasses())
         .addProgramClassFileData(getTransformedClasses())
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java
index 8ae84a0..eb88c69 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java
@@ -79,7 +79,6 @@
 
   @Test
   public void testR8() throws IOException, CompilationFailedException, ExecutionException {
-    expectThrowsWithHorizontalClassMergingIf(parameters.isCfRuntime());
     testForR8(parameters.getBackend())
         .addInnerClasses(MultipleImplementsTest.class)
         .enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java
index 829a26b..5628ea2 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java
@@ -85,7 +85,6 @@
 
   @Test
   public void testR8() throws IOException, CompilationFailedException, ExecutionException {
-    expectThrowsWithHorizontalClassMergingIf(parameters.isCfRuntime());
     testForR8(parameters.getBackend())
         .addInnerClasses(SubTypeMissingOverridesTest.class)
         .enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
index d7a5246..731e807 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
@@ -14,6 +14,7 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestDiagnosticMessagesImpl;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.retrace.Retrace.RetraceAbortException;
 import com.android.tools.r8.retrace.stacktraces.ActualBotStackTraceBase;
 import com.android.tools.r8.retrace.stacktraces.ActualIdentityStackTrace;
@@ -29,6 +30,7 @@
 import com.android.tools.r8.retrace.stacktraces.InlineSourceFileContextStackTrace;
 import com.android.tools.r8.retrace.stacktraces.InlineWithLineNumbersStackTrace;
 import com.android.tools.r8.retrace.stacktraces.InvalidStackTrace;
+import com.android.tools.r8.retrace.stacktraces.MemberFieldOverlapStackTrace;
 import com.android.tools.r8.retrace.stacktraces.NamedModuleStackTrace;
 import com.android.tools.r8.retrace.stacktraces.NullStackTrace;
 import com.android.tools.r8.retrace.stacktraces.ObfucatedExceptionClassStackTrace;
@@ -41,6 +43,7 @@
 import com.google.common.collect.ImmutableList;
 import java.util.Collection;
 import java.util.List;
+import java.util.function.Consumer;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -191,6 +194,22 @@
     runRetraceTest(new InlineSourceFileContextStackTrace());
   }
 
+  @Test
+  public void testMemberFieldOverlapStackTrace() throws Exception {
+    MemberFieldOverlapStackTrace stackTraceForTest = new MemberFieldOverlapStackTrace();
+    runRetraceTest(stackTraceForTest);
+    inspectRetraceTest(stackTraceForTest, stackTraceForTest::inspectField);
+  }
+
+  private void inspectRetraceTest(
+      StackTraceForTest stackTraceForTest, Consumer<RetraceApi> inspection) throws Exception {
+    TestDiagnosticMessagesImpl diagnosticsHandler = new TestDiagnosticMessagesImpl();
+    ClassNameMapper classNameMapper =
+        ClassNameMapper.mapperFromString(stackTraceForTest.mapping(), diagnosticsHandler);
+    RetraceApi retracer = Retracer.create(classNameMapper);
+    inspection.accept(retracer);
+  }
+
   private TestDiagnosticMessagesImpl runRetraceTest(StackTraceForTest stackTraceForTest) {
     TestDiagnosticMessagesImpl diagnosticsHandler = new TestDiagnosticMessagesImpl();
     RetraceCommand retraceCommand =
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/MemberFieldOverlapStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/MemberFieldOverlapStackTrace.java
new file mode 100644
index 0000000..9071654
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/MemberFieldOverlapStackTrace.java
@@ -0,0 +1,48 @@
+// Copyright (c) 2020, 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.retrace.stacktraces;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.RetraceApi;
+import com.android.tools.r8.retrace.RetraceFieldResult;
+import com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import java.util.List;
+
+public class MemberFieldOverlapStackTrace implements StackTraceForTest {
+
+  @Override
+  public List<String> obfuscatedStackTrace() {
+    return Arrays.asList(
+        "Exception in thread \"main\" java.lang.NullPointerException", "\tat a.A.a(Bar.java:1)");
+  }
+
+  @Override
+  public String mapping() {
+    return StringUtils.lines("foo.Bar -> a.A:", "  1:1:int method():5 -> a", "  int field -> a");
+  }
+
+  @Override
+  public List<String> retracedStackTrace() {
+    return Arrays.asList(
+        "Exception in thread \"main\" java.lang.NullPointerException",
+        "\tat foo.Bar.method(Bar.java:5)");
+  }
+
+  @Override
+  public int expectedWarnings() {
+    return 1;
+  }
+
+  public void inspectField(RetraceApi retracer) {
+    RetraceFieldResult result =
+        retracer.retrace(Reference.classFromTypeName("a.A")).lookupField("field");
+    assertTrue(result.stream().findAny().isPresent());
+    assertFalse(result.isAmbiguous());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java b/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java
index 943e3b3..b299b76 100644
--- a/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java
@@ -53,7 +53,6 @@
 
   @Test
   public void testR8() throws IOException, CompilationFailedException, ExecutionException {
-    expectThrowsWithHorizontalClassMergingIf(parameters.isDexRuntime());
     testForR8(parameters.getBackend())
         .addInnerClasses(JavaScriptScriptEngineTest.class)
         .addKeepMainRule(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/rewrite/serviceloaders/MissingServiceClassTest.java b/src/test/java/com/android/tools/r8/rewrite/serviceloaders/MissingServiceClassTest.java
index 94d7781..8325b62 100644
--- a/src/test/java/com/android/tools/r8/rewrite/serviceloaders/MissingServiceClassTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/serviceloaders/MissingServiceClassTest.java
@@ -5,20 +5,16 @@
 package com.android.tools.r8.rewrite.serviceloaders;
 
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
-import static org.hamcrest.CoreMatchers.anyOf;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
 import com.android.tools.r8.DataEntryResource;
-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.graph.AppServices;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.rewrite.serviceloaders.MissingServiceImplementationClassTest.Service;
-import com.android.tools.r8.rewrite.serviceloaders.MissingServiceImplementationClassTest.ServiceImpl;
 import com.android.tools.r8.utils.DataResourceConsumerForTesting;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.List;
@@ -60,24 +56,15 @@
         .compile()
         .inspectDiagnosticMessages(
             inspector -> {
-              inspector.assertWarningsCount(2);
               inspector.assertAllWarningsMatch(
                   diagnosticMessage(
-                      anyOf(
-                          containsString(
-                              "Unexpected reference to missing service class: "
-                                  + AppServices.SERVICE_DIRECTORY_NAME
-                                  + Service.class.getTypeName()
-                                  + "."),
-                          containsString(
-                              "Unexpected reference to missing service implementation class in "
-                                  + AppServices.SERVICE_DIRECTORY_NAME
-                                  + Service.class.getTypeName()
-                                  + ": "
-                                  + ServiceImpl.class.getTypeName()
-                                  + "."))));
+                      containsString(
+                          "Unexpected reference to missing service class: "
+                              + AppServices.SERVICE_DIRECTORY_NAME
+                              + Service.class.getTypeName()
+                              + ".")));
             })
-        .apply(this::configureRunClasspath)
+        .addRunClasspathClasses(Service.class, ServiceImpl.class)
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithEmptyOutput();
 
@@ -91,19 +78,6 @@
     assertEquals(ServiceImpl.class.getTypeName(), contents.get(0));
   }
 
-  private void configureRunClasspath(R8TestCompileResult compileResult) throws Exception {
-    if (parameters.isCfRuntime()) {
-      compileResult.addRunClasspathClasses(Service.class, ServiceImpl.class);
-    } else {
-      compileResult.addRunClasspathFiles(
-          testForD8(temp)
-              .addProgramClasses(Service.class, ServiceImpl.class)
-              .setMinApi(parameters.getApiLevel())
-              .compile()
-              .writeToZip());
-    }
-  }
-
   static class TestClass {
 
     public static void main(String[] args) throws ClassNotFoundException {
diff --git a/src/test/java/com/android/tools/r8/rewrite/serviceloaders/MissingServiceImplementationClassTest.java b/src/test/java/com/android/tools/r8/rewrite/serviceloaders/MissingServiceImplementationClassTest.java
index 7f3e416..5976b7c 100644
--- a/src/test/java/com/android/tools/r8/rewrite/serviceloaders/MissingServiceImplementationClassTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/serviceloaders/MissingServiceImplementationClassTest.java
@@ -4,9 +4,7 @@
 
 package com.android.tools.r8.rewrite.serviceloaders;
 
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -19,8 +17,6 @@
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.AppServices;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.rewrite.serviceloaders.MissingServiceClassTest.Service;
-import com.android.tools.r8.rewrite.serviceloaders.MissingServiceClassTest.ServiceImpl;
 import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.DataResourceConsumerForTesting;
 import com.android.tools.r8.utils.StringUtils;
@@ -74,22 +70,8 @@
                       new DataResourceConsumerForTesting(options.dataResourceConsumer));
                   options.dataResourceConsumer = dataResourceConsumer.get();
                 })
-            .allowDiagnosticWarningMessages()
             .setMinApi(parameters.getApiLevel())
-            .compile()
-            .inspectDiagnosticMessages(
-                inspector -> {
-                  inspector.assertWarningsCount(1);
-                  inspector.assertAllWarningsMatch(
-                      diagnosticMessage(
-                          containsString(
-                              "Unexpected reference to missing service implementation class in "
-                                  + AppServices.SERVICE_DIRECTORY_NAME
-                                  + Service.class.getTypeName()
-                                  + ": "
-                                  + ServiceImpl.class.getTypeName()
-                                  + ".")));
-                });
+            .compile();
 
     CodeInspector inspector = compileResult.inspector();
     ClassSubject serviceClassSubject = inspector.clazz(Service.class);
diff --git a/src/test/java/com/android/tools/r8/rewrite/serviceloaders/MissingServiceImplementationClassWithFeatureTest.java b/src/test/java/com/android/tools/r8/rewrite/serviceloaders/MissingServiceImplementationClassWithFeatureTest.java
index b3f120c..896cc71 100644
--- a/src/test/java/com/android/tools/r8/rewrite/serviceloaders/MissingServiceImplementationClassWithFeatureTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/serviceloaders/MissingServiceImplementationClassWithFeatureTest.java
@@ -4,16 +4,12 @@
 
 package com.android.tools.r8.rewrite.serviceloaders;
 
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
-import static org.hamcrest.CoreMatchers.containsString;
-
 import com.android.tools.r8.DataEntryResource;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.AppServices;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.rewrite.serviceloaders.MissingServiceImplementationClassTest.Service;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.ServiceLoader;
 import org.junit.Test;
@@ -48,20 +44,8 @@
                 AppServices.SERVICE_DIRECTORY_NAME + Service.class.getTypeName(),
                 Origin.unknown()))
         .addFeatureSplit(FeatureClass.class)
-        .allowDiagnosticWarningMessages()
         .setMinApi(parameters.getApiLevel())
-        .compile()
-        .inspectDiagnosticMessages(
-            inspector -> {
-              inspector.assertWarningsCount(1);
-              inspector.assertAllWarningsMatch(
-                  diagnosticMessage(
-                      containsString(
-                          "Unexpected reference to missing service implementation class in "
-                              + AppServices.SERVICE_DIRECTORY_NAME
-                              + Service.class.getTypeName()
-                              + ": MissingClass.")));
-            });
+        .compile();
   }
 
   static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/shaking/AbstractMethodOnNonAbstractClassTest.java b/src/test/java/com/android/tools/r8/shaking/AbstractMethodOnNonAbstractClassTest.java
index 4d65424..0fce1c4 100644
--- a/src/test/java/com/android/tools/r8/shaking/AbstractMethodOnNonAbstractClassTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/AbstractMethodOnNonAbstractClassTest.java
@@ -11,6 +11,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -40,11 +41,11 @@
 
   @Test
   public void testCompat() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     R8TestCompileResult compileResult =
         testForR8Compat(parameters.getBackend())
             .addInnerClasses(AbstractMethodOnNonAbstractClassTest.class)
             .addKeepMainRule(TestClass.class)
+            .enableNoHorizontalClassMergingAnnotations()
             .setMinApi(parameters.getApiLevel())
             .compile();
 
@@ -75,6 +76,7 @@
         testForR8(parameters.getBackend())
             .addInnerClasses(AbstractMethodOnNonAbstractClassTest.class)
             .addKeepMainRule(TestClass.class)
+            .enableNoHorizontalClassMergingAnnotations()
             .setMinApi(parameters.getApiLevel())
             .compile();
 
@@ -114,6 +116,7 @@
     void m() {}
   }
 
+  @NoHorizontalClassMerging
   static class B extends A {
 
     @Override
diff --git a/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking12Test.java b/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking12Test.java
index 47f8b62..b30a14d 100644
--- a/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking12Test.java
+++ b/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking12Test.java
@@ -44,8 +44,6 @@
 
   @Test
   public void testKeeprules() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        getFrontend() != Frontend.JAR || getParameters().isDexRuntime());
     runTest(
         TreeShaking12Test::shaking12OnlyInstantiatedClassesHaveConstructors,
         null,
@@ -55,8 +53,6 @@
 
   @Test
   public void testKeeprulesprintusage() throws Exception {
-    expectThrowsWithHorizontalClassMergingIf(
-        getFrontend() != Frontend.JAR || getParameters().isDexRuntime());
     runTest(
         null,
         null,
diff --git a/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingInliningTest.java b/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingInliningTest.java
index 97ad730..08dfc6a 100644
--- a/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingInliningTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingInliningTest.java
@@ -37,13 +37,11 @@
 
   @Test
   public void testKeeprules() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     runTest(null, null, null, ImmutableList.of("src/test/examples/inlining/keep-rules.txt"));
   }
 
   @Test
   public void testKeeprulesdiscard() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     // On the cf backend, we don't inline into constructors, see: b/136250031
     List<String> keepRules =
         getParameters().isCfRuntime()
diff --git a/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingMinificationTest.java b/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingMinificationTest.java
index f703896..b8151d6 100644
--- a/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingMinificationTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingMinificationTest.java
@@ -38,7 +38,6 @@
 
   @Test
   public void test() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     runTest(null, null, null, ImmutableList.of("src/test/examples/minification/keep-rules.txt"));
   }
 
diff --git a/src/test/java/com/android/tools/r8/shaking/includedescriptorclasses/IncludeDescriptorClassesTest.java b/src/test/java/com/android/tools/r8/shaking/includedescriptorclasses/IncludeDescriptorClassesTest.java
index 8ab404c..a3ad6d1 100644
--- a/src/test/java/com/android/tools/r8/shaking/includedescriptorclasses/IncludeDescriptorClassesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/includedescriptorclasses/IncludeDescriptorClassesTest.java
@@ -82,7 +82,6 @@
 
   @Test
   public void testNoIncludesDescriptorClasses() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     for (Class<?> mainClass : mainClasses) {
       List<Class<?>> allClasses = new ArrayList<>(applicationClasses);
       allClasses.add(mainClass);
diff --git a/src/test/java/com/android/tools/r8/shaking/testrules/ForceInlineTest.java b/src/test/java/com/android/tools/r8/shaking/testrules/ForceInlineTest.java
index 8d56292..41533ec 100644
--- a/src/test/java/com/android/tools/r8/shaking/testrules/ForceInlineTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/testrules/ForceInlineTest.java
@@ -50,7 +50,6 @@
 
   @Test
   public void testDefaultInlining() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     CodeInspector inspector =
         runTest(
             ImmutableList.of(
@@ -79,7 +78,6 @@
 
   @Test
   public void testNeverInline() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     CodeInspector inspector =
         runTest(
             ImmutableList.of(
@@ -107,7 +105,6 @@
 
   @Test
   public void testForceInline() throws Exception {
-    expectThrowsWithHorizontalClassMerging();
     CodeInspector inspector =
         runTest(
             ImmutableList.of(