Add tests for casts to special Native types.
And make the cast/instanceof GLOBAL.Object be typeof == "object"
instead of noop.
Change-Id: I02948db24c104fb42616a986b50d9b1b87d9b6d5
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 65c5f47..2c4831a 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
@@ -44,7 +44,6 @@
TYPE_JAVA_OBJECT("", true, false),
TYPE_JAVA_OBJECT_OR_JSO("AllowJso", true, false),
TYPE_JSO("Jso"),
- TYPE_NATIVE_ARRAY("NativeArray"),
TYPE_ARRAY("Array"),
TYPE_JSO_ARRAY("JsoArray", true, false),
TYPE_JAVA_LANG_OBJECT("AllowJso", true, false),
@@ -54,6 +53,9 @@
TYPE_JS_NATIVE("Native", false, true),
TYPE_JS_UNKNOWN_NATIVE("UnknownNative"),
TYPE_JS_FUNCTION("Function"),
+ TYPE_JS_OBJECT("JsObject"),
+ TYPE_JS_ARRAY("JsArray"),
+ // Primitive types are meant to be consecutive.
TYPE_PRIMITIVE_LONG,
TYPE_PRIMITIVE_NUMBER,
TYPE_PRIMITIVE_BOOLEAN;
@@ -111,7 +113,7 @@
} else if (getJsSpecialType(type) != null) {
return getJsSpecialType(type);
} else if (program.isUntypedArrayType(type)) {
- return TypeCategory.TYPE_NATIVE_ARRAY;
+ return TypeCategory.TYPE_JS_ARRAY;
} else if (type == program.getTypeJavaLangObject()) {
return TypeCategory.TYPE_JAVA_LANG_OBJECT;
} else if (program.getRepresentedAsNativeTypesDispatchMap().containsKey(type)) {
@@ -142,11 +144,11 @@
switch (classType.getJsName()) {
case "Object":
- return TypeCategory.TYPE_JAVA_LANG_OBJECT;
+ return TypeCategory.TYPE_JS_OBJECT;
case "Function":
return TypeCategory.TYPE_JS_FUNCTION;
case "Array":
- return TypeCategory.TYPE_NATIVE_ARRAY;
+ return TypeCategory.TYPE_JS_ARRAY;
case "Number":
return TypeCategory.TYPE_JAVA_LANG_DOUBLE;
case "String":
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 c16a522..0b7244a 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
@@ -33,19 +33,21 @@
private static final int TYPE_JAVA_OBJECT = 0;
private static final int TYPE_JAVA_OBJECT_OR_JSO = 1;
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_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;
+ private static final int TYPE_ARRAY = 3;
+ private static final int TYPE_JSO_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_JS_OBJECT = 12;
+ private static final int TYPE_JS_ARRAY = 13;
+ // Primitive types must be consecutive.
+ private static final int TYPE_PRIMITIVE_LONG = 14;
+ private static final int TYPE_PRIMITIVE_NUMBER = 15;
+ private static final int TYPE_PRIMITIVE_BOOLEAN = 16;
public static <T> T[] stampJavaTypeInfo(Object array, T[] referenceType) {
if (Array.getElementTypeCategory(referenceType) != TYPE_JS_UNKNOWN_NATIVE) {
@@ -187,6 +189,8 @@
return Cast.instanceOfArray(value);
case TYPE_JS_FUNCTION:
return Cast.instanceOfFunction(value);
+ case TYPE_JS_OBJECT:
+ return Cast.instanceOfJsObject(value);
case TYPE_JAVA_OBJECT:
return Cast.canCast(value, Array.getElementTypeId(array));
case TYPE_JSO:
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 10468f9..840ad28 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
@@ -111,8 +111,8 @@
/**
* Allow a cast to (untyped) array. This case covers single and multidimensional JsType arrays.
*/
- static Object castToNativeArray(Object src) {
- checkType(src == null || instanceOfNativeArray(src));
+ static Object castToJsArray(Object src) {
+ checkType(src == null || instanceOfJsArray(src));
return src;
}
@@ -141,6 +141,14 @@
}
/**
+ * Allow a dynamic cast to a native GLOBAL.Object if it is JavaScript object.
+ */
+ static Object castToJsObject(Object src) {
+ checkType(src == null || isJsObject(src));
+ return src;
+ }
+
+ /**
* A dynamic cast that optionally checks for JsType prototypes.
*/
static Object castToNative(Object src, JavaScriptObject jsType) {
@@ -188,7 +196,7 @@
/**
* Returns true if {@code src} is an array (native or not).
*/
- static boolean instanceOfNativeArray(Object src) {
+ static boolean instanceOfJsArray(Object src) {
return isArray(src);
}
@@ -220,6 +228,13 @@
}
/**
+ * Returns true if the object is a JS object.
+ */
+ static boolean instanceOfJsObject(Object src) {
+ return (src != null) && isJsObject(src);
+ }
+
+ /**
* Returns whether the Object is a function.
*/
@HasNoSideEffects
@@ -228,6 +243,11 @@
}-*/;
@HasNoSideEffects
+ private static native boolean isJsObject(Object src)/*-{
+ return typeof(src) === "object";
+ }-*/;
+
+ @HasNoSideEffects
static boolean isJavaScriptObject(Object src) {
return isJsObjectOrFunction(src) && !Util.hasTypeMarker(src);
}
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 5bb4166..3bf511a 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
@@ -94,7 +94,7 @@
" 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 castToJsArray(Object src) { return src;}",
" public static Object castToJso(Object src) { return src;}",
" public static Object castToString(Object src) { return src;}",
" public static Object castToDouble(Object src) { return src;}",
@@ -102,6 +102,7 @@
" public static Object castToNative(Object src, JavaScriptObject type) { return src;}",
" public static Object castToUnknownNative(Object src) { return src;}",
" public static Object castToFunction(Object src) { return src; }",
+ " public static Object castToJsObject(Object src) { return src; }",
" public static Class<?> getClass(Object src) { return null; }",
" public static boolean hasJavaObjectVirtualDispatch(Object o) { return true; }",
" public static boolean instanceOf(Object src, int dstId) { return false;}",
@@ -110,7 +111,7 @@
" 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 instanceOfJsArray(Object src) { return false;}",
" public static boolean instanceOfAllowJso(Object src, int dst) { return false;}",
" public static boolean instanceOfJso(Object src) { return false;}",
" public static boolean instanceOfUnknownNative(Object src) { return false;}",
@@ -118,6 +119,7 @@
" return false;",
" }",
" public static boolean instanceOfFunction(Object src) { return false; }",
+ " public static boolean instanceOfJsObject(Object src) { return false; }",
" public static boolean isArray(Object o) { return false; }",
" public static boolean isJavaScriptObject(Object o) { return true; }",
" public static native boolean isNull(Object a) /*-{ }-*/;",
diff --git a/user/test/com/google/gwt/core/interop/NativeJsTypeTest.java b/user/test/com/google/gwt/core/interop/NativeJsTypeTest.java
index 2ccdcec..262ffaa 100644
--- a/user/test/com/google/gwt/core/interop/NativeJsTypeTest.java
+++ b/user/test/com/google/gwt/core/interop/NativeJsTypeTest.java
@@ -18,9 +18,11 @@
import static jsinterop.annotations.JsPackage.GLOBAL;
import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.interop.JsTypeSpecialTypesTest.SomeFunctionalInterface;
import com.google.gwt.junit.client.GWTTestCase;
import javaemul.internal.annotations.DoNotInline;
+import jsinterop.annotations.JsFunction;
import jsinterop.annotations.JsOverlay;
import jsinterop.annotations.JsPackage;
import jsinterop.annotations.JsType;
@@ -206,4 +208,132 @@
assertEquals(new Integer(5),
new NativeJsTypeWithStaticInitializationAndInstanceOverlayMethod().getObject());
}
+
+ @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Function")
+ static class NativeFunction {
+ }
+
+ private static native Object createFunction() /*-{
+ return function() {};
+ }-*/;
+
+ @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Array")
+ static class NativeArray {
+ }
+
+ @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Number")
+ static class NativeNumber {
+ }
+
+ private static native Object createNumber() /*-{
+ return 1;
+ }-*/;
+
+ private static native Object createBoxedNumber() /*-{
+ return new Number(1);
+ }-*/;
+
+ @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "String")
+ static class NativeString {
+ }
+
+ private static native Object createBoxedString() /*-{
+ return new String("hello");
+ }-*/;
+
+ @JsFunction
+ interface SomeFunctionInterface {
+ void m();
+ }
+
+ static class SomeFunction implements SomeFunctionInterface {
+ public void m() {
+ }
+ }
+
+ public void testSpecialNativeInstanceOf() {
+ Object aJsFunction = new SomeFunction();
+ // True cases.
+ assertTrue(aJsFunction instanceof NativeFunction);
+ assertTrue(aJsFunction instanceof SomeFunctionalInterface);
+ // False cases.
+ assertFalse(aJsFunction instanceof NativeObject);
+ assertFalse(aJsFunction instanceof NativeArray);
+ assertFalse(aJsFunction instanceof NativeNumber);
+ assertFalse(aJsFunction instanceof NativeString);
+
+ Object anotherFunction = createFunction();
+ // True cases.
+ assertTrue(anotherFunction instanceof NativeFunction);
+ assertTrue(anotherFunction instanceof SomeFunctionalInterface);
+ // False cases.
+ assertFalse(anotherFunction instanceof NativeObject);
+ assertFalse(anotherFunction instanceof NativeArray);
+ assertFalse(anotherFunction instanceof NativeNumber);
+ assertFalse(anotherFunction instanceof NativeString);
+
+ Object aString = "Hello";
+ // True cases.
+ assertTrue(aString instanceof NativeString);
+ // False cases.
+ assertFalse(aString instanceof NativeFunction);
+ assertFalse(aString instanceof NativeObject);
+ assertFalse(aString instanceof NativeArray);
+ assertFalse(aString instanceof NativeNumber);
+
+ Object aBoxedString = createBoxedString();
+ // True cases.
+ // Note that boxed strings are (surprisingly) not strings but objects.
+ assertTrue(aBoxedString instanceof NativeObject);
+ // False cases.
+ assertFalse(aBoxedString instanceof NativeFunction);
+ assertFalse(aBoxedString instanceof NativeArray);
+ assertFalse(aBoxedString instanceof NativeNumber);
+ assertFalse(aBoxedString instanceof NativeString);
+
+ Object anArray = new String[0];
+ // True cases.
+ assertTrue(anArray instanceof NativeArray);
+ assertTrue(anArray instanceof NativeObject);
+ // False cases.
+ assertFalse(anArray instanceof NativeFunction);
+ assertFalse(anArray instanceof NativeNumber);
+ assertFalse(anArray instanceof NativeString);
+
+ Object aNativeArray = JavaScriptObject.createArray();
+ // True cases.
+ assertTrue(aNativeArray instanceof NativeArray);
+ assertTrue(anArray instanceof NativeObject);
+ // False cases.
+ assertFalse(aNativeArray instanceof NativeFunction);
+ assertFalse(aNativeArray instanceof NativeNumber);
+ assertFalse(aNativeArray instanceof NativeString);
+
+ Object aNumber = new Double(3);
+ // True cases.
+ assertTrue(aNumber instanceof NativeNumber);
+ // False cases.
+ assertFalse(aNumber instanceof NativeArray);
+ assertFalse(aNumber instanceof NativeObject);
+ assertFalse(aNumber instanceof NativeFunction);
+ assertFalse(aNumber instanceof NativeString);
+
+ Object anotherNumber = createNumber();
+ // True cases.
+ assertTrue(anotherNumber instanceof NativeNumber);
+ // False cases.
+ assertFalse(anotherNumber instanceof NativeArray);
+ assertFalse(anotherNumber instanceof NativeObject);
+ assertFalse(anotherNumber instanceof NativeFunction);
+ assertFalse(anotherNumber instanceof NativeString);
+
+ Object aBoxedNumber = createBoxedNumber();
+ // True cases.
+ assertTrue(aBoxedNumber instanceof NativeObject);
+ // False cases.
+ assertFalse(aBoxedNumber instanceof NativeNumber);
+ assertFalse(aBoxedNumber instanceof NativeArray);
+ assertFalse(aBoxedNumber instanceof NativeFunction);
+ assertFalse(aBoxedNumber instanceof NativeString);
+ }
}
diff --git a/user/test/com/google/gwt/dev/jjs/optimized/CastOptimizationTest.java b/user/test/com/google/gwt/dev/jjs/optimized/CastOptimizationTest.java
index 500b198..c4d14cc 100644
--- a/user/test/com/google/gwt/dev/jjs/optimized/CastOptimizationTest.java
+++ b/user/test/com/google/gwt/dev/jjs/optimized/CastOptimizationTest.java
@@ -21,6 +21,7 @@
import java.util.Random;
+import jsinterop.annotations.JsPackage;
import jsinterop.annotations.JsType;
/**
@@ -40,6 +41,26 @@
protected JsoTestObject() { }
}
+ @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
+ static class NativeObject {
+ }
+
+ @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Function")
+ static class NativeFunction {
+ }
+
+ @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Array")
+ static class NativeArray {
+ }
+
+ @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Number")
+ static class NativeNumber {
+ }
+
+ @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "String")
+ static class NativeString {
+ }
+
private static Object field;
private static int randomNumber = new Random().nextInt(42);
@@ -86,6 +107,22 @@
return ((String) field);
}
+ public static NativeFunction castNativeFunction() {
+ return ((NativeFunction) field);
+ }
+
+ public static NativeObject castNativeObject() {
+ return ((NativeObject) field);
+ }
+
+ public static NativeArray castNativeArray() {
+ return ((NativeArray) field);
+ }
+
+ public static NativeNumber castNativeNumber() {
+ return ((NativeNumber) field);
+ }
+
private static native String getGeneratedCastFunctionDefinition() /*-{
return function() {
@CastOptimizationTest::castOp()();
@@ -93,6 +130,10 @@
@CastOptimizationTest::castOpDualJso()();
@CastOptimizationTest::castOpJsType()();
@CastOptimizationTest::castOpString()();
+ @CastOptimizationTest::castNativeFunction()();
+ @CastOptimizationTest::castNativeNumber()();
+ @CastOptimizationTest::castNativeArray()();
+ @CastOptimizationTest::castNativeObject()();
}.toString();
}-*/;