Merge commit '33ae86d80351efc4d632452331d06cb97e42f2a7' into dev-release
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
index b288d9a..a6384e1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
@@ -24,7 +24,6 @@
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.DesugarDescription;
-import com.android.tools.r8.ir.desugar.DesugarDescription.ScanCallback;
 import com.android.tools.r8.ir.desugar.FreshLocalProvider;
 import com.android.tools.r8.ir.desugar.LocalStackAllocator;
 import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations;
@@ -106,46 +105,46 @@
                 getThrowInstructions(
                     appView,
                     invoke,
+                    resolutionResult,
                     localStackAllocator,
                     eventConsumer,
                     context,
-                    methodProcessingContext,
-                    getMethodSynthesizerForThrowing(appView, invoke, resolutionResult, context)))
+                    methodProcessingContext))
         .build();
   }
 
-  public static DesugarDescription computeInvokeAsThrowNSMERewrite(
-      AppView<?> appView, CfInvoke invoke, ScanCallback scanCallback) {
-    DesugarDescription.Builder builder =
-        DesugarDescription.builder()
-            .setDesugarRewrite(
-                (freshLocalProvider,
-                    localStackAllocator,
-                    eventConsumer,
-                    context,
-                    methodProcessingContext,
-                    dexItemFactory) ->
-                    getThrowInstructions(
-                        appView,
-                        invoke,
-                        localStackAllocator,
-                        eventConsumer,
-                        context,
-                        methodProcessingContext,
-                        UtilityMethodsForCodeOptimizations
-                            ::synthesizeThrowNoSuchMethodErrorMethod));
-    builder.addScanEffect(scanCallback);
-    return builder.build();
-  }
-
   private static Collection<CfInstruction> getThrowInstructions(
       AppView<?> appView,
       CfInvoke invoke,
+      MethodResolutionResult resolutionResult,
       LocalStackAllocator localStackAllocator,
       CfInstructionDesugaringEventConsumer eventConsumer,
       ProgramMethod context,
-      MethodProcessingContext methodProcessingContext,
-      MethodSynthesizerConsumer methodSynthesizerConsumer) {
+      MethodProcessingContext methodProcessingContext) {
+    MethodSynthesizerConsumer methodSynthesizerConsumer = null;
+    if (resolutionResult == null) {
+      methodSynthesizerConsumer =
+          UtilityMethodsForCodeOptimizations::synthesizeThrowNoSuchMethodErrorMethod;
+    } else if (resolutionResult.isSingleResolution()) {
+      if (resolutionResult.getResolvedMethod().isStatic() != invoke.isInvokeStatic()) {
+        methodSynthesizerConsumer =
+            UtilityMethodsForCodeOptimizations::synthesizeThrowIncompatibleClassChangeErrorMethod;
+      }
+    } else if (resolutionResult.isFailedResolution()) {
+      FailedResolutionResult failedResolutionResult = resolutionResult.asFailedResolution();
+      AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
+      if (failedResolutionResult.isIllegalAccessErrorResult(context.getHolder(), appInfo)) {
+        methodSynthesizerConsumer =
+            UtilityMethodsForCodeOptimizations::synthesizeThrowIllegalAccessErrorMethod;
+      } else if (failedResolutionResult.isNoSuchMethodErrorResult(context.getHolder(), appInfo)) {
+        methodSynthesizerConsumer =
+            UtilityMethodsForCodeOptimizations::synthesizeThrowNoSuchMethodErrorMethod;
+      } else if (failedResolutionResult.isIncompatibleClassChangeErrorResult()) {
+        methodSynthesizerConsumer =
+            UtilityMethodsForCodeOptimizations::synthesizeThrowIncompatibleClassChangeErrorMethod;
+      }
+    }
+
     if (methodSynthesizerConsumer == null) {
       assert false;
       return null;
@@ -199,32 +198,4 @@
     }
     return replacement;
   }
