Tests codifying some null-value usages.

Change-Id: Iab836ad5ce81b50c1b38e17ef40fd0a81d1408bc
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/JarState.java b/src/main/java/com/android/tools/r8/ir/conversion/JarState.java
index cd08984..79a83f8 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/JarState.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/JarState.java
@@ -934,7 +934,7 @@
       return "<byte|bool>";
     }
     if (type == ARRAY_TYPE) {
-      return type.getElementType().getInternalName();
+      return "<any array>";
     }
     if (type == REFERENCE_TYPE || type == OBJECT_TYPE || type == NULL_TYPE) {
       return type.getInternalName();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NullArrayAndNullObjectValueTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NullArrayAndNullObjectValueTest.java
new file mode 100644
index 0000000..a1408fa
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NullArrayAndNullObjectValueTest.java
@@ -0,0 +1,192 @@
+// 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.optimize;
+
+import com.android.tools.r8.D8;
+import com.android.tools.r8.D8Command;
+import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.jasmin.JasminBuilder;
+import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
+import com.android.tools.r8.jasmin.JasminTestBase;
+import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class NullArrayAndNullObjectValueTest extends JasminTestBase {
+
+  @Test
+  public void testNullIsArray() throws Exception {
+    JasminBuilder jasminBuilder = new JasminBuilder();
+    ClassBuilder classBuilder = jasminBuilder.addClass("TestClass");
+
+    // Store directly to the null value.
+    classBuilder.addStaticMethod(
+        "nullArrayStore",
+        ImmutableList.of(),
+        "V",
+        ".limit stack 10",
+        ".limit locals 10",
+        ".catch java/lang/NullPointerException from L0 to L1 using L2",
+        "aconst_null",
+        "iconst_0",
+        "iconst_1",
+        "L0:",
+        "iastore",
+        "L1:",
+        "return",
+        "L2:",
+        "pop",
+        "getstatic java/lang/System/out Ljava/io/PrintStream;",
+        "ldc \"NPE\"",
+        "invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V",
+        "return");
+
+    // Load directly from the null value.
+    classBuilder.addStaticMethod(
+        "nullArrayLoad",
+        ImmutableList.of(),
+        "V",
+        ".limit stack 10",
+        ".limit locals 10",
+        ".catch java/lang/NullPointerException from L0 to L1 using L2",
+        "aconst_null",
+        "iconst_0",
+        "L0:",
+        "iaload",
+        "L1:",
+        "pop",
+        "return",
+        "L2:",
+        "pop",
+        "getstatic java/lang/System/out Ljava/io/PrintStream;",
+        "ldc \"NPE\"",
+        "invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V",
+        "return");
+
+    // Get the length of the null value.
+    classBuilder.addStaticMethod(
+        "nullArrayLength",
+        ImmutableList.of(),
+        "V",
+        ".limit stack 10",
+        ".limit locals 10",
+        ".catch java/lang/NullPointerException from L0 to L1 using L2",
+        "aconst_null",
+        "L0:",
+        "arraylength",
+        "L1:",
+        "pop",
+        "return",
+        "L2:",
+        "pop",
+        "getstatic java/lang/System/out Ljava/io/PrintStream;",
+        "ldc \"NPE\"",
+        "invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V",
+        "return");
+
+    // Use the same null value (local containing null) as both an object type and an array type.
+    classBuilder.addStaticMethod(
+        "nullToObjectAndArray",
+        ImmutableList.of(),
+        "V",
+        ".limit stack 10",
+        ".limit locals 10",
+        // Stored null in local 0
+        "aconst_null",
+        "astore 0",
+        // Create single-cell array of object type and store the null in it.
+        "iconst_1",
+        "anewarray java/lang/String",
+        "iconst_0",
+        "aload 0",
+        "aastore",
+        // Create single-cell array of array type and store the null in it.
+        "iconst_1",
+        "anewarray [I",
+        "iconst_0",
+        "aload 0",
+        "aastore",
+        "return");
+
+    classBuilder.addMainMethod(
+        ".limit stack 5",
+        ".limit locals 5",
+        "invokestatic TestClass/nullToObjectAndArray()V",
+        "invokestatic TestClass/nullArrayStore()V",
+        "invokestatic TestClass/nullArrayLoad()V",
+        "invokestatic TestClass/nullArrayLength()V",
+        "return");
+
+    Path riJar = temp.getRoot().toPath().resolve("ri-out.jar");
+    jasminBuilder.writeJar(riJar, new DefaultDiagnosticsHandler());
+    ProcessResult riResult = ToolHelper.runJava(riJar, "TestClass");
+    Assert.assertEquals(riResult.toString(), 0, riResult.exitCode);
+
+    Path d8Jar = temp.getRoot().toPath().resolve("d8-out.jar");
+    D8.run(
+        D8Command.builder().addProgramFiles(riJar).setOutput(d8Jar, OutputMode.DexIndexed).build());
+    ProcessResult d8Result = ToolHelper.runArtRaw(d8Jar.toString(), "TestClass");
+    Assert.assertEquals(d8Result.toString(), 0, riResult.exitCode);
+
+    Assert.assertEquals(riResult.stdout, d8Result.stdout);
+  }
+
+  @Test
+  public void testObjectNotArray() throws Exception {
+    JasminBuilder jasminBuilder = new JasminBuilder();
+    ClassBuilder classBuilder = jasminBuilder.addClass("TestClass");
+
+    // Invalid attempt at using object as an array.
+    classBuilder.addStaticMethod(
+        "objectAsArray",
+        ImmutableList.of("Ljava/lang/Object;"),
+        "V",
+        ".limit stack 10",
+        ".limit locals 10",
+        ".catch java/lang/NullPointerException from L0 to L1 using L2",
+        "aload 0",
+        "iconst_0",
+        "iconst_1",
+        "L0:",
+        "iastore",
+        "L1:",
+        "return",
+        "L2:",
+        "pop",
+        "getstatic java/lang/System/out Ljava/io/PrintStream;",
+        "ldc \"NPE\"",
+        "invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V",
+        "return");
+    classBuilder.addMainMethod(
+        ".limit stack 5",
+        ".limit locals 5",
+        "aconst_null",
+        "invokestatic TestClass/objectAsArray(Ljava/lang/Object;)V",
+        "return");
+
+    Path riJar = temp.getRoot().toPath().resolve("ri-out.jar");
+    jasminBuilder.writeJar(riJar, new DefaultDiagnosticsHandler());
+    ProcessResult riResult = ToolHelper.runJava(riJar, "TestClass");
+    Assert.assertEquals(riResult.toString(), 1, riResult.exitCode);
+    Assert.assertTrue(riResult.stderr.contains("VerifyError"));
+
+    Path d8Jar = temp.getRoot().toPath().resolve("d8-out.jar");
+    try {
+      D8.run(
+          D8Command.builder().addProgramFiles(riJar).setOutput(d8Jar, OutputMode.DexIndexed)
+              .build());
+    } catch (RuntimeException e) {
+      // Discard expected failure.
+      // If we ever start post-verifying inputs on internal errors this will need to be updated.
+      Assert.assertTrue(e.getCause() instanceof AssertionError);
+      return;
+    }
+    Assert.fail("Expected D8 to fail compilation");
+  }
+}