Version 2.1.61

Cherry pick: Reproduce NPE from missing AppInfoWithLiveness rewriting
CL: https://r8-review.googlesource.com/c/r8/+/52765

Cherry pick: Rewrite AppInfoWithLiveness using LambdaRewriterLens
CL: https://r8-review.googlesource.com/c/r8/+/52766

This also cherry-picks part of 'Do not apply the graph lens to positions' at https://r8-review.googlesource.com/c/r8/+/52380, specifically the part that introduces LambdaRewriterLense in LambdaRewriter.java.

Bug: 161735546
Change-Id: I92ef83f646d6681956438917e5331bbbeed39d65
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 80f8371..e3becb5 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -700,7 +700,8 @@
                       executorService,
                       timing)
                   .withEnumValueInfoMaps(enumValueInfoMapCollection));
-
+          // Rerunning the enqueuer should not give rise to any method rewritings.
+          assert enqueuer.buildGraphLens(appView) == null;
           appView.withGeneratedMessageLiteBuilderShrinker(
               shrinker ->
                   shrinker.rewriteDeadBuilderReferencesFromDynamicMethods(
@@ -917,6 +918,14 @@
                 options.getProguardConfiguration().getDontWarnPatterns(),
                 executorService,
                 timing));
+    NestedGraphLense lens = enqueuer.buildGraphLens(appView);
+    if (lens != null) {
+      appView.setGraphLense(lens);
+      appViewWithLiveness.setAppInfo(
+          appViewWithLiveness
+              .appInfo()
+              .rewrittenWithLens(appView.appInfo().app().asDirect(), lens));
+    }
     if (InternalOptions.assertionsEnabled()) {
       // Register the dead proto types. These are needed to verify that no new missing types are
       // reported and that no dead proto types are referenced in the generated application.
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 1f7c9d4..571ec73 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
 
   // This field is accessed from release scripts using simple pattern matching.
   // Therefore, changing this field could break our release scripts.
-  public static final String LABEL = "2.1.60";
+  public static final String LABEL = "2.1.61";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
index 8a7b983..0b83e0f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
@@ -7,10 +7,13 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexApplication.Builder;
 import com.android.tools.r8.graph.DexCallSite;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
@@ -29,6 +32,7 @@
 import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
 import com.google.common.collect.BiMap;
 import com.google.common.collect.HashBiMap;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
@@ -342,4 +346,34 @@
   public Map<DexType, LambdaClass> getKnownLambdaClasses() {
     return knownLambdaClasses;
   }
+
+  public NestedGraphLense buildMappingLens(AppView<?> appView) {
+    if (originalMethodSignatures.isEmpty()) {
+      return null;
+    }
+    return new LambdaRewriterLens(
+        originalMethodSignatures, appView.graphLense(), appView.dexItemFactory());
+  }
+
+  static class LambdaRewriterLens extends NestedGraphLense {
+
+    public LambdaRewriterLens(
+        BiMap<DexMethod, DexMethod> originalMethodSignatures,
+        GraphLense graphLens,
+        DexItemFactory factory) {
+      super(
+          ImmutableMap.of(),
+          ImmutableMap.of(),
+          ImmutableMap.of(),
+          null,
+          originalMethodSignatures,
+          graphLens,
+          factory);
+    }
+
+    @Override
+    protected boolean isLegitimateToHaveEmptyMappings() {
+      return true;
+    }
+  }
 }
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 08d6abf..fead6b8 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -57,6 +57,7 @@
 import com.android.tools.r8.graph.FieldAccessInfoCollectionImpl;
 import com.android.tools.r8.graph.FieldAccessInfoImpl;
 import com.android.tools.r8.graph.FieldResolutionResult;
+import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
 import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.graph.LookupLambdaTarget;
 import com.android.tools.r8.graph.LookupTarget;
@@ -2642,6 +2643,10 @@
     return appInfoWithLiveness;
   }
 
+  public NestedGraphLense buildGraphLens(AppView<?> appView) {
+    return lambdaRewriter != null ? lambdaRewriter.buildMappingLens(appView) : null;
+  }
+
   public boolean isPinned(DexReference reference) {
     return pinnedItems.contains(reference);
   }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/B161735546.java b/src/test/java/com/android/tools/r8/ir/optimize/B161735546.java
new file mode 100644
index 0000000..ce969b7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/B161735546.java
@@ -0,0 +1,66 @@
+// 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.ir.optimize;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class B161735546 extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public B161735546(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(B161735546.class)
+        .addKeepMainRule(TestClass.class)
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("1", "2", "3");
+  }
+
+  static class TestClass {
+    public static void main(String[] args) {
+      new CounterUtils() {}.add(new Counter(), 3);
+    }
+  }
+
+  static class Counter {
+    int i = 0;
+  }
+
+  interface CounterConsumer {
+    void accept(Counter counter);
+  }
+
+  interface CounterUtils {
+    default void add(Counter counter, int i) {
+      if (i == 0) {
+        return;
+      }
+      CounterConsumer continuation =
+          c -> {
+            System.out.println(++counter.i);
+            add(counter, i - 1);
+          };
+      continuation.accept(counter);
+    }
+  }
+}