Record that singleton fields from lambda merger are definitely-not-null

Change-Id: I01d73730c6dcf0af6a1536000560680dd96d5bfd
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
index ae5e066..f7d423e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
@@ -13,9 +13,9 @@
 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.ir.optimize.info.OptimizationFeedback;
 import com.android.tools.r8.ir.optimize.lambda.CodeProcessor.Strategy;
 import com.android.tools.r8.kotlin.Kotlin;
-import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.ThrowingConsumer;
 import com.google.common.collect.Lists;
 import com.google.common.io.BaseEncoding;
@@ -163,19 +163,22 @@
 
   protected abstract String getGroupSuffix();
 
-  final DexProgramClass synthesizeClass(InternalOptions options) {
+  final DexProgramClass synthesizeClass(
+      AppView<? extends AppInfoWithSubtyping> appView, OptimizationFeedback feedback) {
     assert classType == null;
     assert verifyLambdaIds(true);
     List<LambdaInfo> lambdas = Lists.newArrayList(this.lambdas.values());
     classType =
-        options.itemFactory.createType(
-            "L"
-                + getTypePackage()
-                + "-$$LambdaGroup$"
-                + getGroupSuffix()
-                + createHash(lambdas)
-                + ";");
-    return getBuilder(options.itemFactory).synthesizeClass(options);
+        appView
+            .dexItemFactory()
+            .createType(
+                "L"
+                    + getTypePackage()
+                    + "-$$LambdaGroup$"
+                    + getGroupSuffix()
+                    + createHash(lambdas)
+                    + ";");
+    return getBuilder(appView.dexItemFactory()).synthesizeClass(appView, feedback);
   }
 
   protected abstract LambdaGroupClassBuilder getBuilder(DexItemFactory factory);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
index e569714..2c4315c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.ir.optimize.lambda;
 
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ClassAccessFlags;
 import com.android.tools.r8.graph.DexAnnotationSet;
 import com.android.tools.r8.graph.DexEncodedField;
@@ -14,8 +16,8 @@
 import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.EnclosingMethodAttribute;
 import com.android.tools.r8.graph.InnerClassAttribute;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
 import com.android.tools.r8.origin.SynthesizedOrigin;
-import com.android.tools.r8.utils.InternalOptions;
 import java.util.Collections;
 import java.util.List;
 
@@ -32,7 +34,8 @@
     this.origin = origin;
   }
 
-  public final DexProgramClass synthesizeClass(InternalOptions options) {
+  public final DexProgramClass synthesizeClass(
+      AppView<? extends AppInfoWithSubtyping> appView, OptimizationFeedback feedback) {
     DexType groupClassType = group.getGroupClassType();
     DexType superClassType = getSuperClassType();
     DexProgramClass programClass =
@@ -49,7 +52,7 @@
             buildEnclosingMethodAttribute(),
             buildInnerClasses(),
             buildAnnotations(),
-            buildStaticFields(),
+            buildStaticFields(appView, feedback),
             buildInstanceFields(),
             buildDirectMethods(),
             buildVirtualMethods(),
@@ -75,7 +78,8 @@
 
   protected abstract DexEncodedField[] buildInstanceFields();
 
-  protected abstract DexEncodedField[] buildStaticFields();
+  protected abstract DexEncodedField[] buildStaticFields(
+      AppView<? extends AppInfoWithSubtyping> appView, OptimizationFeedback feedback);
 
   protected abstract DexTypeList buildInterfaces();
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
index 3bb09ce..9981290 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
@@ -326,7 +326,7 @@
 
     // Remove invalidated lambdas, compact groups to ensure
     // sequential lambda ids, create group lambda classes.
-    BiMap<LambdaGroup, DexProgramClass> lambdaGroupsClasses = finalizeLambdaGroups();
+    BiMap<LambdaGroup, DexProgramClass> lambdaGroupsClasses = finalizeLambdaGroups(feedback);
 
     // Fixup optimization info to ensure that the optimization info does not refer to any merged
     // lambdas.
@@ -388,7 +388,7 @@
     ThreadUtils.awaitFutures(futures);
   }
 
-  private BiMap<LambdaGroup, DexProgramClass> finalizeLambdaGroups() {
+  private BiMap<LambdaGroup, DexProgramClass> finalizeLambdaGroups(OptimizationFeedback feedback) {
     for (DexType lambda : invalidatedLambdas) {
       LambdaGroup group = lambdas.get(lambda);
       assert group != null;
@@ -405,7 +405,7 @@
     for (LambdaGroup group : groups.values()) {
       assert !group.isTrivial() : "No trivial group is expected here.";
       group.compact();
-      DexProgramClass lambdaGroupClass = group.synthesizeClass(appView.options());
+      DexProgramClass lambdaGroupClass = group.synthesizeClass(appView, feedback);
       result.put(group, lambdaGroupClass);
     }
     return result;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupClassBuilder.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupClassBuilder.java
index 15d4160..74a5236 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupClassBuilder.java
@@ -4,11 +4,16 @@
 
 package com.android.tools.r8.ir.optimize.lambda.kotlin;
 
+import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
+
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ClassAccessFlags;
 import com.android.tools.r8.graph.DexAnnotation;
 import com.android.tools.r8.graph.DexAnnotationSet;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
@@ -20,7 +25,9 @@
 import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.ir.analysis.type.ClassTypeLatticeElement;
 import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
 import com.android.tools.r8.ir.optimize.lambda.LambdaGroupClassBuilder;
 import com.android.tools.r8.ir.synthetic.SynthesizedCode;
 import com.android.tools.r8.ir.synthetic.SyntheticSourceCode;
@@ -212,18 +219,30 @@
   }
 
   @Override
-  protected DexEncodedField[] buildStaticFields() {
+  protected DexEncodedField[] buildStaticFields(
+      AppView<? extends AppInfoWithSubtyping> appView, OptimizationFeedback feedback) {
     if (!group.isStateless()) {
       return DexEncodedField.EMPTY_ARRAY;
     }
     // One field for each singleton lambda in the group.
     List<DexEncodedField> result = new ArrayList<>(group.size());
-    group.forEachLambda(info -> {
-      if (group.isSingletonLambda(info.clazz.type)) {
-        result.add(new DexEncodedField(group.getSingletonInstanceField(factory, info.id),
-            SINGLETON_FIELD_FLAGS, DexAnnotationSet.empty(), DexValueNull.NULL));
-      }
-    });
+    group.forEachLambda(
+        info -> {
+          if (group.isSingletonLambda(info.clazz.type)) {
+            DexField field = group.getSingletonInstanceField(factory, info.id);
+            DexEncodedField encodedField =
+                new DexEncodedField(
+                    field, SINGLETON_FIELD_FLAGS, DexAnnotationSet.empty(), DexValueNull.NULL);
+            result.add(encodedField);
+
+            // Record that the field is definitely not null. It is guaranteed to be assigned in the
+            // class initializer of the enclosing class before it is read.
+            ClassTypeLatticeElement exactType =
+                ClassTypeLatticeElement.create(field.type, definitelyNotNull(), appView);
+            feedback.markFieldHasDynamicLowerBoundType(encodedField, exactType);
+            feedback.markFieldHasDynamicUpperBoundType(encodedField, exactType);
+          }
+        });
     assert result.isEmpty() == !group.hasAnySingletons();
     return result.toArray(DexEncodedField.EMPTY_ARRAY);
   }