Make JSO[] and native JsType getClass() return JavaScriptObject[].class.

For consistency Native[] are considered instanceof JavaScriptObject[].

Change-Id: I619307de11242de5c4981a72b9f8304d57bf4338
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java
index 40f7d7e..65c5f47 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java
@@ -16,6 +16,7 @@
 package com.google.gwt.dev.jjs.impl;
 
 import com.google.gwt.dev.javac.JsInteropUtil;
+import com.google.gwt.dev.jjs.ast.JArrayType;
 import com.google.gwt.dev.jjs.ast.JClassType;
 import com.google.gwt.dev.jjs.ast.JPrimitiveType;
 import com.google.gwt.dev.jjs.ast.JProgram;
@@ -45,6 +46,7 @@
   TYPE_JSO("Jso"),
   TYPE_NATIVE_ARRAY("NativeArray"),
   TYPE_ARRAY("Array"),
+  TYPE_JSO_ARRAY("JsoArray", true, false),
   TYPE_JAVA_LANG_OBJECT("AllowJso", true, false),
   TYPE_JAVA_LANG_STRING("String"),
   TYPE_JAVA_LANG_DOUBLE("Double"),
@@ -104,6 +106,8 @@
     type = type.getUnderlyingType();
     if (type == program.getTypeJavaLangObjectArray()) {
       return TypeCategory.TYPE_ARRAY;
+    } else if (isJsoArray(type)) {
+      return TypeCategory.TYPE_JSO_ARRAY;
     } else if (getJsSpecialType(type) != null) {
       return getJsSpecialType(type);
     } else if (program.isUntypedArrayType(type)) {
@@ -150,4 +154,13 @@
     }
     return null;
   }
+
+  private static boolean isJsoArray(JType type) {
+    if (!type.isArrayType()) {
+      return false;
+    }
+
+    JArrayType arrayType = (JArrayType) type;
+    return arrayType.getLeafType().isJsoType();
+  }
 }
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
index 9e843fa..1af28b4 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
@@ -34,16 +34,17 @@
   private static final int TYPE_JSO = 2;
   private static final int TYPE_NATIVE_ARRAY = 3;
   private static final int TYPE_ARRAY = 4;
