Merge commit '0b579d0bee06cfb404c5f18c4827aee0d3a4e771' into 1.7.9-dev
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index e2ad67e..773f4ad 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.graph.ResolutionResult.NoSuchMethodResult;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.InternalOptions;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMap.Builder;
 import com.google.common.collect.ImmutableSet;
@@ -45,6 +46,10 @@
     copyMetadataFromPrevious(previous);
   }
 
+  protected InternalOptions options() {
+    return app.options;
+  }
+
   public void copyMetadataFromPrevious(AppInfo previous) {
     this.synthesizedClasses.putAll(previous.synthesizedClasses);
   }
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
index ec90464..460885c 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
@@ -325,7 +325,6 @@
     assert checkIfObsolete();
     if (!isSubtype(invocationContext, method.holder)) {
       DexClass contextClass = definitionFor(invocationContext);
-      isSubtype(invocationContext, method.holder);
       throw new CompilationError(
           "Illegal invoke-super to " + method.toSourceString() + " from class " + invocationContext,
           contextClass != null ? contextClass.getOrigin() : Origin.unknown());
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java
index 2af1aa5..079b8bb 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java
@@ -28,4 +28,6 @@
   boolean isReadOnlyIn(DexEncodedMethod method);
 
   boolean isWritten();
+
+  boolean isWrittenOutside(DexEncodedMethod method);
 }
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
index b6c54cb..fcd4f5c 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
@@ -146,6 +146,23 @@
     return writesWithContexts != null && !writesWithContexts.isEmpty();
   }
 
