Add test for type constraints on trivial phis

Bug: 119401913
Change-Id: I2f7a70489dbe6cd411cceb628a50630cb74523fe
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/ArrayTypeTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/ArrayTypeTest.java
index 1d21381..f508934 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/ArrayTypeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/ArrayTypeTest.java
@@ -7,7 +7,6 @@
 import static com.android.tools.r8.ir.analysis.type.TypeLatticeElement.FLOAT;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.ir.code.ArrayGet;
@@ -17,7 +16,6 @@
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.Value;
 import java.util.function.Consumer;
-import java.util.function.Predicate;
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -99,24 +97,6 @@
     };
   }
 
-  private static <T extends Instruction> T getMatchingInstruction(
-      IRCode code, Predicate<Instruction> predicate) {
-    Instruction result = null;
-    Iterable<Instruction> instructions = code::instructionIterator;
-    for (Instruction instruction : instructions) {
-      if (predicate.test(instruction)) {
-        if (result != null) {
-          fail();
-        }
-        result = instruction;
-      }
-    }
-    if (result == null) {
-      fail();
-    }
-    return (T) result;
-  }
-
   static class TestClass {
 
     public static void arrayTest() {
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTestBase.java b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTestBase.java
index 98c4954..3987e03 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTestBase.java
@@ -4,11 +4,14 @@
 
 package com.android.tools.r8.ir.analysis.type;
 
+import static org.junit.Assert.fail;
+
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
@@ -16,6 +19,7 @@
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 import org.junit.Before;
 
 public class TypeAnalysisTestBase extends TestBase {
@@ -52,4 +56,22 @@
             .buildIR(appInfo, GraphLense.getIdentityLense(), options, Origin.unknown());
     irInspector.accept(code);
   }
+
+  public static <T extends Instruction> T getMatchingInstruction(
+      IRCode code, Predicate<Instruction> predicate) {
+    Instruction result = null;
+    Iterable<Instruction> instructions = code::instructionIterator;
+    for (Instruction instruction : instructions) {
+      if (predicate.test(instruction)) {
+        if (result != null) {
+          fail();
+        }
+        result = instruction;
+      }
+    }
+    if (result == null) {
+      fail();
+    }
+    return (T) result;
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeConstraintOnTrivialPhiTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeConstraintOnTrivialPhiTest.java
new file mode 100644
index 0000000..da32262
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeConstraintOnTrivialPhiTest.java
@@ -0,0 +1,113 @@
+// Copyright (c) 2018, 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.analysis.type;
+
+import static com.android.tools.r8.ir.analysis.type.TypeLatticeElement.DOUBLE;
+import static com.android.tools.r8.ir.analysis.type.TypeLatticeElement.FLOAT;
+import static com.android.tools.r8.ir.analysis.type.TypeLatticeElement.INT;
+import static com.android.tools.r8.ir.analysis.type.TypeLatticeElement.LONG;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.ir.code.ConstNumber;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.smali.SmaliBuilder;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.util.function.Consumer;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class TypeConstraintOnTrivialPhiTest extends TypeAnalysisTestBase {
+
+  private enum Config {
+    INT,
+    FLOAT,
+    LONG,
+    DOUBLE;
+
+    public boolean isSingle() {
+      return this == INT || this == FLOAT;
+    }
+
+    public String getTestName() {
+      return toString().toLowerCase() + "ConstraintOnTrivialPhiTest";
+    }
+
+    public String getConstInstruction() {
+      return isSingle() ? "const/4 v0, 0x0" : "const-wide v0, 0x0";
+    }
+
+    public String getMoveInstruction() {
+      return isSingle() ? "move v1, v0" : "move-wide v2, v0";
+    }
+
+    public String getInvokeStaticInstruction() {
+      switch (this) {
+        case INT:
+          return "invoke-static {v1}, Ljava/lang/Integer;->toString(I)Ljava/lang/String;";
+        case FLOAT:
+          return "invoke-static {v1}, Ljava/lang/Float;->toString(F)Ljava/lang/String;";
+        case LONG:
+          return "invoke-static {v2, v3}, Ljava/lang/Long;->toString(J)Ljava/lang/String;";
+        case DOUBLE:
+          return "invoke-static {v2, v3}, Ljava/lang/Double;->toString(D)Ljava/lang/String;";
+      }
+      throw new Unreachable();
+    }
+  }
+
+  public TypeConstraintOnTrivialPhiTest() throws Exception {
+    super(buildApp(), "TestClass");
+  }
+
+  public static AndroidApp buildApp() throws Exception {
+    SmaliBuilder smaliBuilder = new SmaliBuilder("TestClass");
+    for (Config config : Config.values()) {
+      String code =
+          StringUtils.lines(
+              config.getConstInstruction(),
+              ":label_1",
+              "if-eqz p0, :label_2",
+              config.getMoveInstruction(),
+              config.getInvokeStaticInstruction(),
+              ":label_2",
+              "goto :label_1");
+      smaliBuilder.addStaticMethod("void", config.getTestName(), ImmutableList.of("int"), 4, code);
+    }
+    return smaliBuilder.build();
+  }
+
+  @Test
+  public void testIntConstraintOnTrivialPhi() throws Exception {
+    buildAndCheckIR("intConstraintOnTrivialPhiTest", testInspector(INT));
+  }
+
+  @Test
+  @Ignore("b/119401913")
+  public void testFloatConstraintOnTrivialPhi() throws Exception {
+    buildAndCheckIR("floatConstraintOnTrivialPhiTest", testInspector(FLOAT));
+  }
+
+  @Test
+  public void testLongConstraintOnTrivialPhi() throws Exception {
+    buildAndCheckIR("longConstraintOnTrivialPhiTest", testInspector(LONG));
+  }
+
+  @Test
+  @Ignore("b/119401913")
+  public void testDoubleConstraintOnTrivialPhi() throws Exception {
+    buildAndCheckIR("doubleConstraintOnTrivialPhiTest", testInspector(DOUBLE));
+  }
+
+  private static Consumer<IRCode> testInspector(TypeLatticeElement expectedType) {
+    return code -> {
+      ConstNumber constNumberInstruction = getMatchingInstruction(code, Instruction::isConstNumber);
+      assertEquals(expectedType, constNumberInstruction.outValue().getTypeLattice());
+    };
+  }
+}