-  private static final int TYPE_JAVA_LANG_OBJECT = 5;
-  private static final int TYPE_JAVA_LANG_STRING = 6;
-  private static final int TYPE_JAVA_LANG_DOUBLE = 7;
-  private static final int TYPE_JAVA_LANG_BOOLEAN = 8;
-  private static final int TYPE_JS_NATIVE = 9;
-  private static final int TYPE_JS_UNKNOWN_NATIVE = 10;
-  private static final int TYPE_JS_FUNCTION = 11;
-  private static final int TYPE_PRIMITIVE_LONG = 12;
-  private static final int TYPE_PRIMITIVE_NUMBER = 13;
-  private static final int TYPE_PRIMITIVE_BOOLEAN = 14;
+  private static final int TYPE_JSO_ARRAY = 5;
+  private static final int TYPE_JAVA_LANG_OBJECT = 6;
+  private static final int TYPE_JAVA_LANG_STRING = 7;
+  private static final int TYPE_JAVA_LANG_DOUBLE = 8;
+  private static final int TYPE_JAVA_LANG_BOOLEAN = 9;
+  private static final int TYPE_JS_NATIVE = 10;
+  private static final int TYPE_JS_UNKNOWN_NATIVE = 11;
+  private static final int TYPE_JS_FUNCTION = 12;
+  private static final int TYPE_PRIMITIVE_LONG = 13;
+  private static final int TYPE_PRIMITIVE_NUMBER = 14;
+  private static final int TYPE_PRIMITIVE_BOOLEAN = 15;
 
   public static <T> T[] stampJavaTypeInfo(Object array, T[] referenceType) {
     if (Array.getElementTypeCategory(referenceType) != TYPE_JS_UNKNOWN_NATIVE) {
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
index 766eff6..10468f9 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
@@ -101,6 +101,14 @@
   }
 
   /**
+   * Allow a cast to an array of Jsos, accepting also untyped arrays.
+   */
+  static Object castToJsoArray(Object src, JavaScriptObject dstId) {
+    checkType(src == null || instanceOfJsoArray(src, dstId));
+    return src;
+  }
+
+  /**
    * Allow a cast to (untyped) array. This case covers single and multidimensional JsType arrays.
    */
   static Object castToNativeArray(Object src) {
@@ -171,6 +179,13 @@
   }
 
   /**
+   * Returns true if {@code src} is Java object array or an untyped array.
+   */
+  static boolean instanceOfJsoArray(Object src, JavaScriptObject dstId) {
+    return canCast(src, dstId) || !Util.hasTypeMarker(src) && isArray(src);
+  }
+
+  /**
    * Returns true if {@code src} is an array (native or not).
    */
   static boolean instanceOfNativeArray(Object src) {
@@ -353,6 +368,7 @@
   @HasNoSideEffects
   static native Class<?> getClass(Object array) /*-{
     return array.@java.lang.Object::___clazz
+        || Array.isArray(array) && @JavaScriptObject[]::class
         || @JavaScriptObject::class;
   }-*/;
 }
diff --git a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
index b8f1faa..c11946f 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
@@ -92,6 +92,7 @@
           "  public static Object castTo(Object src, int dstId) { return src;}",
           "  public static Object castToAllowJso(Object src, int dstId) { return src;}",
           "  public static Object castToArray(Object src) { return src;}",
+          "  public static Object castToJsoArray(Object src) { return src;}",
           "  public static Object castToNativeArray(Object src) { return src;}",
           "  public static Object castToJso(Object src) { return src;}",
           "  public static Object castToString(Object src) { return src;}",
@@ -107,6 +108,7 @@
           "  public static boolean instanceOfDouble(Object o) { return true; }",
           "  public static boolean instanceOfBoolean(Object o) { return true; }",
           "  public static boolean instanceOfArray(Object src) { return false;}",
+          "  public static boolean instanceOfJsoArray(Object src) { return false;}",
           "  public static boolean instanceOfNativeArray(Object src) { return false;}",
           "  public static boolean instanceOfAllowJso(Object src, int dst) { return false;}",
           "  public static boolean instanceOfJso(Object src) { return false;}",
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/ArrayNormalizerTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/ArrayNormalizerTest.java
index 9e159f1..ff3a760 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/ArrayNormalizerTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/ArrayNormalizerTest.java
@@ -29,8 +29,8 @@
     Result result =
         optimize("void", "A[] a = new A[1]; a[1] = new A();");
     result.intoString(
-        "EntryPoint$A[] a = Array.initUnidimensionalArray(EntryPoint$A.class, [], " +
-            "/* JRuntimeTypeReference */\"test.EntryPoint$A\", 1, 0, 1);",
+        "EntryPoint$A[] a = Array.initUnidimensionalArray(EntryPoint$A.class, [], "
+            + "/* JRuntimeTypeReference */\"test.EntryPoint$A\", 1, 0, 1);",
         "a[1] = new EntryPoint$A();");
   }
 