+  /**
+   * Returns true if this field is written by a method in the program other than {@param method}.
+   */
+  @Override
+  public boolean isWrittenOutside(DexEncodedMethod method) {
+    if (writesWithContexts != null) {
+      for (Set<DexEncodedMethod> encodedWriteContexts : writesWithContexts.values()) {
+        for (DexEncodedMethod encodedWriteContext : encodedWriteContexts) {
+          if (encodedWriteContext != method) {
+            return true;
+          }
+        }
+      }
+    }
+    return false;
+  }
+
   public boolean recordRead(DexField access, DexEncodedMethod context) {
     if (readsWithContexts == null) {
       readsWithContexts = new IdentityHashMap<>();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
index ac6bcde..0ca8fac 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
@@ -144,13 +144,13 @@
 
         boolean encodedValueStorageIsLive;
         if (enqueuer.isFieldLive(encodedValueStorage)) {
-          // Mark that the field is written by reflection such that we do not optimize field reads
-          // into loading the default value of the field.
-          enqueuer.registerFieldWrite(encodedValueStorage.field, dynamicMethod);
-          // Map/required fields cannot be removed. Therefore, we mark such fields as both read and
-          // written such that we cannot optimize any field reads or writes.
-          if (reachesMapOrRequiredField(protoFieldInfo)) {
-            enqueuer.registerFieldRead(encodedValueStorage.field, dynamicMethod);
+          if (enqueuer.isFieldRead(encodedValueStorage)
+              || enqueuer.isFieldWrittenOutsideDefaultConstructor(encodedValueStorage)) {
+            // Mark that the field is both read and written by reflection such that we do not
+            // (i) optimize field reads into loading the default value of the field or (ii) remove
+            // field writes to proto fields that could be read using reflection by the proto
+            // library.
+            enqueuer.registerFieldAccess(encodedValueStorage.field, dynamicMethod);
           }
           encodedValueStorageIsLive = true;
         } else if (reachesMapOrRequiredField(protoFieldInfo)) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java
index d1ca480..8078fe0 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java
@@ -134,10 +134,18 @@
     }
 
     private void addTarget(DexEncodedMethod callee, boolean likelySpuriousCallEdge) {
-      if (!callee.accessFlags.isAbstract()) {
-        assert callee.isProgramMethod(appView);
-        getOrCreateNode(callee).addCallerConcurrently(caller, likelySpuriousCallEdge);
+      if (callee.accessFlags.isAbstract()) {
+        // Not a valid target.
+        return;
       }
+      if (appView.appInfo().isPinned(callee.method)) {
+        // Since the callee is kept, we cannot inline it into the caller, and we also cannot collect
+        // any optimization info for the method. Therefore, we drop the call edge to reduce the
+        // total number of call graph edges, which should lead to fewer call graph cycles.
+        return;
+      }
+      assert callee.isProgramMethod(appView);
+      getOrCreateNode(callee).addCallerConcurrently(caller, likelySpuriousCallEdge);
     }
 
     private void processInvoke(Type originalType, DexMethod originalMethod) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
index f0eda16..708cabb8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
@@ -139,6 +139,7 @@
     // We look up everywhere to see if there is a supertype/interface implementing the method...
     LinkedList<DexType> workList = new LinkedList<>();
     Collections.addAll(workList, theClass.interfaces.values);
+    boolean foundOverrideToRewrite = false;
     // There is no methods with desugared types on Object.
     if (theClass.superType != factory.objectType) {
       workList.add(theClass.superType);
@@ -158,10 +159,14 @@
       }
       DexEncodedMethod dexEncodedMethod = dexClass.lookupVirtualMethod(method);
       if (dexEncodedMethod != null) {
-        return true;
+        if (appView.options().desugaredLibraryConfiguration.getEmulateLibraryInterface()
+            .containsKey(dexClass.type)) {
+          return false;
+        }
+        foundOverrideToRewrite = true;
       }
     }
-    return false;
+    return foundOverrideToRewrite;
   }
 
   private synchronized void generateCallBack(DexClass dexClass, DexEncodedMethod originalMethod) {
@@ -169,7 +174,7 @@
         methodWithVivifiedTypeInSignature(originalMethod.method, dexClass.type, appView);
     CfCode cfCode =
         new APIConverterWrapperCfCodeProvider(
-                appView, originalMethod.method, null, this, dexClass.isInterface())
+            appView, originalMethod.method, null, this, dexClass.isInterface())
             .generateCfCode();
     DexEncodedMethod newDexEncodedMethod =
         wrapperSynthesizor.newSynthesizedMethod(methodToInstall, originalMethod, cfCode);
@@ -256,7 +261,7 @@
         // Return conversion added only if return value is used.
         if (invokeMethod.outValue() != null
             && invokeMethod.outValue().numberOfUsers() + invokeMethod.outValue().numberOfPhiUsers()
-                > 0) {
+            > 0) {
           returnConversion =
               createReturnConversionAndReplaceUses(code, invokeMethod, returnType, newReturnType);
         }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
index 95db2cf..2bf43f2 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
@@ -95,6 +95,7 @@
 public class DesugaredLibraryWrapperSynthesizer {
 
   public static final String WRAPPER_PREFIX = "$r8$wrapper$";
+  public static final String WRAPPER_DESCRIPTOR_PREFIX = "L" + WRAPPER_PREFIX;
   public static final String TYPE_WRAPPER_SUFFIX = "$-WRP";
   public static final String VIVIFIED_TYPE_WRAPPER_SUFFIX = "$-V-WRP";
 
@@ -118,6 +119,10 @@
     this.converter = converter;
   }
 
+  public static boolean isSynthesizedWrapper(DexType clazz) {
+    return clazz.descriptor.toString().startsWith(WRAPPER_DESCRIPTOR_PREFIX);
+  }
+
   boolean hasSynthesized(DexType type) {
     return generatedWrappers.contains(type);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index 87350e7..263da6c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -264,14 +264,6 @@
       return false;
     }
 
-    DexClass holder = appView.definitionFor(singleTarget.method.holder);
-    if (holder.isInterface()) {
-      // Art978_virtual_interfaceTest correctly expects an IncompatibleClassChangeError exception at
-      // runtime.
-      whyAreYouNotInliningReporter.reportIncompatibleClassChangeError();
-      return false;
-    }
-
     // Don't inline if target is synchronized.
     if (singleTarget.accessFlags.isSynchronized()) {
       whyAreYouNotInliningReporter.reportSynchronizedMethod();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotInliningReporter.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotInliningReporter.java
index 818b8c2..b5c96d4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotInliningReporter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotInliningReporter.java
@@ -43,9 +43,6 @@
   public void reportInaccessible() {}
 
   @Override
-  public void reportIncompatibleClassChangeError() {}
-
-  @Override
   public void reportIncorrectArity(int numberOfArguments, int arity) {}
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java
index c560944..1e869eb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java
@@ -60,8 +60,6 @@
 
   public abstract void reportInaccessible();
 
-  public abstract void reportIncompatibleClassChangeError();
-
   public abstract void reportIncorrectArity(int numberOfArguments, int arity);
 
   public abstract void reportInlineeDoesNotHaveCode();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java
index 6bc09fd..dcc122b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java
@@ -88,11 +88,6 @@
   }
 
   @Override
-  public void reportIncompatibleClassChangeError() {
-    print("invoke may fail with an IncompatibleClassChangeError.");
-  }
-
-  @Override
   public void reportIncorrectArity(int numberOfArguments, int arity) {
     print(
         "number of arguments ("
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
index 7728c1b..2751153 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
@@ -205,7 +205,7 @@
                 invoke.getLocalInfo());
         affectedValues.addAll(invoke.outValue().affectedValues());
         it.replaceCurrentInstruction(new ConstString(newOutValue, resultString, throwingInfo));
-        numberOfSimplifiedConversions++;
+        numberOfSimplifiedOperations++;
         continue;
       }
 
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 4762db0..45f5bed 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -880,6 +880,31 @@
     }
   }
 