-
-  private static MethodSynthesizerConsumer getMethodSynthesizerForThrowing(
-      AppView<?> appView,
-      CfInvoke invoke,
-      MethodResolutionResult resolutionResult,
-      ProgramMethod context) {
-    if (resolutionResult == null) {
-      return UtilityMethodsForCodeOptimizations::synthesizeThrowNoSuchMethodErrorMethod;
-    } else if (resolutionResult.isSingleResolution()) {
-      if (resolutionResult.getResolvedMethod().isStatic() != invoke.isInvokeStatic()) {
-        return UtilityMethodsForCodeOptimizations
-            ::synthesizeThrowIncompatibleClassChangeErrorMethod;
-      }
-    } else if (resolutionResult.isFailedResolution()) {
-      FailedResolutionResult failedResolutionResult = resolutionResult.asFailedResolution();
-      AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
-      if (failedResolutionResult.isIllegalAccessErrorResult(context.getHolder(), appInfo)) {
-        return UtilityMethodsForCodeOptimizations::synthesizeThrowIllegalAccessErrorMethod;
-      } else if (failedResolutionResult.isNoSuchMethodErrorResult(context.getHolder(), appInfo)) {
-        return UtilityMethodsForCodeOptimizations::synthesizeThrowNoSuchMethodErrorMethod;
-      } else if (failedResolutionResult.isIncompatibleClassChangeErrorResult()) {
-        return UtilityMethodsForCodeOptimizations
-            ::synthesizeThrowIncompatibleClassChangeErrorMethod;
-      }
-    }
-
-    return null;
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index 8e8541b..bc8ebd0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -44,7 +44,6 @@
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.MethodPosition;
 import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
 import com.android.tools.r8.utils.structural.Ordered;
 import com.google.common.collect.Iterables;
@@ -712,23 +711,7 @@
       }
     }
 
-    DesugarDescription emulatedInterfaceDesugaring =
-        computeEmulatedInterfaceInvokeSpecial(clazz, invokedMethod, context);
-    if (!emulatedInterfaceDesugaring.needsDesugaring() && context.isDefaultMethod()) {
-      return AlwaysThrowingInstructionDesugaring.computeInvokeAsThrowNSMERewrite(
-          appView,
-          invoke,
-          () ->
-              appView
-                  .reporter()
-                  .warning(
-                      new StringDiagnostic(
-                          "Interface method desugaring has inserted NoSuchMethodError replacing a"
-                              + " super call in "
-                              + context.toSourceString(),
-                          context.getOrigin())));
-    }
-    return emulatedInterfaceDesugaring;
+    return computeEmulatedInterfaceInvokeSpecial(clazz, invokedMethod, context);
   }
 
   private DesugarDescription computeEmulatedInterfaceInvokeSpecial(
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 295dc47..f7d3e74 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -3923,10 +3923,31 @@
       }
     }
 
