Fixes issue 1822. Arrays now implement Serializable and Cloneable.
Review by: scottb
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7343 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
index df289af..3092e21 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
@@ -71,10 +71,10 @@
public static final Set<String> INDEX_TYPES_SET = new LinkedHashSet<String>(
Arrays.asList(new String[] {
- "java.lang.Object", "java.lang.String", "java.lang.Class",
- "java.lang.CharSequence", "java.lang.Comparable", "java.lang.Enum",
- "java.lang.Iterable", "java.util.Iterator",
- "com.google.gwt.core.client.GWT",
+ "java.io.Serializable", "java.lang.Object", "java.lang.String",
+ "java.lang.Class", "java.lang.CharSequence", "java.lang.Cloneable",
+ "java.lang.Comparable", "java.lang.Enum", "java.lang.Iterable",
+ "java.util.Iterator", "com.google.gwt.core.client.GWT",
"com.google.gwt.core.client.JavaScriptObject",
"com.google.gwt.lang.ClassLiteralHolder",
"com.google.gwt.core.client.RunAsyncCallback",
@@ -313,6 +313,10 @@
private Map<JReferenceType, Integer> typeIdMap = new HashMap<JReferenceType, Integer>();
+ private JInterfaceType typeJavaIoSerializable;
+
+ private JInterfaceType typeJavaLangCloneable;
+
private JClassType typeJavaLangEnum;
private JClassType typeJavaLangObject;
@@ -334,10 +338,10 @@
/**
* Constructor.
*
- * @param enableSourceInfoDescendants Controls whether or not SourceInfo nodes
- * created via the JProgram will record descendant information.
- * Enabling this feature will collect extra data during the
- * compilation cycle, but at a cost of memory and object allocations.
+ * @param correlator Controls whether or not SourceInfo nodes created via the
+ * JProgram will record descendant information. Enabling this feature
+ * will collect extra data during the compilation cycle, but at a
+ * cost of memory and object allocations.
*/
public JProgram(CorrelationFactory correlator) {
super(correlator.makeSourceInfo(SourceOrigin.create(0,
@@ -467,6 +471,11 @@
if (INDEX_TYPES_SET.contains(sname)) {
indexedTypes.put(x.getShortName(), x);
+ if (sname.equals("java.lang.Cloneable")) {
+ typeJavaLangCloneable = x;
+ } else if (sname.equals("java.io.Serializable")) {
+ typeJavaIoSerializable = x;
+ }
}
return x;
@@ -720,6 +729,9 @@
// unrelated
return typeJavaLangObject;
+ } else if (greater == IS_ARRAY
+ && ((tLesser == typeJavaLangCloneable) || (tLesser == typeJavaIoSerializable))) {
+ return tLesser;
} else {
// unrelated: the best commonality between an interface and array, or
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
index ebd7a0b..bfff3cb 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
@@ -262,6 +262,9 @@
*/
private final Map<JMethod, Map<JClassType, Set<JMethod>>> virtualUpRefMap = new IdentityHashMap<JMethod, Map<JClassType, Set<JMethod>>>();
+ private JDeclaredType javaIoSerializable;
+ private JDeclaredType javaLangCloneable;
+
public JTypeOracle(JProgram program) {
this.program = program;
}
@@ -310,6 +313,12 @@
}
}
+ /*
+ * Warning: If this code is ever updated to consider casts of array types
+ * to interface types, then be sure to consider that casting an array to
+ * Serializable and Cloneable succeeds. Currently all casts of an array to
+ * an interface return true, which is overly conservative but is safe.
+ */
} else if (type instanceof JClassType) {
JClassType cType = (JClassType) type;
@@ -369,6 +378,10 @@
}
}
}
+
+ if (qType == javaIoSerializable || qType == javaLangCloneable) {
+ return true;
+ }
} else if (type instanceof JClassType) {
JClassType cType = (JClassType) type;
@@ -402,6 +415,9 @@
public void computeBeforeAST() {
javaLangObject = program.getTypeJavaLangObject();
+ javaIoSerializable = program.getFromTypeMap(Serializable.class.getName());
+ javaLangCloneable = program.getFromTypeMap(Cloneable.class.getName());
+
superClassMap.clear();
subClassMap.clear();
superInterfaceMap.clear();
diff --git a/dev/core/test/com/google/gwt/dev/jjs/JjsTypeTest.java b/dev/core/test/com/google/gwt/dev/jjs/JjsTypeTest.java
index 38821ac..4bb4cb9 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JjsTypeTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JjsTypeTest.java
@@ -64,6 +64,8 @@
private SourceInfo synthSource;
private JReferenceType typeNull;
private JTypeOracle typeOracle;
+ private JReferenceType intfSerializable;
+ private JReferenceType intfCloneable;
public void testCanTheoreticallyCast() {
assertFalse(typeOracle.canTheoreticallyCast(classBnn, typeNull));
@@ -90,6 +92,12 @@
assertTrue(typeOracle.canTheoreticallyCast(intfIBase, classBase));
assertFalse(typeOracle.canTheoreticallyCast(intfJ, classA));
+
+ assertTrue(typeOracle.canTheoreticallyCast(arrayOfA, intfSerializable));
+ assertTrue(typeOracle.canTheoreticallyCast(intfSerializable, arrayOfA));
+
+ assertTrue(typeOracle.canTheoreticallyCast(arrayOfA, intfCloneable));
+ assertTrue(typeOracle.canTheoreticallyCast(intfCloneable, arrayOfA));
}
public void testCanTriviallyCast() {
@@ -133,6 +141,12 @@
assertTrue(typeOracle.canTriviallyCast(classJso, classJso1));
assertTrue(typeOracle.canTriviallyCast(classJso, classJso1));
+
+ assertTrue(typeOracle.canTriviallyCast(arrayOfA, intfSerializable));
+ assertFalse(typeOracle.canTriviallyCast(intfSerializable, arrayOfA));
+
+ assertTrue(typeOracle.canTriviallyCast(arrayOfA, intfCloneable));
+ assertFalse(typeOracle.canTriviallyCast(intfCloneable, arrayOfA));
/*
* Test that two types cannot both be trivially castable to each other,
@@ -172,6 +186,9 @@
assertSame(classObject, generalizeTypes(intfI, arrayOfInt));
+ assertSame(intfSerializable, generalizeTypes(intfSerializable, arrayOfA));
+ assertSame(intfCloneable, generalizeTypes(intfCloneable, arrayOfA));
+
for (JReferenceType type1 : severalTypes()) {
for (JReferenceType type2 : severalTypes()) {
JReferenceType generalized = generalizeTypes(type1, type2);
@@ -187,6 +204,8 @@
assertSame(classB, program.strongerType(classB, classBase));
assertSame(classB, program.strongerType(classBase, classB));
assertSame(intfI, program.strongerType(intfI, intfJ));
+ assertSame(arrayOfA, program.strongerType(intfSerializable, arrayOfA));
+ assertSame(arrayOfA, program.strongerType(intfCloneable, arrayOfA));
}
@Override
@@ -220,6 +239,9 @@
classJso = createClass("com.google.gwt.core.client.JavaScriptObject",
classObject, false, false);
+ intfSerializable = createInterface("java.io.Serializable");
+ intfCloneable = createInterface("java.lang.Cloneable");
+
intfIBase = createInterface("IBase");
intfI = createInterface("I");
diff --git a/user/test/com/google/gwt/dev/jjs/test/ClassCastTest.java b/user/test/com/google/gwt/dev/jjs/test/ClassCastTest.java
index 79eabce..8cd751d 100644
--- a/user/test/com/google/gwt/dev/jjs/test/ClassCastTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/ClassCastTest.java
@@ -16,9 +16,12 @@
package com.google.gwt.dev.jjs.test;
import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.ui.Widget;
+
+import java.io.Serializable;
/**
- * TODO: document me.
+ * Test type casts and <code>instanceof</code>.
*/
@SuppressWarnings("unused")
public class ClassCastTest extends GWTTestCase {
@@ -32,14 +35,27 @@
static abstract class Food {
}
- private final Food foodItem = new Apple();
+ private volatile Object arrayOfInt = new int[3];
+ private volatile Object arrayOfWidget = new Widget[4];
+ private volatile Food foodItem = new Apple();
+ private volatile CanEatRaw rawFoodItem = new Apple();
- private final CanEatRaw rawFoodItem = new Apple();
-
+ @Override
public String getModuleName() {
return "com.google.gwt.dev.jjs.CompilerSuite";
}
+ public void testArrayInterfaces() {
+ assertTrue(arrayOfInt instanceof Serializable);
+ assertTrue(arrayOfWidget instanceof Serializable);
+
+ assertTrue(arrayOfInt instanceof Cloneable);
+ assertTrue(arrayOfWidget instanceof Cloneable);
+
+ assertFalse(arrayOfInt instanceof Food);
+ assertFalse(arrayOfWidget instanceof Food);
+ }
+
public void testBaseToInterface() {
Apple apple = (Apple) foodItem;
}