+  private DexEncodedMethod validateSingleVirtualTarget(
+      DexEncodedMethod singleTarget, DexEncodedMethod resolutionResult) {
+    assert resolutionResult.isValidVirtualTarget(options());
+
+    if (singleTarget == null || singleTarget == DexEncodedMethod.SENTINEL) {
+      return null;
+    }
+
+    // Art978_virtual_interfaceTest correctly expects an IncompatibleClassChangeError exception
+    // at runtime.
+    if (isInvalidSingleVirtualTarget(singleTarget, resolutionResult)) {
+      return null;
+    }
+
+    return singleTarget;
+  }
+
+  private boolean isInvalidSingleVirtualTarget(
+      DexEncodedMethod singleTarget, DexEncodedMethod resolutionResult) {
+    assert resolutionResult.isValidVirtualTarget(options());
+    // Art978_virtual_interfaceTest correctly expects an IncompatibleClassChangeError exception
+    // at runtime.
+    return !singleTarget.accessFlags.isAtLeastAsVisibleAs(resolutionResult.accessFlags);
+  }
+
   /** For mapping invoke virtual instruction to single target method. */
   public DexEncodedMethod lookupSingleVirtualTarget(DexMethod method, DexType invocationContext) {
     assert checkIfObsolete();
@@ -903,11 +928,13 @@
     if (receiverLowerBoundType != null) {
       if (receiverLowerBoundType.getClassType() == refinedReceiverType) {
         ResolutionResult resolutionResult = resolveMethod(method.holder, method, false);
-        if (resolutionResult.isValidVirtualTargetForDynamicDispatch()) {
+        if (resolutionResult.hasSingleTarget()
+            && resolutionResult.isValidVirtualTargetForDynamicDispatch()) {
           ResolutionResult refinedResolutionResult = resolveMethod(refinedReceiverType, method);
           if (refinedResolutionResult.hasSingleTarget()
               && refinedResolutionResult.isValidVirtualTargetForDynamicDispatch()) {
-            return refinedResolutionResult.asSingleTarget();
+            return validateSingleVirtualTarget(
+                refinedResolutionResult.asSingleTarget(), resolutionResult.asSingleTarget());
           }
         }
         return null;
@@ -942,29 +969,29 @@
     // First get the target for the holder type.
     ResolutionResult topMethod = resolveMethodOnClass(holder, method);
     // We might hit none or multiple targets. Both make this fail at runtime.
-    if (!topMethod.hasSingleTarget() || !topMethod.isValidVirtualTarget(app().options)) {
+    if (!topMethod.hasSingleTarget() || !topMethod.isValidVirtualTarget(options())) {
       method.setSingleVirtualMethodCache(refinedReceiverType, null);
       return null;
     }
     // Now, resolve the target with the refined receiver type.
-    if (refinedReceiverIsStrictSubType) {
-      topMethod = resolveMethodOnClass(refinedHolder, method);
-    }
-    DexEncodedMethod topSingleTarget = topMethod.asSingleTarget();
+    ResolutionResult refinedResolutionResult =
+        refinedReceiverIsStrictSubType ? resolveMethodOnClass(refinedHolder, method) : topMethod;
+    DexEncodedMethod topSingleTarget = refinedResolutionResult.asSingleTarget();
     DexClass topHolder = definitionFor(topSingleTarget.method.holder);
     // We need to know whether the top method is from an interface, as that would allow it to be
     // shadowed by a default method from an interface further down.
     boolean topIsFromInterface = topHolder.isInterface();
     // Now look at all subtypes and search for overrides.
     DexEncodedMethod result =
-        findSingleTargetFromSubtypes(
-            refinedReceiverType,
-            method,
-            topSingleTarget,
-            !refinedHolder.accessFlags.isAbstract(),
-            topIsFromInterface);
-    // Map the failure case of SENTINEL to null.
-    result = result == DexEncodedMethod.SENTINEL ? null : result;
+        validateSingleVirtualTarget(
+            findSingleTargetFromSubtypes(
+                refinedReceiverType,
+                method,
+                topSingleTarget,
+                !refinedHolder.accessFlags.isAbstract(),
+                topIsFromInterface),
+            topMethod.asSingleTarget());
+    assert result != DexEncodedMethod.SENTINEL;
     method.setSingleVirtualMethodCache(refinedReceiverType, result);
     return result;
   }
@@ -1099,11 +1126,13 @@
     if (receiverLowerBoundType != null) {
       if (receiverLowerBoundType.getClassType() == refinedReceiverType) {
         ResolutionResult resolutionResult = resolveMethod(method.holder, method, true);
-        if (resolutionResult.isValidVirtualTargetForDynamicDispatch()) {
+        if (resolutionResult.hasSingleTarget()
+            && resolutionResult.isValidVirtualTargetForDynamicDispatch()) {
           ResolutionResult refinedResolutionResult = resolveMethod(refinedReceiverType, method);
           if (refinedResolutionResult.hasSingleTarget()
               && refinedResolutionResult.isValidVirtualTargetForDynamicDispatch()) {
-            return refinedResolutionResult.asSingleTarget();
+            return validateSingleVirtualTarget(
+                refinedResolutionResult.asSingleTarget(), resolutionResult.asSingleTarget());
           }
         }
         return null;
@@ -1119,11 +1148,8 @@
     }
     // First check that there is a target for this invoke-interface to hit. If there is none,
     // this will fail at runtime.
-    ResolutionResult topTarget = resolveMethodOnInterface(holder, method);
-    if (!topTarget.isValidVirtualTarget(app().options)) {
-      return null;
-    }
-    if (topTarget.asResultOfResolve() == null) {
+    DexEncodedMethod topTarget = resolveMethodOnInterface(holder, method).asSingleTarget();
+    if (topTarget == null || !topTarget.isValidVirtualTarget(options())) {
       return null;
     }
     // For kept types we cannot ensure a single target.
@@ -1152,19 +1178,18 @@
         // override them, so we ignore interface methods here. Otherwise, we would look up
         // default methods that are factually never used.
       } else if (!clazz.accessFlags.isAbstract()) {
-        ResolutionResult resolutionResult = resolveMethodOnClass(clazz, method);
-        if (resolutionResult.hasSingleTarget()) {
-          if ((result != null) && (result != resolutionResult.asSingleTarget())) {
-            return null;
-          } else {
-            result = resolutionResult.asSingleTarget();
-          }
-        } else {
+        DexEncodedMethod resolutionResult = resolveMethodOnClass(clazz, method).asSingleTarget();
+        if (resolutionResult == null || isInvalidSingleVirtualTarget(resolutionResult, topTarget)) {
           // This will fail at runtime.
           return null;
         }
+        if (result != null && result != resolutionResult) {
+          return null;
+        }
+        result = resolutionResult;
       }
     }
+    assert result == null || !isInvalidSingleVirtualTarget(result, topTarget);
     return result == null || !result.isVirtualMethod() ? null : result;
   }
 
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 1d209ea..0689533 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -1786,6 +1786,23 @@
     return liveFields.contains(field);
   }
 
+  public boolean isFieldRead(DexEncodedField field) {
+    FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field.field);
+    return info != null && info.isRead();
+  }
+
+  public boolean isFieldWrittenOutsideDefaultConstructor(DexEncodedField field) {
+    FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field.field);
+    if (info == null) {
+      return false;
+    }
+    DexClass clazz = appView.definitionFor(field.field.holder);
+    DexEncodedMethod defaultInitializer = clazz.getDefaultInitializer();
+    return defaultInitializer != null
+        ? info.isWrittenOutside(defaultInitializer)
+        : info.isWritten();
+  }
+
   private boolean isInstantiatedOrHasInstantiatedSubtype(DexProgramClass clazz) {
     return directAndIndirectlyInstantiatedTypes.contains(clazz);
   }
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
index 1aef50b..21f78a7 100644
--- a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
+++ b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
+import com.android.tools.r8.ir.desugar.DesugaredLibraryWrapperSynthesizer;
 import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
 import com.android.tools.r8.ir.desugar.LambdaRewriter;
 import com.android.tools.r8.ir.desugar.NestBasedAccessDesugaring;
@@ -85,6 +86,7 @@
         || BackportedMethodRewriter.hasRewrittenMethodPrefix(a.type)
         || InterfaceMethodRewriter.hasDispatchClassSuffix(a.type)
         || NestBasedAccessDesugaring.isNestConstructor(a.type)
+        || DesugaredLibraryWrapperSynthesizer.isSynthesizedWrapper(a.type)
         || a.type.descriptor.toString().equals(TwrCloseResourceRewriter.UTILITY_CLASS_DESCRIPTOR);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/classlookup/LibraryClassExtendsProgramClassTest.java b/src/test/java/com/android/tools/r8/classlookup/LibraryClassExtendsProgramClassTest.java
index 231f2c1..5cbb40d 100644
--- a/src/test/java/com/android/tools/r8/classlookup/LibraryClassExtendsProgramClassTest.java
+++ b/src/test/java/com/android/tools/r8/classlookup/LibraryClassExtendsProgramClassTest.java
@@ -5,21 +5,25 @@
 package com.android.tools.r8.classlookup;
 
 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.fail;
-import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.jasmin.JasminBuilder;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
 import java.util.List;
+import java.util.Set;
+import org.hamcrest.CoreMatchers;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -37,6 +41,13 @@
 @RunWith(Parameterized.class)
 public class LibraryClassExtendsProgramClassTest extends TestBase {
 
+  private static String[] libraryClassesExtendingTestCase =
+      new String[] {
+        "android.test.InstrumentationTestCase",
+        "android.test.AndroidTestCase",
+        "android.test.suitebuilder.TestSuiteBuilder$FailedToCreateTests"
+      };
+
   private static List<byte[]> junitClasses;
 
   @BeforeClass
@@ -57,8 +68,15 @@
     this.parameters = parameters;
   }
 
+  // The default library in the test runner is chosen to be the first one with at least the API
+  // level. The junit testing framework was removed in P.
+  private boolean libraryContainsJUnit() {
+    return parameters.isDexRuntime()
+        && parameters.getApiLevel().getLevel() < AndroidApiLevel.P.getLevel();
+  }
+
   private void checkClassesInResult(CodeInspector inspector) {
-    if (parameters.isDexRuntime()) {
+    if (libraryContainsJUnit()) {
       noClassesInResult(inspector);
     } else {
       testCaseClassInResult(inspector);
@@ -76,9 +94,21 @@
     assertThat(inspector.clazz(TestClass.class), isPresent());
   }
 
+  private void checkDiagnostics(List<Diagnostic> diagnostics) {
+    Builder<String> builder = ImmutableSet.builder();
+    for (String libraryClass : libraryClassesExtendingTestCase) {
+      builder.add(
+          "Library class " + libraryClass + " extends program class junit.framework.TestCase");
+    }
+    Set<String> expected = builder.build();
+    for (Diagnostic diagnostic : diagnostics) {
+      assertThat(expected, CoreMatchers.hasItem(diagnostic.getDiagnosticMessage()));
+    }
+    assertEquals(expected.size(), diagnostics.size());
+  }
+
   @Test
   public void testFullMode() throws Exception {
-    assumeFalse(parameters.getApiLevel().getLevel() == 28);
     testForR8(parameters.getBackend())
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(TestClass.class)
@@ -93,7 +123,6 @@
 
   @Test
   public void testCompatibilityMode() throws Exception {
-    assumeFalse(parameters.getApiLevel().getLevel() == 28);
     testForR8Compat(parameters.getBackend())
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(TestClass.class)
@@ -119,56 +148,52 @@
   }
 
   @Test
-  public void testFullModeError() {
-    assumeFalse(parameters.getApiLevel().getLevel() == 28);
-    assumeTrue("Only run for Dex backend", parameters.isDexRuntime());
+  public void testFullModeError() throws Exception {
+    R8FullTestBuilder builder =
+        testForR8(parameters.getBackend())
+            .setMinApi(parameters.getApiLevel())
+            .addProgramClasses(TestClass.class)
+            .addProgramClassFileData(junitClasses)
+            .addKeepAllClassesRule()
+            .addOptionsModification(options -> options.lookupLibraryBeforeProgram = false);
+    if (!libraryContainsJUnit()) {
+      builder.compile().inspect(this::testCaseClassInResult).assertNoMessages();
+      return;
+    }
     try {
-      testForR8(parameters.getBackend())
-          .setMinApi(parameters.getApiLevel())
-          .addProgramClasses(TestClass.class)
-          .addProgramClassFileData(junitClasses)
-          .addKeepAllClassesRule()
-          .addOptionsModification(options -> options.lookupLibraryBeforeProgram = false)
-          .compile();
-      fail("Succeeded in full mode");
+      builder.compileWithExpectedDiagnostics(
+          diagnostics -> {
+            diagnostics.assertOnlyErrors();
+            checkDiagnostics(diagnostics.getErrors());
+          });
+      fail("Expected compilation failure");
     } catch (CompilationFailedException e) {
-      // Ignore.
+      // Expected exception.
     }
   }
 
   @Test
   public void testCompatibilityModeWarning() throws Exception {
-    assumeFalse(parameters.getApiLevel().getLevel() == 28);
-    assumeTrue("Only run for Dex backend", parameters.isDexRuntime());
-    R8TestCompileResult result =
-        testForR8Compat(parameters.getBackend())
-            .setMinApi(parameters.getApiLevel())
-            .addProgramClasses(TestClass.class)
-            .addProgramClassFileData(junitClasses)
-            .addKeepAllClassesRule()
-            .addOptionsModification(options -> options.lookupLibraryBeforeProgram = false)
-            .compile()
-            .assertOnlyWarnings();
-
-    String[] libraryClassesExtendingTestCase = new String[]{
-        "android.test.InstrumentationTestCase",
-        "android.test.AndroidTestCase",
-        "android.test.suitebuilder.TestSuiteBuilder$FailedToCreateTests"
-    };
-
-    result.getDiagnosticMessages().assertWarningsCount(libraryClassesExtendingTestCase.length);
-
-    for (String name : libraryClassesExtendingTestCase) {
-      result
-          .assertWarningMessageThatMatches(
-              containsString(
-                  "Library class " + name + " extends program class junit.framework.TestCase"));
-    }
+    testForR8Compat(parameters.getBackend())
+        .setMinApi(parameters.getApiLevel())
+        .addProgramClasses(TestClass.class)
+        .addProgramClassFileData(junitClasses)
+        .addKeepAllClassesRule()
+        .addOptionsModification(options -> options.lookupLibraryBeforeProgram = false)
+        .compileWithExpectedDiagnostics(
+            diagnostics -> {
+              if (libraryContainsJUnit()) {
+                diagnostics.assertOnlyWarnings();
+                checkDiagnostics(diagnostics.getWarnings());
+              } else {
+                diagnostics.assertNoMessages();
+              }
+            })
+        .inspect(this::testCaseClassInResult);
   }
 
   @Test
   public void testWithDontWarn() throws Exception {
-    assumeTrue("Only run for Dex backend", parameters.isDexRuntime());
     testForR8(parameters.getBackend())
         .setMinApi(parameters.getApiLevel())
         .addProgramClassFileData(junitClasses)
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java
index 9a8bb6b..71cbfcd 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java
@@ -11,8 +11,10 @@
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.ir.desugar.DesugaredLibraryWrapperSynthesizer;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject.JumboStringMode;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -57,8 +59,6 @@
   public void testCustomCollectionD8() throws Exception {
     // TODO(b/142377475).
     Assume.assumeTrue(!shrinkDesugaredLibrary);
-    // TODO(b/142377161).
-    Assume.assumeTrue(parameters.getRuntime().asDex().getVm().isNewerThan(DexVm.ART_4_4_4_HOST));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     D8TestRunResult d8TestRunResult =
         testForD8()
@@ -66,7 +66,9 @@
             .setMinApi(parameters.getApiLevel())
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
             .compile()
-            .inspect(inspector -> this.assertCustomCollectionCallsCorrect(inspector, false))
+            .inspect(inspector -> {
+                this.assertNoWrappers(inspector);
+                this.assertCustomCollectionCallsCorrect(inspector, false);})
             .addDesugaredCoreLibraryRunClassPath(
                 this::buildDesugaredLibrary,
                 parameters.getApiLevel(),
@@ -89,8 +91,6 @@
 
   @Test
   public void testCustomCollectionR8() throws Exception {
-    // TODO(b/142377161).
-    Assume.assumeTrue(parameters.getRuntime().asDex().getVm().isNewerThan(DexVm.ART_4_4_4_HOST));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     R8TestRunResult r8TestRunResult =
         testForR8(Backend.DEX)
@@ -104,7 +104,9 @@
                 })
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
             .compile()
-            .inspect(inspector -> this.assertCustomCollectionCallsCorrect(inspector, true))
+            .inspect(inspector -> {
+              this.assertNoWrappers(inspector);
+              this.assertCustomCollectionCallsCorrect(inspector, true);})
             .addDesugaredCoreLibraryRunClassPath(
                 this::buildDesugaredLibrary,
                 parameters.getApiLevel(),
@@ -125,6 +127,11 @@
     }
   }
 
+  private void assertNoWrappers(CodeInspector inspector) {
+    assertTrue(inspector.allClasses().stream().noneMatch(cl -> cl.getOriginalName().startsWith(
+        DesugaredLibraryWrapperSynthesizer.WRAPPER_PREFIX)));
+  }
+
   private void assertCustomCollectionCallsCorrect(CodeInspector inspector, boolean r8) {
     MethodSubject direct = inspector.clazz(EXECUTOR).uniqueMethodWithName("directTypes");
     // TODO(b/134732760): Due to memberRebinding, R8 is not as precise as D8 regarding
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/conversionTests/MoreFunctionConversionTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/conversionTests/MoreFunctionConversionTest.java
index 80a61e7..fd3af23 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/conversionTests/MoreFunctionConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/conversionTests/MoreFunctionConversionTest.java
@@ -38,12 +38,12 @@
             this::buildDesugaredLibraryWithConversionExtension, AndroidApiLevel.B)
         .addRunClasspathFiles(customLib)
         .run(new DexRuntime(DexVm.ART_9_0_0_HOST), Executor.class)
-        // TODO(clement): Make output reliable and put back expected results.
-        .assertSuccess();
+        .assertSuccessWithOutput(StringUtils.lines("6","6","6","6","6"));
   }
 
   // If we have the exact same lambda in both, but one implements j$..Function and the other
   // java..Function, ART is obviously very confused.
+  // This happens for instance when String::length function is used both in CustomLib and Executor.
   private void assertNoDuplicateLambdas(Path program, Path customLib) throws Exception {
     CodeInspector programInspector = new CodeInspector(program);
     CodeInspector customLibInspector = new CodeInspector(customLib);
@@ -76,30 +76,34 @@
     }
 
     public static void oneParameterReturn() {
-      Function<Object, String> toString = Object::toString;
+      Function<Object, String> toString = getObjectStringConv();
       Function<Object, Integer> oneParam = CustomLibClass.oneParameterReturn(toString);
       System.out.println(oneParam.apply(new Object()));
     }
 
     public static void twoParametersReturn() {
-      Function<Object, String> toString = Object::toString;
+      Function<Object, String> toString = getObjectStringConv();
       Function<String, Integer> length = String::length;
       Function<Object, Integer> twoParam = CustomLibClass.twoParametersReturn(toString, length);
       System.out.println(twoParam.apply(new Object()));
     }
 
     public static void oneParameter() {
-      Function<Object, String> toString = Object::toString;
+      Function<Object, String> toString = getObjectStringConv();
       int res = CustomLibClass.oneParameter(toString);
       System.out.println(res);
     }
 
     public static void twoParameters() {
-      Function<Object, String> toString = Object::toString;
+      Function<Object, String> toString = getObjectStringConv();
       Function<String, Integer> length = String::length;
       int res = CustomLibClass.twoParameters(toString, length);
       System.out.println(res);
     }
+
+    public static Function<Object, String> getObjectStringConv() {
+      return (Object o) -> o.getClass().getSimpleName();
+    }
   }
 
   // This class will be put at compilation time as library and on the runtime class path.
@@ -130,13 +134,14 @@
       return f1.andThen(f2).apply(new Object());
     }
 
-    // Following functions are defined to avoid name collision with the program.
+    // Following functions are defined to avoid name collision with the program. Name collision
+    // happens for instance when String::length function is used both in CustomLib and Executor.
     public static Function<String, Integer> getStringIntConv() {
       return (String s) -> 1 + s.length() - 1;
     }
 
     public static Function<Object, String> getObjectStringConv() {
-      return (Object o) -> "" + o.toString() + "";
+      return (Object o) -> "" + o.getClass().getSimpleName() + "";
     }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/conversionTests/WrapperMergeTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/conversionTests/WrapperMergeTest.java
new file mode 100644
index 0000000..c4d1880
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/conversionTests/WrapperMergeTest.java
@@ -0,0 +1,71 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.corelib.conversionTests;
+
+import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.TestRuntime.DexRuntime;
+import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.ir.desugar.DesugaredLibraryWrapperSynthesizer;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.nio.file.Path;
+import java.util.Arrays;
+import org.junit.Test;
+
+public class WrapperMergeTest extends APIConversionTestBase {
+
+  @Test
+  public void testWrapperMerge() throws Exception {
+    // Multiple wrapper classes have to be merged here.
+    Path path1 = testForD8()
+        .addProgramClasses(Executor1.class)
+        .setMinApi(AndroidApiLevel.B)
+        .enableCoreLibraryDesugaring(AndroidApiLevel.B)
+        .compile()
+        .inspect(this::assertWrappers)
+        .writeToZip();
+    Path path2 = testForD8()
+        .addProgramClasses(Executor2.class)
+        .setMinApi(AndroidApiLevel.B)
+        .enableCoreLibraryDesugaring(AndroidApiLevel.B)
+        .compile()
+        .inspect(this::assertWrappers)
+        .writeToZip();
+    testForD8()
+        .addProgramFiles(path1,path2)
+        .compile()
+        .addDesugaredCoreLibraryRunClassPath(
+            this::buildDesugaredLibraryWithConversionExtension, AndroidApiLevel.B)
+        .run(new DexRuntime(DexVm.ART_9_0_0_HOST), Executor1.class)
+        .assertSuccessWithOutput(
+            StringUtils.lines("[1, 2, 3]"));
+
+  }
+
+  private void assertWrappers(CodeInspector inspector) {
+    assertEquals(2,inspector.allClasses().stream().filter(c -> c.getOriginalName().contains(
+        DesugaredLibraryWrapperSynthesizer.WRAPPER_PREFIX)).count());
+  }
+
+  static class Executor1 {
+
+    public static void main(String[] args) {
+      int[] ints = new int[3];
+      Arrays.setAll(ints,x->x+1);
+      System.out.println(Arrays.toString(ints));
+    }
+  }
+
+  static class Executor2 {
+
+    public static void main(String[] args) {
+      int[] ints = new int[3];
+      Arrays.setAll(ints,x->x+2);
+      System.out.println(Arrays.toString(ints));
+    }
+  }
+
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java
index 26a4f2f..df9ab8d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java
@@ -4,53 +4,58 @@
 
 package com.android.tools.r8.ir.optimize.inliner.interfacemethods;
 
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.DEFAULT_METHOD_PREFIX;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.NeverClassInline;
-import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NeverMerge;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
+@RunWith(Parameterized.class)
 public class InlineDefaultInterfaceMethodTest extends TestBase {
 
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public InlineDefaultInterfaceMethodTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
   @Test
   public void test() throws Exception {
     String expectedOutput = StringUtils.lines("Hello world!");
 
     CodeInspector inspector =
-        testForR8(Backend.DEX)
+        testForR8(parameters.getBackend())
             .addInnerClasses(InlineDefaultInterfaceMethodTest.class)
             .addKeepMainRule(TestClass.class)
-            .setMinApi(AndroidApiLevel.M)
+            .setMinApi(parameters.getApiLevel())
             .enableClassInliningAnnotations()
             .enableMergeAnnotations()
             .noMinification()
-            .run(TestClass.class)
+            .run(parameters.getRuntime(), TestClass.class)
             .assertSuccessWithOutput(expectedOutput)
             .inspector();
 
-    // TODO(b/124017330): interface methods should have been inlined into C.method().
-    ClassSubject classSubject =
-        inspector.clazz(I.class.getTypeName() + COMPANION_CLASS_NAME_SUFFIX);
-    assertThat(classSubject, isPresent());
-    assertThat(classSubject.uniqueMethodWithName(DEFAULT_METHOD_PREFIX + "hello"), isPresent());
-    assertThat(classSubject.uniqueMethodWithName(DEFAULT_METHOD_PREFIX + "space"), isPresent());
-    assertThat(classSubject.uniqueMethodWithName(DEFAULT_METHOD_PREFIX + "world"), isPresent());
+    // After inlining, only one class remains, namely TestClass.
+    assertEquals(1, inspector.allClasses().size());
   }
 
   static class TestClass {
 
     public static void main(String[] args) {
-      C obj = new C();
-      obj.method();
+      new C().method();
     }
   }
 
@@ -73,7 +78,6 @@
   @NeverClassInline
   static class C implements I {
 
-    @NeverInline
     public void method() {
       // invoke-virtual
       hello();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineStaticInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineStaticInterfaceMethodTest.java
index 9eb57fb..49dee4b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineStaticInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineStaticInterfaceMethodTest.java
@@ -4,37 +4,47 @@
 
 package com.android.tools.r8.ir.optimize.inliner.interfacemethods;
 
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
+@RunWith(Parameterized.class)
 public class InlineStaticInterfaceMethodTest extends TestBase {
 
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public InlineStaticInterfaceMethodTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
   @Test
   public void test() throws Exception {
     String expectedOutput = StringUtils.lines("Hello world!");
 
     CodeInspector inspector =
-        testForR8(Backend.DEX)
+        testForR8(parameters.getBackend())
             .addInnerClasses(InlineStaticInterfaceMethodTest.class)
             .addKeepMainRule(TestClass.class)
-            .setMinApi(AndroidApiLevel.M)
-            .run(TestClass.class)
+            .setMinApi(parameters.getApiLevel())
+            .run(parameters.getRuntime(), TestClass.class)
             .assertSuccessWithOutput(expectedOutput)
             .inspector();
 
-    // TODO(b/124017330): greet() should have been inlined into main().
-    ClassSubject classSubject =
-        inspector.clazz(I.class.getTypeName() + COMPANION_CLASS_NAME_SUFFIX);
-    assertThat(classSubject, isPresent());
-    assertThat(classSubject.uniqueMethodWithName("greet"), isPresent());
+    // After inlining of I.greet(), only one class remains, namely TestClass.
+    assertEquals(1, inspector.allClasses().size());
   }
 
   static class TestClass {
diff --git a/tools/r8_release.py b/tools/r8_release.py
index 7ce3582..4d9273c 100755
--- a/tools/r8_release.py
+++ b/tools/r8_release.py
@@ -130,8 +130,6 @@
 
 
 def prepare_google3():
-  utils.check_prodacces()
-
   # Check if an existing client exists.
   if ':update-r8:' in subprocess.check_output('g4 myclients', shell=True):
     print "Remove the existing 'update-r8' client before continuing."
@@ -217,7 +215,7 @@
   result.add_argument('--version',
                       required=True,
                       help='The new version of R8 (e.g., 1.4.51)')
-  result.add_argument('--no_sync',
+  result.add_argument('--no-sync', '--no_sync',
                       default=False,
                       action='store_true',
                       help='Do not sync repos before uploading')
@@ -246,6 +244,9 @@
 def main():
   args = parse_options()
   targets_to_run = []
+  if args.google3 or args.studio:
+    utils.check_prodacces()
+
   if args.google3:
     targets_to_run.append(prepare_google3())
   if args.studio: