Revision: 8668
Author: [email protected]
Date: Mon Aug 30 07:43:31 2010
Log: Removed Object.typeId from generated class prototypes, and from the compilation and linkage phases. Type cast checking depends only on the castableTypeMaps and queryIds now. Fixed a bug in deRPC for preserving meta data in transmitted Arrays for proper element assignment type checking.

Review at http://gwt-code-reviews.appspot.com/751803

http://code.google.com/p/google-web-toolkit/source/detail?r=8668

Modified:
 /trunk/dev/core/src/com/google/gwt/core/ext/linker/SymbolData.java
/trunk/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSymbolData.java
 /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
 /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java
 /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
 /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
/trunk/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java /trunk/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java /trunk/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Util.java
 /trunk/user/src/com/google/gwt/rpc/linker/ClientOracleLinker.java
 /trunk/user/src/com/google/gwt/rpc/server/ClientOracle.java
 /trunk/user/src/com/google/gwt/rpc/server/DelegatingClientOracle.java
 /trunk/user/src/com/google/gwt/rpc/server/HostedModeClientOracle.java
 /trunk/user/src/com/google/gwt/rpc/server/WebModeClientOracle.java
 /trunk/user/src/com/google/gwt/rpc/server/WebModePayloadSink.java
 /trunk/user/super/com/google/gwt/emul/java/lang/Object.java
 /trunk/user/test/com/google/gwt/dev/jjs/test/ClassCastTest.java
 /trunk/user/test/com/google/gwt/emultest/java/lang/ObjectTest.java
 /trunk/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
 /trunk/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java

=======================================
--- /trunk/dev/core/src/com/google/gwt/core/ext/linker/SymbolData.java Mon Aug 16 17:56:17 2010 +++ /trunk/dev/core/src/com/google/gwt/core/ext/linker/SymbolData.java Mon Aug 30 07:43:31 2010
@@ -102,6 +102,11 @@
    */
   String getMemberName();

+  /**
+   * Returns the queryId for castability comparisons.
+   */
+  int getQueryId();
+
   /**
    * Returns the line number on which the symbol was originally declared or
    * <code>-1</code> if the line number is unknown.
@@ -120,11 +125,6 @@
    */
   String getSymbolName();

-  /**
- * Returns the typeId or <code>0</code> if the type does not have a typeId.
-   */
-  int getTypeId();
-
   /**
    * Returns <code>true</code> if the symbol represents a class.
    */
=======================================
--- /trunk/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSymbolData.java Mon Aug 16 17:56:17 2010 +++ /trunk/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSymbolData.java Mon Aug 30 07:43:31 2010
@@ -32,9 +32,9 @@
 public class StandardSymbolData implements SymbolData {

public static StandardSymbolData forClass(String className, String uriString,
-      int lineNumber, int typeId, CastableTypeMap castableTypeMap) {
+      int lineNumber, int queryId, CastableTypeMap castableTypeMap) {
return new StandardSymbolData(className, null, null, uriString, lineNumber,
-        typeId, castableTypeMap);
+        queryId, castableTypeMap);
   }

   public static StandardSymbolData forMember(String className,
@@ -62,11 +62,11 @@
   private int sourceLine;
   private String sourceUri;
   private String symbolName;
-  private int typeId;
+  private int queryId;
   private CastableTypeMap castableTypeMap;

   private StandardSymbolData(String className, String memberName,
-      String methodSig, String sourceUri, int sourceLine, int typeId,
+      String methodSig, String sourceUri, int sourceLine, int queryId,
       CastableTypeMap castableTypeMap) {
     assert className != null && className.length() > 0 : "className";
assert memberName != null || methodSig == null : "methodSig without memberName";
@@ -77,7 +77,7 @@
     this.methodSig = methodSig;
     this.sourceUri = sourceUri;
     this.sourceLine = sourceLine;
-    this.typeId = typeId;
+    this.queryId = queryId;
     this.castableTypeMap = castableTypeMap;
   }

@@ -102,6 +102,10 @@
   public String getMemberName() {
     return memberName;
   }
+
+  public int getQueryId() {
+    return queryId;
+  }

   public int getSourceLine() {
     return sourceLine;
@@ -114,10 +118,6 @@
   public String getSymbolName() {
     return symbolName;
   }
-
-  public int getTypeId() {
-    return typeId;
-  }

   public boolean isClass() {
     return memberName == null;
@@ -159,7 +159,7 @@
     sourceLine = in.readInt();
     sourceUri = (String) in.readObject();
     symbolName = in.readUTF();
-    typeId = in.readInt();
+    queryId = in.readInt();
     castableTypeMap = (CastableTypeMap) in.readObject();
   }

@@ -187,7 +187,7 @@
     out.writeInt(sourceLine);
     out.writeObject(sourceUri);
     out.writeUTF(symbolName);
-    out.writeInt(typeId);
+    out.writeInt(queryId);
     out.writeObject(castableTypeMap);
   }
 }
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java Thu Aug 19 13:25:39 2010 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java Mon Aug 30 04:31:11 2010
@@ -318,7 +318,7 @@
    */
   private final SourceInfo intrinsic;

-  private List<JsonObject> jsonCastableTypeMaps;
+  private IdentityHashMap<JReferenceType, JsonObject> castableTypeMaps;

private Map<JReferenceType, JNonNullType> nonNullTypes = new IdentityHashMap<JReferenceType, JNonNullType>();

@@ -348,8 +348,6 @@

   private JClassType typeClass;

- private Map<JReferenceType, Integer> typeIdMap = new HashMap<JReferenceType, Integer>();
-
   private JInterfaceType typeJavaIoSerializable;

   private JInterfaceType typeJavaLangCloneable;
@@ -766,18 +764,23 @@
     return allEntryMethods;
   }

-  public JsonObject getCastableTypeMap(int typeId) {
+  public JsonObject getCastableTypeMap(JReferenceType referenceType) {
+
     // ensure jsonCastableTypeMaps has been initialized
     // it might not have been if the CastNormalizer has not been run
-    if (jsonCastableTypeMaps == null) {
-      jsonCastableTypeMaps = new ArrayList<JsonObject>();
-      // ensure the always-false (typeId == 0) entry is present
-      jsonCastableTypeMaps.add(new JsonObject(createSourceInfoSynthetic(
-          JProgram.class, "always-false typeinfo entry"),
-          getJavaScriptObject()));
+    if (castableTypeMaps == null) {
+      initTypeInfo(null);
     }

-    return jsonCastableTypeMaps.get(typeId);
+    JsonObject returnMap = castableTypeMaps.get(referenceType);
+    if (returnMap == null) {
+      // add a new empty map
+      returnMap = new JsonObject(createSourceInfoSynthetic(JProgram.class,
+ "empty map"), getJavaScriptObject());
+      castableTypeMaps.put(referenceType, returnMap);
+    }
+
+    return returnMap;
   }

   public CorrelationFactory getCorrelator() {
@@ -1099,16 +1102,6 @@
       return getTypeArray(type, dim);
     }
   }
-
-  public int getTypeId(JReferenceType referenceType) {
-    assert (referenceType == getRunTimeType(referenceType));
-    Integer integer = typeIdMap.get(referenceType);
-    if (integer == null) {
-      return 0;
-    }
-
-    return integer.intValue();
-  }

   public JClassType getTypeJavaLangClass() {
     return typeClass;
@@ -1165,13 +1158,15 @@
   public JPrimitiveType getTypeVoid() {
     return JPrimitiveType.VOID;
   }
-
-  public void initTypeInfo(List<JReferenceType> types,
-      List<JsonObject> jsonObjects) {
-    for (int i = 0, c = types.size(); i < c; ++i) {
-      typeIdMap.put(types.get(i), Integer.valueOf(i));
-    }
-    this.jsonCastableTypeMaps = jsonObjects;
+
+  public void initTypeInfo(
+ IdentityHashMap<JReferenceType,JsonObject> instantiatedTypeCastableTypeMaps) {
+
+    castableTypeMaps = instantiatedTypeCastableTypeMaps;
+
+    if (castableTypeMaps == null || castableTypeMaps.size() == 0) {
+      castableTypeMaps = new IdentityHashMap<JReferenceType, JsonObject>();
+    }
   }

   public boolean isJavaLangString(JType type) {
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java Mon Aug 16 17:56:17 2010 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java Mon Aug 30 04:31:11 2010
@@ -124,15 +124,11 @@
       JMethodCall call = new JMethodCall(x.getSourceInfo(), null, initDim,
           arrayType);
       JLiteral classLit = x.getClassLiteral();
-
-      int typeId = program.getTypeId(arrayType);
-      JLiteral typeIdLit = program.getLiteralInt(typeId);
-      JsonObject castableTypeMap = program.getCastableTypeMap(typeId);
-
+      JsonObject castableTypeMap = program.getCastableTypeMap(arrayType);
JLiteral queryIdLit = program.getLiteralInt(tryGetQueryId(arrayType));
       JExpression dim = x.dims.get(0);
       JType elementType = arrayType.getElementType();
-      call.addArgs(classLit, typeIdLit, castableTypeMap, queryIdLit, dim,
+      call.addArgs(classLit, castableTypeMap, queryIdLit, dim,
           getSeedTypeLiteralFor(elementType));
       ctx.replaceMe(call);
     }
@@ -145,8 +141,6 @@
JMethodCall call = new JMethodCall(sourceInfo, null, initDims, arrayType);
       JsonArray classLitList = new JsonArray(sourceInfo,
           program.getJavaScriptObject());
-      JsonArray typeIdList = new JsonArray(sourceInfo,
-          program.getJavaScriptObject());
       JsonArray castableTypeMapList = new JsonArray(sourceInfo,
           program.getJavaScriptObject());
       JsonArray queryIdList = new JsonArray(sourceInfo,
@@ -160,12 +154,8 @@

         JLiteral classLit = x.getClassLiterals().get(i);
         classLitList.exprs.add(classLit);
-
-        int typeId = program.getTypeId(curArrayType);
-        JLiteral typeIdLit = program.getLiteralInt(typeId);
-        typeIdList.exprs.add(typeIdLit);
-
-        JsonObject castableTypeMap = program.getCastableTypeMap(typeId);
+
+ JsonObject castableTypeMap = program.getCastableTypeMap(curArrayType);
         castableTypeMapList.exprs.add(castableTypeMap);

JLiteral queryIdLit = program.getLiteralInt(tryGetQueryId(curArrayType));
@@ -174,7 +164,7 @@
         dimList.exprs.add(x.dims.get(i));
         cur = curArrayType.getElementType();
       }
- call.addArgs(classLitList, typeIdList, castableTypeMapList, queryIdList,
+      call.addArgs(classLitList, castableTypeMapList, queryIdList,
dimList, program.getLiteralInt(dims), getSeedTypeLiteralFor(cur));
       ctx.replaceMe(call);
     }
@@ -187,28 +177,24 @@
       JMethodCall call = new JMethodCall(sourceInfo, null, initValues,
           arrayType);
       JLiteral classLit = x.getClassLiteral();
-
-      int typeId = program.getTypeId(arrayType);
-      JLiteral typeIdLit = program.getLiteralInt(typeId);
-      JsonObject castableTypeMap = program.getCastableTypeMap(typeId);
-
+      JsonObject castableTypeMap = program.getCastableTypeMap(arrayType);
JLiteral queryIdLit = program.getLiteralInt(tryGetQueryId(arrayType));
       JsonArray initList = new JsonArray(sourceInfo,
           program.getJavaScriptObject());
       for (int i = 0; i < x.initializers.size(); ++i) {
         initList.exprs.add(x.initializers.get(i));
       }
- call.addArgs(classLit, typeIdLit, castableTypeMap, queryIdLit, initList);
+      call.addArgs(classLit, castableTypeMap, queryIdLit, initList);
       ctx.replaceMe(call);
     }

     private int tryGetQueryId(JArrayType type) {
       JType elementType = type.getElementType();
-      int leafTypeId = -1;
+      int leafQueryId = -1;
       if (elementType instanceof JReferenceType) {
- leafTypeId = program.getQueryId(program.getRunTimeType((JReferenceType) elementType));
-      }
-      return leafTypeId;
+ leafQueryId = program.getQueryId(program.getRunTimeType((JReferenceType) elementType));
+      }
+      return leafQueryId;
     }
   }

=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java Wed Mar 10 15:24:26 2010 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java Mon Aug 30 04:31:11 2010
@@ -53,11 +53,6 @@
  * on {...@link CatchBlockNormalizer}, {...@link CompoundAssignmentNormalizer},
* {...@link JsoDevirtualizer}, and {...@link LongCastNormalizer} having already run.
  *
- * <p>
- * Object and String always get a typeId of 1 and 2, respectively. 0 is reserved - * as the typeId for any classes that can never be instance type of a successful
- * dynamic cast.
- * </p>
  * <p>
  * Object and String always get a queryId of 0 and 1, respectively. The 0
* queryId always means "always succeeds". In practice, we never generate an
@@ -65,20 +60,21 @@
  * where the 0 queryId means that anything can be stored into an Object[].
  * </p>
  * <p>
- * JavaScriptObject and subclasses have no typeId at all. JavaScriptObject has a - * queryId of -1, which again is only used for array store checking, to ensure
- * that a non-JSO is not stored into a JavaScriptObject[].
+ * JavaScriptObject has a queryId of -1, which again is only used for array store + * checking, to ensure that a non-JSO is not stored into a JavaScriptObject[].
  * </p>
  */
 public class CastNormalizer {
-  private class AssignTypeIdsVisitor extends JVisitor {
+  private class AssignTypeCastabilityVisitor extends JVisitor {

     Set<JReferenceType> alreadyRan = new HashSet<JReferenceType>();
- private List<JReferenceType> instantiableTypes = new ArrayList<JReferenceType>(); - private final List<JArrayType> instantiatedArrayTypes = new ArrayList<JArrayType>();
-    private List<JsonObject> jsonObjects = new ArrayList<JsonObject>();
+    private IdentityHashMap<JReferenceType, JsonObject>
+ castableTypeMaps = new IdentityHashMap<JReferenceType, JsonObject>();
+    private final List<JArrayType> instantiatedArrayTypes =
+          new ArrayList<JArrayType>();
     private int nextQueryId = 0;
- private Map<JReferenceType, Set<JReferenceType>> queriedTypes = new IdentityHashMap<JReferenceType, Set<JReferenceType>>();
+    private Map<JReferenceType, Set<JReferenceType>> queriedTypes =
+          new IdentityHashMap<JReferenceType, Set<JReferenceType>>();

     {
       JTypeOracle typeOracle = program.typeOracle;
@@ -93,26 +89,17 @@
           program.getTypeJavaLangObject());

// Reserve query id 1 for java.lang.String to facilitate the mashup case. + // Also, facilitates detecting an object as a Java String (see Cast.java) // Multiple GWT modules need to modify String's prototype the same way.
       recordCastInternal(program.getTypeJavaLangString(),
           program.getTypeJavaLangObject());
     }

-    public void computeTypeIds() {
-
-      // the 0th entry is the "always false" entry
-      instantiableTypes.add(null);
-      jsonObjects.add(new JsonObject(program.createSourceInfoSynthetic(
-          AssignTypeIdsVisitor.class, "always-false typeinfo entry"),
-          program.getJavaScriptObject()));
-
-      /*
-       * Do String first to reserve typeIds 1 and 2 for Object and String,
-       * respectively. This ensures consistent modification of String's
-       * prototype.
-       */
+    public void computeTypeCastabilityMaps() {
+
+      // do String first (which will pull in Object also, it's superclass).
       computeSourceType(program.getTypeJavaLangString());
-      assert (instantiableTypes.size() == 3);
+      assert (castableTypeMaps.size() == 3);

       /*
        * Compute the list of classes than can successfully satisfy cast
@@ -130,9 +117,9 @@
       }

       // pass our info to JProgram
-      program.initTypeInfo(instantiableTypes, jsonObjects);
-
-      // JSO's maker queryId is -1 (used for array stores).
+      program.initTypeInfo(castableTypeMaps);
+
+      // JSO's marker queryId is -1 (used for array stores).
       JClassType jsoType = program.getJavaScriptObject();
       if (jsoType != null) {
         queryIds.put(jsoType, -1);
@@ -156,7 +143,6 @@
           // will generate a null pointer exception instead
           return;
         }
-        JArrayType lhsArrayType = lhsArrayRef.getArrayType();

         // primitives are statically correct
         if (!(elementType instanceof JReferenceType)) {
@@ -177,6 +163,7 @@
         JType rhsType = x.getRhs().getType();
         assert (rhsType instanceof JReferenceType);

+        JArrayType lhsArrayType = lhsArrayRef.getArrayType();
         for (JArrayType arrayType : instantiatedArrayTypes) {
           if (typeOracle.canTheoreticallyCast(arrayType, lhsArrayType)) {
             JType itElementType = arrayType.getElementType();
@@ -257,7 +244,7 @@

       // Create a sparse lookup object.
       SourceInfo sourceInfo = program.createSourceInfoSynthetic(
-          AssignTypeIdsVisitor.class, "typeinfo lookup");
+          AssignTypeCastabilityVisitor.class, "typeinfo lookup");
       JsonObject jsonObject = new JsonObject(sourceInfo,
           program.getJavaScriptObject());
       // Start at 1; 0 is Object and always true.
@@ -272,7 +259,7 @@

       /*
* Don't add an entry for empty answer sets, except for Object and String
-       * which require typeIds.
+       * which require entries.
        */
       if (jsonObject.propInits.isEmpty()
           && type != program.getTypeJavaLangObject()
@@ -281,8 +268,7 @@
       }

       // add an entry for me
-      instantiableTypes.add(type);
-      jsonObjects.add(jsonObject);
+      castableTypeMaps.put(type,jsonObject);
     }

     private void recordCast(JType targetType, JExpression rhs) {
@@ -604,9 +590,9 @@
       visitor.accept(program);
     }
     {
-      AssignTypeIdsVisitor assigner = new AssignTypeIdsVisitor();
+ AssignTypeCastabilityVisitor assigner = new AssignTypeCastabilityVisitor();
       assigner.accept(program);
-      assigner.computeTypeIds();
+      assigner.computeTypeCastabilityMaps();
     }
     {
       ReplaceTypeChecksVisitor replacer = new ReplaceTypeChecksVisitor();
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java Mon Aug 16 17:56:17 2010 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java Mon Aug 30 04:31:11 2010
@@ -118,7 +118,6 @@
 import com.google.gwt.dev.js.ast.JsNameRef;
 import com.google.gwt.dev.js.ast.JsNew;
 import com.google.gwt.dev.js.ast.JsNode;
-import com.google.gwt.dev.js.ast.JsNumberLiteral;
 import com.google.gwt.dev.js.ast.JsObjectLiteral;
 import com.google.gwt.dev.js.ast.JsParameter;
 import com.google.gwt.dev.js.ast.JsPostfixOperation;
@@ -445,14 +444,13 @@
     }

     private void recordSymbol(JReferenceType x, JsName jsName) {
-      int typeId = program.getTypeId(x);
-
-      JsonObject castableTypeMapObj = program.getCastableTypeMap(typeId);
+      int queryId = program.getQueryId(x);
+      JsonObject castableTypeMapObj = program.getCastableTypeMap(x);
CastableTypeMap castableTypeMap = new StandardCastableTypeMap(castableTypeMapObj.toString());

StandardSymbolData symbolData = StandardSymbolData.forClass(x.getName(), x.getSourceInfo().getFileName(), x.getSourceInfo().getStartLine(),
-          typeId, castableTypeMap);
+          queryId, castableTypeMap);
       assert !symbolTable.containsKey(symbolData);
       symbolTable.put(symbolData, jsName);
     }
@@ -1500,9 +1498,9 @@
           lhs, rhs);
     }

- private void generateCastableTypeIds(JClassType x, List<JsStatement> globalStmts) {
-      int typeId = program.getTypeId(x);
-      if (typeId >= 0) {
+ private void generateCastableTypeMap(JClassType x, List<JsStatement> globalStmts) {
+      JsonObject castableTypeMap = program.getCastableTypeMap(x);
+      if (castableTypeMap != null) {
JField castableTypeMapField = program.getIndexedField("Object.castableTypeMap");
         JsName castableTypeMapName = names.get(castableTypeMapField);
         if (castableTypeMapName == null) {
@@ -1513,8 +1511,7 @@
         SourceInfo sourceInfo = jsProgram.createSourceInfoSynthetic(
               GenerateJavaScriptAST.class, "Castable type map");

-        JsonObject jsonObject = program.getCastableTypeMap(typeId);
-        accept(jsonObject);
+        accept(castableTypeMap);
         JsExpression objExpr = pop();

         // Generate castableTypeMap for each type prototype
@@ -1564,8 +1561,7 @@
         generateTypeMarker(globalStmts);
       }

-      generateTypeId(x, globalStmts);
-      generateCastableTypeIds(x, globalStmts);
+      generateCastableTypeMap(x, globalStmts);
     }

     private void generateGwtOnLoad(List<JsFunction> entryFuncs,
@@ -1787,27 +1783,6 @@
         typeForStatMap.put(stmt, program.getTypeJavaLangObject());
       }
     }
-
- private void generateTypeId(JClassType x, List<JsStatement> globalStmts) {
-      int typeId = program.getTypeId(x);
-      if (typeId >= 0) {
-        JField typeIdField = program.getIndexedField("Object.typeId");
-        JsName typeIdName = names.get(typeIdField);
-        if (typeIdName == null) {
-          // Was pruned; this compilation must have no dynamic casts.
-          return;
-        }
-        SourceInfo sourceInfo = x.getSourceInfo().makeChild(
-            GenerateJavaScriptVisitor.class, "Type id assignment");
-        JsNameRef fieldRef = typeIdName.makeRef(sourceInfo);
-        fieldRef.setQualifier(globalTemp.makeRef(sourceInfo));
-        JsNumberLiteral typeIdLit = jsProgram.getNumberLiteral(typeId);
-        JsExpression asg = createAssignment(fieldRef, typeIdLit);
-        JsExprStmt asgStmt = asg.makeStmt();
-        globalStmts.add(asgStmt);
-        typeForStatMap.put(asgStmt, x);
-      }
-    }

     private void generateTypeMarker(List<JsStatement> globalStmts) {
JField typeMarkerField = program.getIndexedField("Object.typeMarker");
@@ -2156,7 +2131,6 @@

     // Object fields
     specialObfuscatedIdents.put("expando", "eX");
-    specialObfuscatedIdents.put("typeId", "tI");
     specialObfuscatedIdents.put("typeMarker", "tM");
     specialObfuscatedIdents.put("castableTypeMap", "cM");

=======================================
--- /trunk/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java Mon Aug 16 17:56:17 2010 +++ /trunk/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java Mon Aug 30 04:31:11 2010
@@ -97,8 +97,7 @@
public static <T> T[] cloneSubrange(T[] array, int fromIndex, int toIndex) {
     Array a = asArrayType(array);
     Array result = arraySlice(a, fromIndex, toIndex);
-    initValues(a.getClass(), Util.getTypeId(a),
-        Util.getCastableTypeMap(a), a.queryId, result);
+ initValues(a.getClass(), Util.getCastableTypeMap(a), a.queryId, result);
     // implicit type arg not inferred (as of JDK 1.5.0_07)
     return Array.<T> asArray(result);
   }
@@ -117,8 +116,7 @@
   public static <T> T[] createFrom(T[] array, int length) {
     Array a = asArrayType(array);
     Array result = createFromSeed(NULL_SEED_TYPE, length);
-    initValues(a.getClass(), Util.getTypeId(a),
-        Util.getCastableTypeMap(a), a.queryId, result);
+ initValues(a.getClass(), Util.getCastableTypeMap(a), a.queryId, result);
     // implicit type arg not inferred (as of JDK 1.5.0_07)
     return Array.<T> asArray(result);
   }
@@ -128,18 +126,17 @@
    * array, [a, b, c].
    *
    * @param arrayClass the class of the array
-   * @param typeId the typeId of the array
* @param castableTypeMap the map of types to which this array can be casted,
    *          in the form of a JSON map object
    * @param queryId the queryId of the array
    * @param length the length of the array
- * @param seedType the primitive type of the array; 0: null; 1: zero; 2: false + * @param seedType the primitive type of the array; 0: null; 1: zero; 2: false; 3: long
    * @return the new array
    */
-  public static Array initDim(Class<?> arrayClass, int typeId,
+  public static Array initDim(Class<?> arrayClass,
JavaScriptObject castableTypeMap, int queryId, int length, int seedType) {
     Array result = createFromSeed(seedType, length);
-    initValues(arrayClass, typeId, castableTypeMap, queryId, result);
+    initValues(arrayClass, castableTypeMap, queryId, result);
     return result;
   }

@@ -148,18 +145,17 @@
    * array, [a, b, c].
    *
    * @param arrayClasses the class of each dimension of the array
- * @param typeIdExprs the typeId of each dimension, from highest to lowest * @param castableTypeMapExprs the JSON castableTypeMap of each dimension,
    *          from highest to lowest
* @param queryIdExprs the queryId of each dimension, from highest to lowest
    * @param dimExprs the length of each dimension, from highest to lower
- * @param seedType the primitive type of the array; 0: null; 1: zero; 2: false + * @param seedType the primitive type of the array; 0: null; 1: zero; 2: false; 3: long
    * @return the new array
    */
-  public static Array initDims(Class<?> arrayClasses[], int[] typeIdExprs,
- JavaScriptObject[] castableTypeMapExprs, int[] queryIdExprs, int[] dimExprs,
-      int count, int seedType) {
- return initDims(arrayClasses, typeIdExprs, castableTypeMapExprs, queryIdExprs,
+  public static Array initDims(Class<?> arrayClasses[],
+      JavaScriptObject[] castableTypeMapExprs, int[] queryIdExprs,
+      int[] dimExprs, int count, int seedType) {
+    return initDims(arrayClasses, castableTypeMapExprs, queryIdExprs,
         dimExprs, 0, count, seedType);
   }

@@ -168,18 +164,16 @@
    * array, [a, b, c, d].
    *
    * @param arrayClass the class of the array
-   * @param typeId the typeId of the array
* @param castableTypeMap the map of types to which this array can be casted,
    *          in the form of a JSON map object
    * @param queryId the queryId of the array
    * @param array the JSON array that will be transformed into a GWT array
    * @return values; having wrapped it for GWT
    */
-  public static Array initValues(Class<?> arrayClass, int typeId,
+  public static Array initValues(Class<?> arrayClass,
       JavaScriptObject castableTypeMap, int queryId, Array array) {
     ExpandoWrapper.wrapArray(array);
     array.arrayClass = arrayClass;
-    Util.setTypeId(array, typeId);
     Util.setCastableTypeMap(array, castableTypeMap);
     array.queryId = queryId;
     return array;
@@ -227,6 +221,7 @@
    * @see #NULL_SEED_TYPE
    * @see #ZERO_SEED_TYPE
    * @see #FALSE_SEED_TYPE
+   * @see #LONG_SEED_TYPE
    * @return the new JSON array
    */
   private static native Array createFromSeed(int seedType, int length) /*-{
@@ -247,22 +242,21 @@
     return array;
   }-*/;

-  private static Array initDims(Class<?> arrayClasses[], int[] typeIdExprs,
+  private static Array initDims(Class<?> arrayClasses[],
JavaScriptObject[] castableTypeMapExprs, int[] queryIdExprs, int[] dimExprs,
       int index, int count, int seedType) {
-
     int length = dimExprs[index];
     boolean isLastDim = (index == (count - 1));

Array result = createFromSeed(isLastDim ? seedType : NULL_SEED_TYPE, length);
-    initValues(arrayClasses[index], typeIdExprs[index],
-        castableTypeMapExprs[index], queryIdExprs[index], result);
+    initValues(arrayClasses[index], castableTypeMapExprs[index],
+        queryIdExprs[index], result);

     if (!isLastDim) {
       // Recurse to next dimension.
       ++index;
       for (int i = 0; i < length; ++i) {
- set(result, i, initDims(arrayClasses, typeIdExprs, castableTypeMapExprs,
+        set(result, i, initDims(arrayClasses, castableTypeMapExprs,
             queryIdExprs, dimExprs, index, count, seedType));
       }
     }
=======================================
--- /trunk/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java Mon Aug 16 17:56:17 2010 +++ /trunk/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java Mon Aug 30 04:31:11 2010
@@ -26,7 +26,7 @@
 final class Cast {

   static native boolean canCast(Object src, int dstId) /*-{
-    return [email protected]::typeId &&
+    return [email protected]::castableTypeMap &&
           [email protected]::castableTypeMap[dstId];
   }-*/;

@@ -35,7 +35,7 @@
    * context.
    */
   static native boolean canCastUnsafe(Object src, int dstId) /*-{
-    return [email protected]::typeId &&
+    return [email protected]::castableTypeMap &&
           [email protected]::castableTypeMap[dstId];
   }-*/;

@@ -75,9 +75,6 @@
     return (src != null) && canCast(src, dstId);
   }

-  /**
-   * Instance of JSO only if there's no type ID.
-   */
   static boolean instanceOfJso(Object src) {
     return (src != null) && isJavaScriptObject(src);
   }
@@ -92,15 +89,15 @@
   }

   static boolean isJavaObject(Object src) {
- return Util.getTypeMarker(src) == getNullMethod() || Util.getTypeId(src) == 2;
+    return isNonStringJavaObject(src) || isJavaString(src);
   }

   static boolean isJavaScriptObject(Object src) {
- return Util.getTypeMarker(src) != getNullMethod() && Util.getTypeId(src) != 2;
+    return !isNonStringJavaObject(src) && !isJavaString(src);
   }

   static boolean isJavaScriptObjectOrString(Object src) {
-    return Util.getTypeMarker(src) != getNullMethod();
+    return !isNonStringJavaObject(src);
   }

   /**
@@ -208,6 +205,35 @@
     return @null::nullMethod();
   }-*/;

+  /**
+   * Returns whether the Object is a Java String.
+   *
+   * Depends on the requirement that queryId = 1 is reserved for String,
+   * and that the trivial cast String to String is explicitly added to the
+ * castableTypeMap for String, and String cannot be the target of a cast from
+   * anything else (except for the trivial cast from Object), since
+   * java.lang.String is a final class.
+ * (See the constructor for the CastNormalizer.AssignTypeCastabilityVisitor).
+   *
+ * Since java Strings are translated as JavaScript strings, Strings need to be
+   * interchangeable between GWT modules, unlike other Java Objects.
+   */
+  private static boolean isJavaString(Object src) {
+    return canCast(src, 1);
+  }
+
+  /**
+   * Returns whether the Object is a Java Object but not a String.
+   *
+ * Depends on all Java Objects (except for String) having the typeMarker field + * generated, and set to the nullMethod for the current GWT module. Note this + * test essentially tests whether an Object is a java object for the current + * GWT module. Java Objects from external GWT modules are not recognizable as
+   * Java Objects in this context.
+   */
+  private static boolean isNonStringJavaObject(Object src) {
+    return Util.getTypeMarker(src) == getNullMethod();
+  }
 }

 // CHECKSTYLE_NAMING_ON
=======================================
--- /trunk/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Util.java Mon Aug 16 17:56:17 2010 +++ /trunk/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Util.java Mon Aug 30 04:31:11 2010
@@ -18,29 +18,21 @@
 import com.google.gwt.core.client.JavaScriptObject;

 /**
- * This class is used to access the private, GWT-specific typeId and typeMarker
- * fields.
+ * This class is used to access the private, GWT-specific
+ * castableTypeMap and typeMarker fields.
  */
 final class Util {
-
+
   static native JavaScriptObject getCastableTypeMap(Object o) /*-{
     return [email protected]::castableTypeMap;
   }-*/;

-  static native int getTypeId(Object o) /*-{
-    return [email protected]::typeId;
-  }-*/;
-
   static native JavaScriptObject getTypeMarker(Object o) /*-{
     return [email protected]::typeMarker;
   }-*/;
-
+
static native void setCastableTypeMap(Object o, JavaScriptObject castableTypeMap) /*-{
     [email protected]::castableTypeMap = castableTypeMap;
   }-*/;

-  static native void setTypeId(Object o, int typeId) /*-{
-    [email protected]::typeId = typeId;
-  }-*/;
-
-}
+}
=======================================
--- /trunk/user/src/com/google/gwt/rpc/linker/ClientOracleLinker.java Mon Aug 16 17:56:17 2010 +++ /trunk/user/src/com/google/gwt/rpc/linker/ClientOracleLinker.java Mon Aug 30 04:31:11 2010
@@ -71,7 +71,7 @@
         for (SymbolData symbolData : result.getSymbolMap()) {
builder.add(symbolData.getSymbolName(), symbolData.getJsniIdent(),
               symbolData.getClassName(), symbolData.getMemberName(),
-              symbolData.getTypeId(),
+              symbolData.getQueryId(),
               new CastableTypeDataImpl(symbolData.getCastableTypeMap()));
         }

=======================================
--- /trunk/user/src/com/google/gwt/rpc/server/ClientOracle.java Mon Aug 16 17:56:17 2010 +++ /trunk/user/src/com/google/gwt/rpc/server/ClientOracle.java Mon Aug 30 04:31:11 2010
@@ -105,15 +105,15 @@
   public abstract Field[] getOperableFields(Class<?> clazz);

   /**
-   * Returns the name of the top-level function that is used as the seed
-   * function for a given type.
+   * Returns the assigned castability queryId of a given type.
    */
-  public abstract String getSeedName(Class<?> clazz);
+  public abstract int getQueryId(Class<?> clazz);

   /**
-   * Returns the assigned typeId of a given type or 0.
+   * Returns the name of the top-level function that is used as the seed
+   * function for a given type.
    */
-  public abstract int getTypeId(Class<?> clazz);
+  public abstract String getSeedName(Class<?> clazz);

   /**
* Returns the deobfuscated name of a type based on the name of the type's
=======================================
--- /trunk/user/src/com/google/gwt/rpc/server/DelegatingClientOracle.java Mon Aug 16 17:56:17 2010 +++ /trunk/user/src/com/google/gwt/rpc/server/DelegatingClientOracle.java Mon Aug 30 04:31:11 2010
@@ -85,13 +85,13 @@
   }

   @Override
-  public String getSeedName(Class<?> clazz) {
-    return delegate.getSeedName(clazz);
+  public int getQueryId(Class<?> clazz) {
+    return delegate.getQueryId(clazz);
   }

   @Override
-  public int getTypeId(Class<?> clazz) {
-    return delegate.getTypeId(clazz);
+  public String getSeedName(Class<?> clazz) {
+    return delegate.getSeedName(clazz);
   }

   @Override
=======================================
--- /trunk/user/src/com/google/gwt/rpc/server/HostedModeClientOracle.java Mon Aug 16 17:56:17 2010 +++ /trunk/user/src/com/google/gwt/rpc/server/HostedModeClientOracle.java Mon Aug 30 04:31:11 2010
@@ -132,16 +132,16 @@
    * Unimplemented.
    */
   @Override
-  public String getSeedName(Class<?> clazz) {
-    return unimplemented();
+  public int getQueryId(Class<?> clazz) {
+    return this.<Integer> unimplemented();
   }

   /**
    * Unimplemented.
    */
   @Override
-  public int getTypeId(Class<?> clazz) {
-    return this.<Integer> unimplemented();
+  public String getSeedName(Class<?> clazz) {
+    return unimplemented();
   }

   /**
=======================================
--- /trunk/user/src/com/google/gwt/rpc/server/WebModeClientOracle.java Mon Aug 16 17:56:17 2010 +++ /trunk/user/src/com/google/gwt/rpc/server/WebModeClientOracle.java Mon Aug 30 04:31:11 2010
@@ -52,11 +52,23 @@
     private WebModeClientOracle oracle = new WebModeClientOracle();

     public void add(String jsIdent, String jsniIdent, String className,
-        String memberName, int typeId, CastableTypeData castableTypeData) {
+ String memberName, int queryId, CastableTypeData castableTypeData) {
+
       oracle.idents.add(jsIdent);
       ClassData data = oracle.getClassData(className);
-      data.typeId = typeId;
-      data.castableTypeData = castableTypeData;
+
+      /*
+       * Don't overwrite castableTypeData and queryId if already set.
+       * There are many versions of symbols for a given className,
+       * corresponding to the type of member fields, etc.,
+ * which don't have the queryId or castableTypeData initialized. Only
+       * the symbol data for the class itself has this info.
+       */
+      if (data.castableTypeData == null) {
+        data.queryId = queryId;
+        data.castableTypeData = castableTypeData;
+      }
+
       if (jsniIdent == null || jsniIdent.length() == 0) {
         data.typeName = className;
         data.seedName = jsIdent;
@@ -109,15 +121,15 @@
   }

   private static class ClassData implements Serializable {
-    private static final long serialVersionUID = 4L;
+    private static final long serialVersionUID = 5L;

     public CastableTypeData castableTypeData;
public final Map<String, String> fieldIdentsToNames = new HashMap<String, String>(); public final Map<String, String> fieldNamesToIdents = new HashMap<String, String>(); public final Map<String, String> methodJsniNamesToIdents = new HashMap<String, String>();
+    public int queryId;
     public String seedName;
     public List<String> serializableFields = Collections.emptyList();
-    public int typeId;
     public String typeName;
   }

@@ -345,15 +357,9 @@
   }

   @Override
-  public String getSeedName(Class<?> clazz) {
-    ClassData data = getClassData(clazz.getName());
-    return data.seedName;
-  }
-
-  @Override
-  public int getTypeId(Class<?> clazz) {
+  public int getQueryId(Class<?> clazz) {
     while (clazz != null) {
-      int toReturn = getTypeId(canonicalName(clazz));
+      int toReturn = getQueryId(canonicalName(clazz));
       if (toReturn != 0) {
         return toReturn;
       }
@@ -361,6 +367,12 @@
     }
     return 0;
   }
+
+  @Override
+  public String getSeedName(Class<?> clazz) {
+    ClassData data = getClassData(clazz.getName());
+    return data.seedName;
+  }

   @Override
   public String getTypeName(String seedName) {
@@ -437,9 +449,9 @@
     return getMethodId(className, methodName, jsniArgTypes);
   }

-  private int getTypeId(String className) {
+  private int getQueryId(String className) {
     ClassData data = getClassData(className);
-    return data.typeId;
+    return data.queryId;
   }

   /**
=======================================
--- /trunk/user/src/com/google/gwt/rpc/server/WebModePayloadSink.java Mon Aug 16 17:56:17 2010 +++ /trunk/user/src/com/google/gwt/rpc/server/WebModePayloadSink.java Mon Aug 30 04:31:11 2010
@@ -532,7 +532,7 @@
       }

       String initValuesId = clientOracle.getMethodId(
-          "com.google.gwt.lang.Array", "initValues", "Ljava/lang/Class;", "I",
+          "com.google.gwt.lang.Array", "initValues", "Ljava/lang/Class;",
           "Lcom/google/gwt/core/client/JavaScriptObject;", "I",
           "Lcom/google/gwt/lang/Array;");
       assert initValuesId != null : "Could not find initValues";
@@ -547,26 +547,22 @@
       constructorFunctions.put(targetClass, functionName);

       /*
-       * Set the typeIds, castableTypeData, and queryIds to exact values,
+       * Set the castableTypeData and queryIds to exact values,
        * or fall back to acting like a plain Object[] array.
        */
-      CastableTypeData castableTypeData;
-      int typeId = clientOracle.getTypeId(targetClass);
-      if (typeId != 0) {
-        castableTypeData = clientOracle.getCastableTypeData(targetClass);
-      } else {
-        typeId = clientOracle.getTypeId(Object[].class);
+ CastableTypeData castableTypeData = clientOracle.getCastableTypeData(targetClass);
+      if (castableTypeData == null) {
castableTypeData = clientOracle.getCastableTypeData(Object[].class);
       }

-      int queryId = clientOracle.getTypeId(x.getComponentType());
+      int queryId = clientOracle.getQueryId(x.getComponentType());
       if (queryId == 0) {
-        queryId = clientOracle.getTypeId(Object.class);
+        queryId = clientOracle.getQueryId(Object.class);
       }

       byte[] ident = getBytes("_0");

- // function foo(_0) {return initValues(classLid, typeId, queryId, _0)} + // function foo(_0) {return initValues(classLid, castableTypeData, queryId, _0)}
       function();
       push(functionName);
       lparen();
@@ -578,8 +574,6 @@
       lparen();
       push(classLitId);
       comma();
-      push(String.valueOf(typeId));
-      comma();
       push(castableTypeData.toJs());
       comma();
       push(String.valueOf(queryId));
=======================================
--- /trunk/user/super/com/google/gwt/emul/java/lang/Object.java Mon Aug 16 17:56:17 2010 +++ /trunk/user/super/com/google/gwt/emul/java/lang/Object.java Mon Aug 30 04:31:11 2010
@@ -34,14 +34,6 @@
   @SuppressWarnings("unused")
   private transient JavaScriptObject expando;

-  /**
-   * magic magic magic.
-   *
-   * @skip
-   */
-  @SuppressWarnings("unused")
-  private transient int typeId;
-
   /**
    * A JavaScript Json map for looking up castability between types.
    *
=======================================
--- /trunk/user/test/com/google/gwt/dev/jjs/test/ClassCastTest.java Mon Dec 21 10:20:58 2009 +++ /trunk/user/test/com/google/gwt/dev/jjs/test/ClassCastTest.java Mon Aug 30 04:31:11 2010
@@ -34,11 +34,16 @@

   static abstract class Food {
   }
+
+  static class Drink {
+  }

   private volatile Object arrayOfInt = new int[3];
   private volatile Object arrayOfWidget = new Widget[4];
+  private volatile Object arrayOfApple = new Apple[5];
   private volatile Food foodItem = new Apple();
   private volatile CanEatRaw rawFoodItem = new Apple();
+  private volatile Object drinkItem = new Drink();

   @Override
   public String getModuleName() {
@@ -55,15 +60,20 @@
     assertFalse(arrayOfInt instanceof Food);
     assertFalse(arrayOfWidget instanceof Food);
   }
-
+
   public void testBaseToInterface() {
-    Apple apple = (Apple) foodItem;
-  }
-
+    CanEatRaw canEatRaw = (CanEatRaw) foodItem;
+  }
+
+  public void testBaseToInterfaceArrayElement() {
+    CanEatRaw[] canEatRawArray = new CanEatRaw[3];
+    canEatRawArray[1] = (CanEatRaw) foodItem;
+  }
+
   public void testBaseToInterfaceMethod() {
-    Apple apple = (Apple) getFoodItem();
-  }
-
+    CanEatRaw canEatRaw = (CanEatRaw) getFoodItem();
+  }
+
   @SuppressWarnings("cast")
   public void testBaseToInterfaceToConcreteCrazyInline() {
     Apple apple = (Apple) (CanEatRaw) (Food) new Apple();
@@ -85,6 +95,21 @@
     Apple apple = (Apple) foodItem;
   }

+  public void testDownCastToArrayElement() {
+    Apple[] appleArray = new Apple[3];
+    appleArray[2] = (Apple) foodItem;
+  }
+
+  public void testDownCastToArrayArrayElement() {
+    Apple[][] appleArrayArray = new Apple[3][4];
+    appleArrayArray[2][2] = (Apple) foodItem;
+  }
+
+  public void testArrayToArrayArrayElement() {
+    Apple[][] appleArrayArray = new Apple[3][5];
+    appleArrayArray[2] = (Apple[]) arrayOfApple;
+  }
+
   public void testDownCastClassMethod() {
     Apple apple = (Apple) getFoodItem();
   }
@@ -93,6 +118,11 @@
     Apple apple = (Apple) rawFoodItem;
   }

+  public void testDownCastInterfaceToArrayElement() {
+    Apple[] appleArray = new Apple[3];
+    appleArray[2] = (Apple) rawFoodItem;
+  }
+
   public void testDownCastInterfaceMethod() {
     Apple apple = (Apple) getRawFoodItem();
   }
@@ -108,7 +138,92 @@
   public void testInterfaceToBaseToConcreteMethod() {
     Apple apple = (Apple) getRawFoodAsFoodMethod();
   }
-
+
+  public void testClassCastExceptionObjectToConcrete() {
+    try {
+      Apple apple = (Apple) drinkItem;
+      fail("Expected ClassCastException");
+    } catch (ClassCastException e) {
+      // expected
+    }
+  }
+
+  public void testClassCastExceptionToBase() {
+    try {
+      Food food = (Food) drinkItem;
+      fail("Expected ClassCastException");
+    } catch (ClassCastException e) {
+      // expected
+    }
+  }
+
+  public void testClassCastExceptionToInterface() {
+    try {
+      CanEatRaw canEatRaw = (CanEatRaw) drinkItem;
+      fail("Expected ClassCastException");
+    } catch (ClassCastException e) {
+      // expected
+    }
+  }
+
+  public void testClassCastExceptionArrayToConcrete() {
+    try {
+      Apple apple = (Apple) arrayOfWidget;
+      fail("Expected ClassCastException");
+    } catch (ClassCastException e) {
+      // expected
+    }
+  }
+
+  public void testClassCastExceptionObjectToArray() {
+    try {
+      Apple[] appleArray = (Apple[]) drinkItem;
+      fail("Expected ClassCastException");
+    } catch (ClassCastException e) {
+      // expected
+    }
+  }
+
+  public void testClassCastExceptionObjectToConcreteArrayElement() {
+    try {
+      Apple[] appleArray = new Apple[3];
+      appleArray[0] = (Apple) drinkItem;
+      fail("Expected ClassCastException");
+    } catch (ClassCastException e) {
+      // expected
+    }
+  }
+
+  public void testArrayStoreExceptionObjectToConcreteArrayElement() {
+    try {
+      Object[] appleArray = new Apple[3];
+      appleArray[0] = drinkItem;
+      fail("Expected ArrayStoreException");
+    } catch (ArrayStoreException e) {
+      // expected
+    }
+  }
+
+  public void testClassCastExceptionArrayToArrayArrayElement() {
+    try {
+      Apple[][] appleArrayArray = new Apple[3][4];
+      appleArrayArray[2] = (Apple[]) arrayOfWidget;
+      fail("Expected ClassCastException");
+    } catch (ClassCastException e) {
+      // expected
+    }
+  }
+
+  public void testArrayStoreExceptionArrayToArrayArrayElement() {
+    try {
+      Object[][] appleArrayArray = new Apple[3][4];
+      appleArrayArray[2] = (Object[]) arrayOfWidget;
+      fail("Expected ArrayStoreException");
+    } catch (ArrayStoreException e) {
+      // expected
+    }
+  }
+
   private CanEatRaw getFoodAsRawFoodField() {
     return (CanEatRaw) foodItem;
   }
=======================================
--- /trunk/user/test/com/google/gwt/emultest/java/lang/ObjectTest.java Fri Jun 13 17:45:25 2008 +++ /trunk/user/test/com/google/gwt/emultest/java/lang/ObjectTest.java Mon Aug 30 04:31:11 2010
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.emultest.java.lang;

+import com.google.gwt.core.client.JavaScriptObject;
 import com.google.gwt.junit.client.GWTTestCase;

 /**
@@ -37,26 +38,26 @@
   }

   /**
-   * Tests that 'java.lang.Object.typeId' does not shadow a local field.
+ * Tests that 'java.lang.Object.castableTypeMap' does not shadow a local field.
    */
-  public void testTypeIdShadow() {
-    // arbitrary number
-    final int typeId = -824107554;
-    Object obj = new Object() {
-      public int hashCode() {
-        return typeId;
-      }
-    };
-    assertEquals(typeId, obj.hashCode());
+  public void testCastableTypeMapShadow() {
+ final JavaScriptObject castableTypeMap = JavaScriptObject.createObject();
+    class TestClass {
+      public JavaScriptObject getCastableTypeMap() {
+        return castableTypeMap;
+      }
+    }
+    TestClass test = new TestClass();
+    assertEquals(castableTypeMap, test.getCastableTypeMap());
   }

   /**
* Tests that 'java.lang.Object.typeMarker' does not shadow a local field.
    */
   public void testTypeMarkerShadow() {
-    final Object typeMarker = new Object();
+    final JavaScriptObject typeMarker = JavaScriptObject.createObject();
     class TestClass {
-      public Object getTypeMarker() {
+      public JavaScriptObject getTypeMarker() {
         return typeMarker;
       }
     }
=======================================
--- /trunk/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java Fri Jul 23 07:41:23 2010 +++ /trunk/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java Mon Aug 30 04:31:11 2010
@@ -48,26 +48,6 @@
 public class CollectionsTest extends RpcTestBase {

   private CollectionsTestServiceAsync collectionsTestService;
-
-  /**
-   * TODO: Why is this disabled???
-   */
-  public void disabledTestDateArray() {
-    CollectionsTestServiceAsync service = getServiceAsync();
-    final Date[] expected = TestSetFactory.createDateArray();
-    delayTestFinishForRpc();
-    service.echo(expected, new AsyncCallback<Date[]>() {
-      public void onFailure(Throwable caught) {
-        TestSetValidator.rethrowException(caught);
-      }
-
-      public void onSuccess(Date[] result) {
-        assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, result));
-        finishTest();
-      }
-    });
-  }

   /**
* This tests sending payloads that must be segmented to avoid problems with
@@ -156,6 +136,11 @@
       public void onSuccess(Boolean[] result) {
         assertNotNull(result);
         assertTrue(TestSetValidator.equals(expected, result));
+
+        // ensure result preserves meta-data for array store type checking
+        assertTrue(TestSetValidator.checkObjectArrayElementAssignment(
+            result, 0, new Boolean(false)));
+
         finishTest();
       }
     });
@@ -173,6 +158,11 @@
       public void onSuccess(Byte[] result) {
         assertNotNull(result);
         assertTrue(TestSetValidator.equals(expected, result));
+
+        // ensure result preserves meta-data for array store type checking
+        assertTrue(TestSetValidator.checkObjectArrayElementAssignment(
+            result, 0, new Byte((byte) 0)));
+
         finishTest();
       }
     });
@@ -190,11 +180,38 @@
       public void onSuccess(Character[] result) {
         assertNotNull(result);
         assertTrue(TestSetValidator.equals(expected, result));
+
+        // ensure result preserves meta-data for array store type checking
+        assertTrue(TestSetValidator.checkObjectArrayElementAssignment(
+            result, 0, new Character('0')));
+
         finishTest();
       }
     });
   }
-
+
+  public void testDateArray() {
+    CollectionsTestServiceAsync service = getServiceAsync();
+    final Date[] expected = TestSetFactory.createDateArray();
+    delayTestFinishForRpc();
+    service.echo(expected, new AsyncCallback<Date[]>() {
+      public void onFailure(Throwable caught) {
+        TestSetValidator.rethrowException(caught);
+      }
+
+      public void onSuccess(Date[] result) {
+        assertNotNull(result);
+        assertTrue(TestSetValidator.equals(expected, result));
+
+        // ensure result preserves meta-data for array store type checking
+        assertTrue(TestSetValidator.checkObjectArrayElementAssignment(
+            result, 0, new Date()));
+
+        finishTest();
+      }
+    });
+  }
+
   public void testDoubleArray() {
     CollectionsTestServiceAsync service = getServiceAsync();
     final Double[] expected = TestSetFactory.createDoubleArray();
@@ -207,6 +224,11 @@
       public void onSuccess(Double[] result) {
         assertNotNull(result);
         assertTrue(TestSetValidator.equals(expected, result));
+
+        // ensure result preserves meta-data for array store type checking
+        assertTrue(TestSetValidator.checkObjectArrayElementAssignment(
+            result, 0, new Double(0.0)));
+
         finishTest();
       }
     });
@@ -275,6 +297,11 @@
       public void onSuccess(Enum<?>[] result) {
         assertNotNull(result);
         assertTrue(TestSetValidator.equals(expected, result));
+
+        // ensure result preserves meta-data for array store type checking
+        assertTrue(TestSetValidator.checkObjectArrayElementAssignment(
+            result, 0, TestSetFactory.MarkerTypeEnum.C));
+
         finishTest();
       }
     });
@@ -292,6 +319,11 @@
       public void onSuccess(Float[] result) {
         assertNotNull(result);
         assertTrue(TestSetValidator.equals(expected, result));
+
+        // ensure result preserves meta-data for array store type checking
+        assertTrue(TestSetValidator.checkObjectArrayElementAssignment(
+            result, 0, new Float(0.0)));
+
         finishTest();
       }
     });
@@ -344,6 +376,11 @@
       public void onSuccess(Integer[] result) {
         assertNotNull(result);
         assertTrue(TestSetValidator.equals(expected, result));
+
+        // ensure result preserves meta-data for array store type checking
+        assertTrue(TestSetValidator.checkObjectArrayElementAssignment(
+            result, 0, new Integer(0)));
+
         finishTest();
       }
     });
@@ -409,6 +446,11 @@
       public void onSuccess(Long[] result) {
         assertNotNull(result);
         assertTrue(TestSetValidator.equals(expected, result));
+
+        // ensure result preserves meta-data for array store type checking
+        assertTrue(TestSetValidator.checkObjectArrayElementAssignment(
+            result, 0, new Long(0L)));
+
         finishTest();
       }
     });
@@ -560,6 +602,11 @@
       public void onSuccess(Short[] result) {
         assertNotNull(result);
         assertTrue(TestSetValidator.equals(expected, result));
+
+        // ensure result preserves meta-data for array store type checking
+        assertTrue(TestSetValidator.checkObjectArrayElementAssignment(
+            result, 0, new Short((short) 0)));
+
         finishTest();
       }
     });
@@ -594,6 +641,11 @@
       public void onSuccess(java.sql.Date[] result) {
         assertNotNull(result);
         assertTrue(TestSetValidator.equals(expected, result));
+
+        // ensure result preserves meta-data for array store type checking
+        assertTrue(TestSetValidator.checkObjectArrayElementAssignment(
+            result, 0, new java.sql.Date(0L)));
+
         finishTest();
       }
     });
@@ -611,6 +663,11 @@
       public void onSuccess(Time[] result) {
         assertNotNull(result);
         assertTrue(TestSetValidator.equals(expected, result));
+
+        // ensure result preserves meta-data for array store type checking
+        assertTrue(TestSetValidator.checkObjectArrayElementAssignment(
+            result, 0, new Time(0L)));
+
         finishTest();
       }
     });
@@ -628,6 +685,11 @@
       public void onSuccess(Timestamp[] result) {
         assertNotNull(result);
         assertTrue(TestSetValidator.equals(expected, result));
+
+        // ensure result preserves meta-data for array store type checking
+        assertTrue(TestSetValidator.checkObjectArrayElementAssignment(
+            result, 0, new Timestamp(0L)));
+
         finishTest();
       }
     });
@@ -645,6 +707,11 @@
       public void onSuccess(String[] result) {
         assertNotNull(result);
         assertTrue(TestSetValidator.equals(expected, result));
+
+        // ensure result preserves meta-data for array store type checking
+        assertTrue(TestSetValidator.checkObjectArrayElementAssignment(
+            result, 0, new String("")));
+
         finishTest();
       }
     });
@@ -662,6 +729,11 @@

       public void onSuccess(String[][] result) {
         assertNotNull(result);
+
+        // ensure result preserves meta-data for array store type checking
+        assertTrue(TestSetValidator.checkObjectArrayElementAssignment(
+            result, 0, new String[4]));
+
         finishTest();
       }
     });
=======================================
--- /trunk/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java Fri Jul 23 07:41:23 2010 +++ /trunk/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java Mon Aug 30 04:31:11 2010
@@ -50,7 +50,33 @@
  * TODO: could add generics to require args to be of the same type
  */
 public class TestSetValidator {
-
+
+  private static class UnassignableObject {
+  }
+
+  /**
+ * Check that an Object array has it's meta-data preserved (e.g. Array.queryId),
+   * to ensure proper type checking on element assignment.
+   */
+  public static boolean checkObjectArrayElementAssignment(Object[] array,
+      int index, Object value) {
+
+    // first check that the requested assignment succeeds
+    try {
+      array[index] = value;
+    } catch (ArrayStoreException e) {
+      return false;
+    }
+
+ // next check that assignment with a bogus type throws ArrayStoreException
+    try {
+      array[index] = new UnassignableObject();
+      return false;
+    } catch (ArrayStoreException e) {
+      return true;
+    }
+  }
+
   public static boolean equals(boolean[] expected, boolean[] actual) {
     if (actual == null) {
       return false;

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to