Version 1.4.70

Cherry pick: Stopgap of NPE when searching for the definition of synthesized class.
CL: https://r8-review.googlesource.com/c/r8/+/33961

Cherry pick (partial): Use up-to-date AppInfo in IRConverter.
CL: https://r8-review.googlesource.com/c/r8/+/35363

Bug: 127762980
Change-Id: I0752d6d32bf31407a495dd9f080216433dc32e95
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index bfadd2c..30d9b3b 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 = "1.4.69";
+  public static final String LABEL = "1.4.70";
 
   private Version() {
   }
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 db83f6a..d3548c8 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -25,7 +25,7 @@
       new ConcurrentHashMap<>();
   // For some optimizations, e.g. optimizing synthetic classes, we may need to resolve the current
   // class being optimized.
-  private ConcurrentHashMap<DexType, DexProgramClass> synthesizedClasses =
+  private final ConcurrentHashMap<DexType, DexProgramClass> synthesizedClasses =
       new ConcurrentHashMap<>();
 
   public AppInfo(DexApplication application) {
@@ -37,6 +37,7 @@
     this.app = previous.app;
     this.dexItemFactory = app.dexItemFactory;
     this.definitions.putAll(previous.definitions);
+    this.synthesizedClasses.putAll(previous.synthesizedClasses);
   }
 
   protected AppInfo(DirectMappedDexApplication application, GraphLense lense) {
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 1a880f6..9368a79 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -12,11 +12,12 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.ir.desugar.Java8MethodRewriter;
 import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
+import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
-import com.google.common.collect.ImmutableList;
 import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
@@ -169,6 +170,13 @@
   }
 
   public boolean isStrictSubtypeOf(DexType other, AppInfo appInfo) {
+    // For all erroneous cases, saying `no`---not a strict subtype---is conservative.
+    return isStrictSubtypeOf(other, appInfo, false);
+  }
+
+  // Depending on optimizations, conservative answer of subtype relation may vary.
+  // Pass different `orElse` in that case.
+  public boolean isStrictSubtypeOf(DexType other, AppInfo appInfo, boolean orElse) {
     if (this == other) {
       return false;
     }
@@ -187,7 +195,7 @@
       return other.directSubtypes.stream().anyMatch(subtype -> this.isSubtypeOf(subtype,
           appInfo));
     }
-    return isSubtypeOfClass(other, appInfo);
+    return isSubtypeOfClass(other, appInfo, orElse);
   }
 
   private boolean isInterfaceSubtypeOf(DexType candidate, DexType other, AppInfo appInfo) {
@@ -207,15 +215,22 @@
     return false;
   }
 
-  private boolean isSubtypeOfClass(DexType other, AppInfo appInfo) {
+  private boolean isSubtypeOfClass(DexType other, AppInfo appInfo, boolean orElse) {
     DexType self = this;
     if (other.hierarchyLevel == UNKNOWN_LEVEL) {
-      // We have no definition for this class, hence it is not part of the
-      // hierarchy.
-      return false;
+      // We have no definition for this class, hence it is not part of the hierarchy.
+      return orElse;
     }
     while (other.hierarchyLevel < self.hierarchyLevel) {
       DexClass holder = appInfo.definitionFor(self);
+      // TODO(b/113374256): even synthesized class should be available ATM.
+      if (holder == null) {
+        assert self.isD8R8SynthesizedClassType();
+        if (Log.ENABLED) {
+          Log.debug(getClass(), "%s is not in AppInfo yet.", self.toSourceString());
+        }
+        return orElse;
+      }
       assert holder != null && !holder.isInterface();
       self = holder.superType;
     }
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinLambdaMergingWithReprocessingTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinLambdaMergingWithReprocessingTest.java
new file mode 100644
index 0000000..25cb8f94
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinLambdaMergingWithReprocessingTest.java
@@ -0,0 +1,26 @@
+// 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.kotlin;
+
+import com.android.tools.r8.utils.InternalOptions;
+import java.util.function.Consumer;
+import org.junit.Test;
+
+public class KotlinLambdaMergingWithReprocessingTest extends AbstractR8KotlinTestBase {
+
+  private Consumer<InternalOptions> optionsModifier =
+      o -> {
+        o.enableTreeShaking = true;
+        o.enableMinification = false;
+        o.enableInlining = true;
+        o.enableClassInlining = true;
+        o.enableLambdaMerging = true;
+      };
+
+  @Test
+  public void testMergingKStyleLambdasAndReprocessing() throws Exception {
+    final String mainClassName = "reprocess_merged_lambdas_kstyle.MainKt";
+    runTest("reprocess_merged_lambdas_kstyle", mainClassName, optionsModifier, null);
+  }
+}