@@ -41,26 +41,28 @@
     Result result =
         optimize("void", "A[] a = new A[1]; a = new B[1]; a[1] = new A();");
     result.intoString(
-        "EntryPoint$A[] a = Array.initUnidimensionalArray(EntryPoint$A.class, [], " +
-            "/* JRuntimeTypeReference */\"test.EntryPoint$A\", 1, 0, 1);",
-        "a = Array.initUnidimensionalArray(EntryPoint$B.class, [], " +
-            "/* JRuntimeTypeReference */\"test.EntryPoint$B\", 1, 0, 1);",
+        "EntryPoint$A[] a = Array.initUnidimensionalArray(EntryPoint$A.class, [], "
+            + "/* JRuntimeTypeReference */\"test.EntryPoint$A\", 1, 0, 1);",
+        "a = Array.initUnidimensionalArray(EntryPoint$B.class, [], "
+            + "/* JRuntimeTypeReference */\"test.EntryPoint$B\", 1, 0, 1);",
         "Array.setCheck(a, 1, new EntryPoint$A());");
   }
 
   public void testObjectArray() throws Exception {
     optimize("void", "Object[] o = new Object[10];")
-        .intoString("Object[] o = Array.initUnidimensionalArray(Object.class, [], " +
-            "/* JRuntimeTypeReference */\"java.lang.Object\", 10, 5, 1);");
+        .intoString("Object[] o = Array.initUnidimensionalArray(Object.class, [], "
+            + "/* JRuntimeTypeReference */\"java.lang.Object\", 10, "
+            + TypeCategory.TYPE_JAVA_LANG_OBJECT.ordinal() + ", 1);");
     optimize("void", "Object[] o = {null, null, Object.class};")
-        .intoString("Object[] o = " +
-            "Array.stampJavaTypeInfo(" +
-            "Array.getClassLiteralForArray(ClassLiteralHolder.Ljava_lang_Object_2_classLit, 1), " +
-            "[], /* JRuntimeTypeReference */\"java.lang.Object\", 5, [null, null, Object.class]);");
+        .intoString("Object[] o = Array.stampJavaTypeInfo("
+            + "Array.getClassLiteralForArray(ClassLiteralHolder.Ljava_lang_Object_2_classLit, 1), "
+            + "[], /* JRuntimeTypeReference */\"java.lang.Object\", "
+            + TypeCategory.TYPE_JAVA_LANG_OBJECT.ordinal() + ", [null, null, Object.class]);");
     optimize("void", "Object[] o = new Object[] {};")
-        .intoString("Object[] o = Array.stampJavaTypeInfo(Array.getClassLiteralForArray(" +
-            "ClassLiteralHolder.Ljava_lang_Object_2_classLit, 1), [], " +
-            "/* JRuntimeTypeReference */\"java.lang.Object\", 5, []);");
+        .intoString("Object[] o = Array.stampJavaTypeInfo(Array.getClassLiteralForArray("
+            + "ClassLiteralHolder.Ljava_lang_Object_2_classLit, 1), [], "
+            + "/* JRuntimeTypeReference */\"java.lang.Object\", "
+            + TypeCategory.TYPE_JAVA_LANG_OBJECT.ordinal() + ", []);");
   }
 
   public void testNativeJsTypeArray() throws Exception {
diff --git a/user/test/com/google/gwt/dev/jjs/test/ArrayTest.java b/user/test/com/google/gwt/dev/jjs/test/ArrayTest.java
index b4f5368..5be7eb0 100644
--- a/user/test/com/google/gwt/dev/jjs/test/ArrayTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/ArrayTest.java
@@ -43,7 +43,7 @@
     assertFalse(nativeArray instanceof Object[][]);
     assertFalse(nativeArray instanceof int[]);
     assertFalse(nativeArray instanceof List[]);
-    assertTrue(nativeArray.getClass() == JavaScriptObject.class);
+    assertTrue(nativeArray.getClass() == JavaScriptObject[].class);
 
     Object objectArray = new Object[0];
     assertTrue(objectArray instanceof Object[]);
diff --git a/user/test/com/google/gwt/dev/jjs/test/NativeDevirtualizationTest.java b/user/test/com/google/gwt/dev/jjs/test/NativeDevirtualizationTest.java
index 3920a89..aab86c4 100644
--- a/user/test/com/google/gwt/dev/jjs/test/NativeDevirtualizationTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/NativeDevirtualizationTest.java
@@ -132,8 +132,9 @@
   @DoNotRunWith(Platform.Devel)
   public void testNativeJavaScriptArray() {
     Object jsoArray = JavaScriptObject.createArray(10);
-    assertEquals(JavaScriptObject.class, jsoArray.getClass());
+    assertEquals(JavaScriptObject[].class, jsoArray.getClass());
     assertTrue(jsoArray instanceof JavaScriptObject);
+    assertTrue(jsoArray instanceof JavaScriptObject[]);
 
     Object objectArray =  new Object[10];
     assertEquals(Object[].class, objectArray.getClass());