Fix nullability flop for definitely null nullability.

Bug: 141654799
Change-Id: I59fe263e975b79049098d6938462c92cee355485
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/Nullability.java b/src/main/java/com/android/tools/r8/ir/analysis/type/Nullability.java
index 11c1c8c..26b9030 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/Nullability.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/Nullability.java
@@ -58,6 +58,19 @@
     return MAYBE_NULL;
   }
 
+  public Nullability meet(Nullability other) {
+    if (this == MAYBE_NULL) {
+      return other;
+    }
+    if (other == MAYBE_NULL) {
+      return this;
+    }
+    if (this == other) {
+      return this;
+    }
+    return BOTTOM;
+  }
+
   public boolean lessThanOrEqual(Nullability other) {
     return join(other) == other;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeLatticeElement.java
index 8e42de0..f6af1f7 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeLatticeElement.java
@@ -75,8 +75,8 @@
 
   public abstract ReferenceTypeLatticeElement getOrCreateVariant(Nullability nullability);
 
-  public TypeLatticeElement asNotNull() {
-    return getOrCreateVariant(Nullability.definitelyNotNull());
+  public TypeLatticeElement asMeetWithNotNull() {
+    return getOrCreateVariant(nullability.meet(Nullability.definitelyNotNull()));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Assume.java b/src/main/java/com/android/tools/r8/ir/code/Assume.java
index 05ff7a1..9ba29fd 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Assume.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Assume.java
@@ -241,7 +241,7 @@
     }
     if (assumption.isAssumeNonNull()) {
       assert src().getTypeLattice().isReference();
-      return src().getTypeLattice().asReferenceTypeLatticeElement().asNotNull();
+      return src().getTypeLattice().asReferenceTypeLatticeElement().asMeetWithNotNull();
     }
     throw new Unimplemented();
   }
@@ -280,7 +280,7 @@
       assert isAssumeNonNull() : this;
       assert inType.isReference() : inType;
       assert inType.isNullType()
-          || outType.equals(inType.asReferenceTypeLatticeElement().asNotNull())
+          || outType.equals(inType.asReferenceTypeLatticeElement().asMeetWithNotNull())
               : "At " + this + System.lineSeparator() + outType + " != " + inType;
     }
     return true;
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index 2881de7..4105077 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -1142,9 +1142,9 @@
     //   i.e., towards something wider.
     assert this.typeLattice.lessThanOrEqual(newType, appView)
         : "During WIDENING, "
-            + typeLattice
-            + " < "
             + newType
+            + " < "
+            + typeLattice
             + " at "
             + (isPhi() ? asPhi().printPhi() : definition.toString());
     setTypeLattice(newType);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java b/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java
index 45f8c45..8d3f18f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java
@@ -197,12 +197,12 @@
       } else {
         specializedArg = originalArg;
       }
+      assert specializedArg != null && specializedArg.getTypeLattice().isReference();
       if (dynamicType.isDefinitelyNotNull()) {
         // If we already knew `arg` is never null, e.g., receiver, skip adding non-null.
         if (!specializedArg.getTypeLattice().isDefinitelyNotNull()) {
-          Value nonNullArg =
-              code.createValue(
-                  specializedArg.getTypeLattice().asReferenceTypeLatticeElement().asNotNull());
+          Value nonNullArg = code.createValue(
+              specializedArg.getTypeLattice().asReferenceTypeLatticeElement().asMeetWithNotNull());
           affectedValues.addAll(specializedArg.affectedValues());
           specializedArg.replaceUsers(nonNullArg);
           Assume<NonNullAssumption> assumeNotNull =
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
index 02cfe3a..0adf3f7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
@@ -227,7 +227,7 @@
                 TypeLatticeElement typeLattice = knownToBeNonNullValue.getTypeLattice();
                 Value nonNullValue =
                     code.createValue(
-                        typeLattice.asReferenceTypeLatticeElement().asNotNull(),
+                        typeLattice.asReferenceTypeLatticeElement().asMeetWithNotNull(),
                         knownToBeNonNullValue.getLocalInfo());
                 affectedValues.addAll(knownToBeNonNullValue.affectedValues());
                 Assume<NonNullAssumption> nonNull =
@@ -359,7 +359,7 @@
         assert typeLattice.isReference();
         Value nonNullValue =
             code.createValue(
-                typeLattice.asReferenceTypeLatticeElement().asNotNull(),
+                typeLattice.asReferenceTypeLatticeElement().asMeetWithNotNull(),
                 knownToBeNonNullValue.getLocalInfo());
         affectedValues.addAll(knownToBeNonNullValue.affectedValues());
         Assume<NonNullAssumption> nonNull =
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
index 25988b8..42908d2 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
@@ -554,7 +554,9 @@
 
   @Test
   public void testNotNullOfNullGivesBottom() {
-    assertEquals(Nullability.bottom(), ReferenceTypeLatticeElement.NULL.asNotNull().nullability());
+    assertEquals(
+        Nullability.bottom(),
+        ReferenceTypeLatticeElement.NULL.asMeetWithNotNull().nullability());
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/B141654799.java b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/B141654799.java
new file mode 100644
index 0000000..de6f2e7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/B141654799.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.ir.optimize.nonnull;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class B141654799 extends TestBase {
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimes().build();
+  }
+
+  public B141654799(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(B141654799.class)
+        .enableInliningAnnotations()
+        .addKeepMainRule(TestClass.class)
+        .setMinApi(parameters.getRuntime())
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("The end")
+        .inspect(inspector -> {
+          ClassSubject main = inspector.clazz(TestClass.class);
+          assertThat(main, isPresent());
+          MethodSubject mainMethod = main.mainMethod();
+          assertThat(mainMethod, isPresent());
+          assertTrue(mainMethod.streamInstructions().noneMatch(i -> i.isIfEqz() || i.isIfNez()));
+        });
+  }
+
+  static class TestClass {
+    public static void main(String... args) {
+      TestClass x = null;
+      if (System.currentTimeMillis() > 0) {
+        TestClass y = (TestClass) returnsNull();
+        if (y != null) {
+          x = y;
+        }
+      }
+      if (x != null) {
+        System.out.println("Dead code: " + x.toString());
+      }
+      System.out.println("The end");
+    }
+
+    @NeverInline
+    static Object returnsNull() {
+      return null;
+    }
+  }
+}