+    BiConsumer<LambdaClass, ProgramMethod> lambdaCallback = this::recordLambdaSynthesizingContext;
+    // TODO(b/233868787): If a lambda implements unknown interfaces its methods won't be live and if
+    //  the tree-pruner is disabled they won't be removed. Workaround this by making them live.
+    if (!options.isShrinking()) {
+      lambdaCallback =
+          lambdaCallback.andThen(
+              (clazz, context) -> {
+                for (DexType itf : clazz.getLambdaProgramClass().getInterfaces()) {
+                  if (definitionFor(itf, context) == null) {
+                    for (ProgramMethod method :
+                        clazz.getLambdaProgramClass().virtualProgramMethods()) {
+                      synchronized (additions) {
+                        additions.addLiveMethod(method);
+                      }
+                    }
+                    break;
+                  }
+                }
+              });
+    }
+
     R8CfInstructionDesugaringEventConsumer eventConsumer =
         CfInstructionDesugaringEventConsumer.createForR8(
             appView,
-            this::recordLambdaSynthesizingContext,
+            lambdaCallback,
             this::recordConstantDynamicSynthesizingContext,
             this::recordTwrCloseResourceMethodSynthesizingContext,
             additions,
diff --git a/src/test/java/com/android/tools/r8/debuginfo/Regress233857593Test.java b/src/test/java/com/android/tools/r8/debuginfo/Regress233857593Test.java
new file mode 100644
index 0000000..d786a12
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/Regress233857593Test.java
@@ -0,0 +1,58 @@
+// Copyright (c) 2022, 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.debuginfo;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class Regress233857593Test extends TestBase {
+
+  @Parameter() public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static List<Object[]> data() {
+    return buildParameters(getTestParameters().withDexRuntimes().withAllApiLevels().build());
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    testForD8(parameters.getBackend())
+        .addProgramClasses(TestClass.class)
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspect(
+            // TODO(b/233857593): There used to be only one goto.
+            inspector -> {
+              assertEquals(
+                  2,
+                  inspector
+                      .clazz(TestClass.class)
+                      .uniqueMethodWithName("testLoopPhiWithNullFirstInput")
+                      .streamInstructions()
+                      .filter(InstructionSubject::isGoto)
+                      .count());
+            });
+  }
+
+  static class TestClass {
+    private void testLoopPhiWithNullFirstInput(boolean cond) {
+      TestClass a = null;
+      while (a == null) {
+        if (cond) {
+          a = new TestClass();
+        }
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultMethodInvokeSuperOnDefaultLibraryMethodTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultMethodInvokeSuperOnDefaultLibraryMethodTest.java
deleted file mode 100644
index 0cb64c8..0000000
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultMethodInvokeSuperOnDefaultLibraryMethodTest.java
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright (c) 2022, 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.desugaring.interfacemethods;
-
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
-import static org.hamcrest.CoreMatchers.allOf;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
-
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.errors.InterfaceDesugarMissingTypeDiagnostic;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.StringDiagnostic;
-import com.android.tools.r8.utils.StringUtils;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.function.Consumer;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class DefaultMethodInvokeSuperOnDefaultLibraryMethodTest extends TestBase {
-
-  @Parameter() public TestParameters parameters;
-
-  @Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withDexRuntimes().build();
-  }
-
-  private static final String EXPECTED_OUTPUT = StringUtils.lines("1", "2");
-
-  private boolean runtimeHasConsumerInterface(TestParameters parameters) {
-    // java,util.function.Consumer was introduced at API level 24.
-    return parameters.asDexRuntime().getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N);
-  }
-
-  @Test
-  public void testD8WithDefaultInterfaceMethodDesugaringWithAPIInLibrary() throws Exception {
-    testForD8(parameters.getBackend())
-        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
-        .addInnerClasses(getClass())
-        .setMinApi(AndroidApiLevel.I_MR1)
-        .compileWithExpectedDiagnostics(
-            diagnostics ->
-                diagnostics
-                    .assertOnlyWarnings()
-                    .assertWarningsMatch(
-                        allOf(
-                            diagnosticType(StringDiagnostic.class),
-                            diagnosticMessage(
-                                containsString(
-                                    "Interface method desugaring has inserted NoSuchMethodError"
-                                        + " replacing a super call in")),
-                            diagnosticMessage(containsString("forEachPrint")))))
-        .run(parameters.getRuntime(), TestClass.class)
-        .applyIf(
-            // If the platform does not have java.util.function.Consumer the lambda instantiation
-            // will throw NoClassDefFoundError as it implements java.util.function.Consumer.
-            // Otherwise, the generated code will throw NoSuchMethodError.
-            runtimeHasConsumerInterface(parameters),
-            b -> b.assertFailureWithErrorThatThrows(NoSuchMethodError.class),
-            b -> b.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
-  }
-
-  @Test
-  public void testD8WithDefaultInterfaceMethodDesugaringWithoutAPIInLibrary() throws Exception {
-    testForD8(parameters.getBackend())
-        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.M))
-        .addInnerClasses(getClass())
-        .setMinApi(AndroidApiLevel.I_MR1)
-        .compileWithExpectedDiagnostics(
-            diagnostics ->
-                diagnostics
-                    .assertOnlyWarnings()
-                    .assertWarningsMatch(
-                        diagnosticType(InterfaceDesugarMissingTypeDiagnostic.class)))
-        .run(parameters.getRuntime(), TestClass.class)
-        .applyIf(
-            // If the platform does not have java.util.function.Consumer the lambda instantiation
-            // will throw NoClassDefFoundError as it implements java.util.function.Consumer.
-            // Otherwise, the generated code will throw NoSuchMethodError.
-            runtimeHasConsumerInterface(parameters),
-            b -> b.assertFailureWithErrorThatThrows(NoSuchMethodError.class),
-            b -> b.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
-  }
-
-  @Test
-  public void testD8WithDefaultInterfaceMethodSupport() throws Exception {
-    assumeTrue(
-        parameters.asDexRuntime().getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N));
-    testForD8(parameters.getBackend())
-        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
-        .addInnerClasses(getClass())
-        .setMinApi(AndroidApiLevel.N)
-        .run(parameters.getRuntime(), TestClass.class)
-        .assertSuccessWithOutput(EXPECTED_OUTPUT);
-  }
-
-  @Test
-  public void testR8WithDefaultInterfaceMethodDesugaringWithAPIInLibrary() throws Exception {
-    testForR8(parameters.getBackend())
-        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
-        .addInnerClasses(getClass())
-        .setMinApi(AndroidApiLevel.I_MR1)
-        .addKeepMainRule(TestClass.class)
-        .run(parameters.getRuntime(), TestClass.class)
-        .assertFailureWithErrorThatThrows(NoSuchMethodError.class);
-  }
-
-  @Test
-  public void testR8WithDefaultInterfaceMethodDesugaringWithoutAPIInLibrary() throws Exception {
-    testForR8(parameters.getBackend())
-        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.M))
-        .addInnerClasses(getClass())
-        .setMinApi(AndroidApiLevel.I_MR1)
-        .addKeepMainRule(TestClass.class)
-        .addDontWarn(Consumer.class)
-        .run(parameters.getRuntime(), TestClass.class)
-        .applyIf(
-            // If the platform does not have java.util.function.Consumer the lambda instantiation
-            // will throw NoClassDefFoundError as it implements java.util.function.Consumer.
-            // Otherwise, the generated code will throw NoSuchMethodError.
-            runtimeHasConsumerInterface(parameters),
-            b -> b.assertFailureWithErrorThatThrows(NoSuchMethodError.class),
-            b -> b.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
-  }
-
-  @Test
-  public void testR8WithDefaultInterfaceMethodSupport() throws Exception {
-    assumeTrue(
-        parameters.asDexRuntime().getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N));
-    testForR8(parameters.getBackend())
-        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
-        .addInnerClasses(getClass())
-        .setMinApi(AndroidApiLevel.N)
-        .addKeepMainRule(TestClass.class)
-        .run(parameters.getRuntime(), TestClass.class)
-        .assertSuccessWithOutput(EXPECTED_OUTPUT);
-  }
-
-  interface IntegerIterable extends Iterable<Integer> {
-    default void forEachPrint() {
-      Iterable.super.forEach(System.out::println);
-    }
-  }
-
-  static class IntegerIterable1And2 implements IntegerIterable {
-
-    @Override
-    public Iterator<Integer> iterator() {
-      List<Integer> result = new ArrayList<>();
-      result.add(1);
-      result.add(2);
-      return result.iterator();
-    }
-  }
-
-  static class TestClass {
-
-    public static void main(String[] args) {
-      new IntegerIterable1And2().forEachPrint();
-    }
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/regress/UndefinedLambdaInterfaceRegress232379893.java b/src/test/java/com/android/tools/r8/regress/UndefinedLambdaInterfaceRegress232379893.java
new file mode 100644
index 0000000..b27e96a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/regress/UndefinedLambdaInterfaceRegress232379893.java
@@ -0,0 +1,62 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.regress;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class UndefinedLambdaInterfaceRegress232379893 extends TestBase {
+
+  static final String EXPECTED = StringUtils.lines("Hello, world");
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+  }
+
+  public UndefinedLambdaInterfaceRegress232379893(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(TestClass.class)
+        .addProgramClassesAndInnerClasses(UserOfUndefinedInterface.class)
+        .addKeepMainRule(TestClass.class)
+        .addDontWarn(UndefinedInterface.class)
+        .addDontShrink()
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  interface UndefinedInterface {
+    void foo();
+  }
+
+  static class UserOfUndefinedInterface {
+    public static void bar(UndefinedInterface i) {
+      throw new RuntimeException("unused method");
+    }
+  }
+
+  static class TestClass {
+    public static void main(String[] args) {
+      if (System.nanoTime() < 0) {
+        UserOfUndefinedInterface.bar(() -> System.out.println("unused lambda"));
+      } else {
+        System.out.println("Hello, world");
+      }
+    }
+  }
+}