Fixes issue 1985.  Moved all subtype tests into JClassType.  Added a new superclass for JParameterizedType and JRawType to make the new subtype tests simpler.

Also implemented JWildcardType.getErasedType() since it was using JDelegatingClassType's version which was wrong.


Patch by: mmendez, rdayal, spoon
Review by: spoon, rdayal, mmendez

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1791 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JArrayType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JArrayType.java
index d1e1b9f..fd67a67 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JArrayType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JArrayType.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -301,45 +301,6 @@
   }
 
   @Override
-  public boolean isAssignableFrom(JClassType possibleSubtype) {
-    if (this == possibleSubtype) {
-      // type is assignable to itself
-      return true;
-    }
-
-    JArrayType possibleSubtypeArray = possibleSubtype.isArray();
-    if (possibleSubtypeArray == null) {
-      // possible subtype must be an array to be assignable
-      return false;
-    }
-
-    JType thisComponentType = getComponentType();
-    JType otherComponentType = possibleSubtypeArray.getComponentType();
-
-    if (thisComponentType.isPrimitive() != null
-        || otherComponentType.isPrimitive() != null) {
-      /*
-       * Since this was not equal to the possible subtype, we know that either
-       * the dimensions are off or the component types are off
-       */
-      return false;
-    }
-
-    assert (thisComponentType instanceof JClassType);
-    assert (otherComponentType instanceof JClassType);
-
-    JClassType thisComponentClassType = (JClassType) thisComponentType;
-    JClassType otherComponentClassType = (JClassType) otherComponentType;
-
-    return thisComponentClassType.isAssignableFrom(otherComponentClassType);
-  }
-
-  @Override
-  public boolean isAssignableTo(JClassType possibleSupertype) {
-    return possibleSupertype.isAssignableFrom(this);
-  }
-
-  @Override
   public JClassType isClass() {
     // intentional null
     return null;
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java
index 1f67de2..be49e4e 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -23,7 +23,7 @@
 import java.util.Set;
 
 /**
- * Type representing a Java class or interface type.
+ * Type used to represent any non-primitive type.
  */
 public abstract class JClassType extends JType implements HasAnnotations,
     HasMetaData {
@@ -40,17 +40,268 @@
   }
 
   /**
-   * Returns the {@link JGenericType} base type if the otherType is raw or
-   * parameterized type.
+   * Returns <code>true</code> if the rhs array type can be assigned to the
+   * lhs array type.
    */
-  protected static JClassType maybeGetGenericBaseType(JClassType otherType) {
-    if (otherType.isParameterized() != null) {
-      return otherType.isParameterized().getBaseType();
-    } else if (otherType.isRawType() != null) {
-      return otherType.isRawType().getGenericType();
+  private static boolean areArraysAssignable(JArrayType lhsType,
+      JArrayType rhsType) {
+    // areClassTypesAssignable should prevent us from getting here if the types
+    // are referentially equal.
+    assert (lhsType != rhsType);
+
+    JType lhsComponentType = lhsType.getComponentType();
+    JType rhsComponentType = rhsType.getComponentType();
+
+    if (lhsComponentType.isPrimitive() != null
+        || rhsComponentType.isPrimitive() != null) {
+      /*
+       * Arrays are referentially stable so there will only be one int[] no
+       * matter how many times it is referenced in the code. So, if either
+       * component type is a primitive then we know that we are not assignable.
+       */
+      return false;
     }
-     
-    return otherType;
+
+    assert (lhsComponentType instanceof JClassType);
+    assert (rhsComponentType instanceof JClassType);
+
+    JClassType thisComponentClass = (JClassType) lhsComponentType;
+    JClassType subtypeComponentClass = (JClassType) rhsComponentType;
+
+    return areClassTypesAssignable(thisComponentClass, subtypeComponentClass);
+  }
+
+  /**
+   * Returns <code>true</code> if the rhsType can be assigned to the lhsType.
+   */
+  private static boolean areClassTypesAssignable(JClassType lhsType,
+      JClassType rhsType) {
+    // The supertypes of rhs will include rhs.
+    Set<JClassType> rhsSupertypes = getFlattenedSuperTypeHierarchy(rhsType);
+    for (JClassType rhsSupertype : rhsSupertypes) {
+      if (areClassTypesAssignableNoSupers(lhsType, rhsSupertype)) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  /**
+   * Returns <code>true</code> if the lhs and rhs are assignable without
+   * consideration of the supertypes of the rhs.
+   * 
+   * @param lhsType
+   * @param rhsType
+   * @return
+   */
+  private static boolean areClassTypesAssignableNoSupers(JClassType lhsType,
+      JClassType rhsType) {
+    if (lhsType == rhsType) {
+      // Done, these are the same types.
+      return true;
+    }
+
+    if (lhsType == lhsType.getOracle().getJavaLangObject()) {
+      // Done, any type can be assigned to object.
+      return true;
+    }
+
+    /*
+     * Get the generic base type, if there is one, for the lhs type and convert
+     * it to a raw type if it is generic.
+     */
+    if (lhsType.isGenericType() != null) {
+      lhsType = lhsType.isGenericType().getRawType();
+    }
+    
+    if (rhsType.isGenericType() != null) {
+      // Treat the generic rhs type as a raw type.
+      rhsType = rhsType.isGenericType().getRawType();
+    }
+
+    // Check for JTypeParameters.
+    JTypeParameter lhsTypeParam = lhsType.isTypeParameter();
+    JTypeParameter rhsTypeParam = rhsType.isTypeParameter();
+    if (lhsTypeParam != null) {
+      JBound bounds = lhsTypeParam.getBounds();
+      JClassType[] lhsTypeBounds = bounds.getBounds();
+      for (JClassType lhsTypeBound : lhsTypeBounds) {
+        if (!areClassTypesAssignable(lhsTypeBound, rhsType)) {
+          // Done, the rhsType was not assignable to one of the bounds.
+          return false;
+        }
+      }
+
+      // Done, the rhsType was assignable to all of the bounds.
+      return true;
+    } else if (rhsTypeParam != null) {
+      JClassType[] possibleSubtypeBounds = rhsTypeParam.getBounds().getBounds();
+      for (JClassType possibleSubtypeBound : possibleSubtypeBounds) {
+        if (areClassTypesAssignable(lhsType, possibleSubtypeBound)) {
+          // Done, at least one bound is assignable to this type.
+          return true;
+        }
+      }
+
+      return false;
+    }
+
+    /*
+     * Check for JWildcards. We have not examined this part in great detail
+     * since there should not be top level wildcard types.
+     */
+    JWildcardType lhsWildcard = lhsType.isWildcard();
+    JWildcardType rhsWildcard = rhsType.isWildcard();
+    if (lhsWildcard != null && rhsWildcard != null) {
+      // Both types are wildcards.
+      return areWildcardsAssignable(lhsWildcard, rhsWildcard);
+    } else if (lhsWildcard != null) {
+      // The lhs type is a wildcard but the rhs is not.
+      // ? extends T, U OR ? super T, U
+      JBound lhsBound = lhsWildcard.getBounds();
+      if (lhsBound.isUpperBound() != null) {
+        return areClassTypesAssignable(lhsBound.getFirstBound(), rhsType);
+      } else {
+        // ? super T will reach object no matter what the rhs type is
+        return true;
+      }
+    } 
+
+    // Check for JArrayTypes.
+    JArrayType lhsArray = lhsType.isArray();
+    JArrayType rhsArray = rhsType.isArray();
+    if (lhsArray != null) {
+      if (rhsArray == null) {
+        return false;
+      } else {
+        return areArraysAssignable(lhsArray, rhsArray);
+      }
+    } else if (rhsArray != null) {
+      // Safe although perhaps not necessary
+      return false;
+    }
+
+    // Check for JParameterizedTypes and JRawTypes.
+    JMaybeParameterizedType lhsMaybeParameterized = lhsType.isMaybeParameterizedType();
+    JMaybeParameterizedType rhsMaybeParameterized = rhsType.isMaybeParameterizedType();
+    if (lhsMaybeParameterized != null && rhsMaybeParameterized != null) {
+      if (lhsMaybeParameterized.getBaseType() == rhsMaybeParameterized.getBaseType()) {
+        if (lhsMaybeParameterized.isRawType() != null
+            || rhsMaybeParameterized.isRawType() != null) {
+          /*
+           * Any raw type can be assigned to or from any parameterization of its
+           * generic type.
+           */
+          return true;
+        }
+
+        assert (lhsMaybeParameterized.isRawType() == null && 
+            rhsMaybeParameterized.isRawType() == null);
+        JParameterizedType lhsParameterized = lhsMaybeParameterized.isParameterized();
+        JParameterizedType rhsParameterized = rhsMaybeParameterized.isParameterized();
+        assert (lhsParameterized != null && rhsParameterized != null);
+
+        return areTypeArgumentsAssignable(lhsParameterized,
+            rhsParameterized);
+      }
+    }
+
+    // Default to not being assignable.
+    return false;
+  }
+
+  /**
+   * Returns <code>true</code> if the type arguments of the rhs parameterized
+   * type are assignable to the type arguments of the lhs parameterized type.
+   */
+  private static boolean areTypeArgumentsAssignable(JParameterizedType lhsType,
+      JParameterizedType rhsType) {
+    // areClassTypesAssignable should prevent us from getting here if the types
+    // are referentially equal.
+    assert (lhsType != rhsType);
+    assert (lhsType.getBaseType() == rhsType.getBaseType());
+
+    JClassType[] lhsTypeArgs = lhsType.getTypeArgs();
+    JClassType[] rhsTypeArgs = rhsType.getTypeArgs();
+    JGenericType lhsBaseType = lhsType.getBaseType();
+
+    // Compare at least as many formal type parameters as are declared on the
+    // generic base type. gwt.typeArgs could cause more types to be included.
+
+    JTypeParameter[] lhsTypeParams = lhsBaseType.getTypeParameters();
+    for (int i = 0; i < lhsTypeParams.length; ++i) {
+      if (!doesTypeArgumentContain(lhsTypeArgs[i], rhsTypeArgs[i])) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  /**
+   * Returns <code>true</code> if the rhsWildcard can be assigned to the
+   * lhsWildcard.  This method does not consider supertypes of either
+   * lhs or rhs.
+   */
+  private static boolean areWildcardsAssignable(JWildcardType lhsWildcard,
+      JWildcardType rhsWildcard) {
+    // areClassTypesAssignable should prevent us from getting here if the types
+    // are referentially equal.
+    assert (lhsWildcard != rhsWildcard);
+    assert (lhsWildcard != null && rhsWildcard != null);
+
+    JBound lhsBound = lhsWildcard.getBounds();
+    JBound rhsBound = rhsWildcard.getBounds();
+
+    if (lhsBound.isUpperBound() != null && rhsBound.isUpperBound() != null) {
+      // lhsType: ? extends T, rhsType: ? extends U
+      return areClassTypesAssignable(lhsBound.getFirstBound(),
+          rhsBound.getFirstBound());
+    } else if (lhsBound.isLowerBound() != null
+        && rhsBound.isLowerBound() != null) {
+      // lhsType: ? super T, rhsType ? super U
+      return areClassTypesAssignable(rhsBound.getFirstBound(),
+          lhsBound.getFirstBound());
+    }
+
+    return false;
+  }
+
+  /**
+   * A restricted version of areClassTypesAssignable that is used for comparing 
+   * the type arguments of parameterized types, where the lhsTypeArg is the
+   * container.
+   */
+  private static boolean doesTypeArgumentContain(JClassType lhsTypeArg,
+      JClassType rhsTypeArg) {
+    if (lhsTypeArg == rhsTypeArg) {
+      return true;
+    }
+
+    // Check for wildcard types
+    JWildcardType lhsWildcard = lhsTypeArg.isWildcard();
+    JWildcardType rhsWildcard = rhsTypeArg.isWildcard();
+
+    if (lhsWildcard != null) {
+      if (rhsWildcard != null) {
+        return areWildcardsAssignable(lhsWildcard, rhsWildcard);
+      } else {
+        // LHS is a wildcard but the RHS is not.
+        JBound lhsBound = lhsWildcard.getBounds();
+        if (lhsBound.isLowerBound() == null) {
+          return areClassTypesAssignable(lhsBound.getFirstBound(), rhsTypeArg);
+        } else {
+          return areClassTypesAssignable(rhsTypeArg, lhsBound.getFirstBound());
+        }
+      }
+    }
+    
+    /*
+     * At this point the arguments are not the same and they are not wildcards
+     * so, they cannot be assignable, Eh.
+     */
+    return false;
   }
 
   private static void getFlattenedSuperTypeHierarchyRecursive(JClassType type,
@@ -72,7 +323,7 @@
       getFlattenedSuperTypeHierarchyRecursive(intf, typesSeen);
     }
   }
-  
+
   public abstract void addImplementedInterface(JClassType intf);
 
   public abstract void addMetaData(String tagName, String[] values);
@@ -171,9 +422,13 @@
   public abstract boolean isAnnotationPresent(
       Class<? extends Annotation> annotationClass);
 
-  public abstract boolean isAssignableFrom(JClassType possibleSubtype);
+  public boolean isAssignableFrom(JClassType possibleSubtype) {
+    return areClassTypesAssignable(this, possibleSubtype);
+  }
 
-  public abstract boolean isAssignableTo(JClassType possibleSupertype);
+  public boolean isAssignableTo(JClassType possibleSupertype) {
+    return areClassTypesAssignable(possibleSupertype, this);
+  }
 
   /**
    * Determines if the class can be constructed using a simple <code>new</code>
@@ -243,6 +498,10 @@
   protected abstract void getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(
       Map<String, JMethod> methodsBySignature);
 
+  protected JMaybeParameterizedType isMaybeParameterizedType() {
+    return null;
+  }
+
   protected final String makeCompoundName(JClassType type) {
     if (type.getEnclosingType() == null) {
       return type.getSimpleSourceName();
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JDelegatingClassType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JDelegatingClassType.java
index e421658..62ab6cd 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JDelegatingClassType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JDelegatingClassType.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -253,16 +253,6 @@
   }
 
   @Override
-  public boolean isAssignableFrom(JClassType possibleSubtype) {
-    return baseType.isAssignableFrom(possibleSubtype);
-  }
-
-  @Override
-  public boolean isAssignableTo(JClassType possibleSupertype) {
-    return baseType.isAssignableTo(possibleSupertype);
-  }
-
-  @Override
   public JClassType isClass() {
     if (baseType.isClass() != null) {
       return this;
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JGenericType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JGenericType.java
index 50441dc..1297351 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JGenericType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JGenericType.java
@@ -17,33 +17,11 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
 
 /**
- * 
+ * Type declaration that has type parameters.
  */
 public class JGenericType extends JRealClassType implements HasTypeParameters {
-  /**
-   * Returns <code>true</code> if lhsType is assignable to rhsType.
-   */
-  private static boolean isAssignable(JClassType lhsType, JClassType rhsType) {
-    if (lhsType == rhsType) {
-      return true;
-    }
-
-    Set<JClassType> supertypes = getFlattenedSuperTypeHierarchy(rhsType);
-    for (JClassType supertype : supertypes) {
-      if (supertype.isParameterized() == null) {
-        continue;
-      }
-
-      if (supertype.isParameterized().getBaseType() == lhsType) {
-        return true;
-      }
-    }
-
-    return false;
-  }
 
   private JRawType lazyRawType = null;
 
@@ -107,20 +85,6 @@
   }
 
   @Override
-  public boolean isAssignableFrom(JClassType otherType) {
-    otherType = maybeGetGenericBaseType(otherType);
-
-    return isAssignable(this, otherType);
-  }
-
-  @Override
-  public boolean isAssignableTo(JClassType otherType) {
-    otherType = maybeGetGenericBaseType(otherType);
-
-    return isAssignable(otherType, this);
-  }
-
-  @Override
   public JGenericType isGenericType() {
     return this;
   }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JMaybeParameterizedType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JMaybeParameterizedType.java
new file mode 100644
index 0000000..ee130ef
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JMaybeParameterizedType.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2008 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.core.ext.typeinfo;
+
+/**
+ * Super class for parameterized types or raw types.
+ */
+abstract class JMaybeParameterizedType extends JDelegatingClassType {
+
+  public JMaybeParameterizedType() {
+    super();
+  }
+
+  @Override
+  public JGenericType getBaseType() {
+    JGenericType genericType = super.getBaseType().isGenericType();
+    assert (genericType != null);
+    return genericType;
+  }
+
+  @Override
+  protected JMaybeParameterizedType isMaybeParameterizedType() {
+    return this;
+  }
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JParameterizedType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JParameterizedType.java
index 3c27edf..ec7ae54 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JParameterizedType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JParameterizedType.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -25,41 +25,7 @@
 /**
  * Represents a parameterized type in a declaration.
  */
-public class JParameterizedType extends JDelegatingClassType {
-  private static boolean areTypeArgsAssignableFrom(JClassType[] myTypeArgs,
-      JClassType[] otherTypeArgs) {
-    assert (myTypeArgs.length <= otherTypeArgs.length);
-
-    for (int i = 0; i < myTypeArgs.length; ++i) {
-      JClassType myTypeArg = myTypeArgs[i];
-      JClassType otherTypeArg = otherTypeArgs[i];
-
-      if (myTypeArg.isTypeParameter() != null) {
-        /*
-         * If my type argument is a type parameter consider it's erased form.  This
-         * avoids recursion sickness in the case where my type argument is of the
-         * form:
-         * 
-         * T extends Serializable & Comparable<T>
-         * 
-         * and otherTypeArg is something like Long, Short, etc.
-         */
-        return myTypeArg.getErasedType().isAssignableFrom(otherTypeArg);
-      }
-      
-      if (myTypeArg.isWildcard() == null) {
-        // myTypeArg needs to be a wildcard or we cannot be assignable.
-        return false;
-      }
-
-      if (!myTypeArg.isAssignableFrom(otherTypeArg)) {
-        return false;
-      }
-    }
-
-    return true;
-  }
-
+public class JParameterizedType extends JMaybeParameterizedType {
   /**
    * Create a parameterized type along with any necessary enclosing
    * parameterized types. Enclosing parameterized types are necessary when the
@@ -99,77 +65,6 @@
     return parameterizedType;
   }
 
-  /**
-   * Returns <code>true</code> if the rhsType can be assigned to the lhsType.
-   */
-  private static boolean isAssignable(JClassType lhsType, JClassType rhsType) {
-    if (lhsType == rhsType) {
-      return true;
-    }
-
-    Set<JClassType> rhsSupertypes = getFlattenedSuperTypeHierarchy(rhsType);
-    if (rhsSupertypes.contains(lhsType)) {
-      // Done, appears explicitly in the supertype hierarchy.
-      return true;
-    }
-
-    /*
-     * Get the generic base type for the lhsType if there is one.
-     */
-    JGenericType lhsBaseType = null;
-    if (lhsType.isParameterized() != null) {
-      lhsBaseType = lhsType.isParameterized().getBaseType();
-    } else if (lhsType.isRawType() != null) {
-      lhsBaseType = lhsType.isRawType().getBaseType();
-    }
-    
-    /*
-     * Check the supertype hierarchy to see if we can find a parameterization
-     * or a raw type that would satisfy the assignment. 
-     */
-    for (JClassType rhsSupertype : rhsSupertypes) {
-      if (rhsSupertype.isGenericType() != null) {
-        /*
-         * A generic type will be treated as its raw type for assignment
-         * purposes.
-         */
-        rhsSupertype = rhsSupertype.isGenericType().getRawType();
-      }
-
-      JParameterizedType rhsParameterized = rhsSupertype.isParameterized();
-      if (rhsParameterized != null) {
-        if (rhsParameterized.getBaseType() == lhsBaseType) {
-          /*
-           * This supertype and the lhsType have the same base type, but they
-           * have different parameterizations so we test them.  
-           */
-          assert (rhsParameterized != lhsType);
-
-          if (lhsType.isRawType() != null) {
-            // The lhsType is raw so we do not need to check the parameterization.
-            return true;
-          } else {
-            assert (lhsType.isParameterized() != null);
-            
-            return areTypeArgsAssignableFrom(
-                lhsType.isParameterized().getTypeArgs(),
-                rhsParameterized.getTypeArgs());
-          }
-        }
-      } else if (rhsSupertype.isRawType() != null) {
-        if (rhsSupertype.isRawType().getBaseType() == lhsBaseType) {
-          /*
-           * The raw supertype has the same base type as the lhsType so the
-           * assignment is okay.
-           */
-          return true;
-        }
-      }
-    }
-
-    return false;
-  }
-
   private final JClassType enclosingType;
 
   private List<JClassType> interfaces;
@@ -229,11 +124,6 @@
   }
 
   @Override
-  public JGenericType getBaseType() {
-    return (JGenericType) super.getBaseType();
-  }
-
-  @Override
   public JConstructor getConstructor(JType[] paramTypes)
       throws NotFoundException {
     return members.getConstructor(paramTypes);
@@ -424,16 +314,6 @@
   }
 
   @Override
-  public boolean isAssignableFrom(JClassType otherType) {
-    return isAssignable(this, otherType);
-  }
-
-  @Override
-  public boolean isAssignableTo(JClassType otherType) {
-    return isAssignable(otherType, this);
-  }
-
-  @Override
   public JGenericType isGenericType() {
     return null;
   }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRawType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRawType.java
index 63ba139..b7a6017 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRawType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRawType.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -21,7 +21,7 @@
 /**
  * Represents a raw type; that is a generic type with no type arguments.
  */
-public class JRawType extends JDelegatingClassType {
+public class JRawType extends JMaybeParameterizedType {
   private static final Substitution ERASURE_SUBSTITUTION = new Substitution() {
     public JType getSubstitution(JType type) {
       return type.getErasedType();
@@ -64,13 +64,6 @@
   }
 
   @Override
-  public JGenericType getBaseType() {
-    JGenericType genericType = super.getBaseType().isGenericType();
-    assert (genericType != null);
-    return genericType;
-  }
-
-  @Override
   public JConstructor getConstructor(JType[] paramTypes)
       throws NotFoundException {
     return members.getConstructor(paramTypes);
@@ -181,20 +174,6 @@
   }
 
   @Override
-  public boolean isAssignableFrom(JClassType otherType) {
-    otherType = maybeGetGenericBaseType(otherType);
-    
-    return getBaseType().isAssignableFrom(otherType);
-  }
-
-  @Override
-  public boolean isAssignableTo(JClassType otherType) {
-    otherType = maybeGetGenericBaseType(otherType);
-    
-    return getBaseType().isAssignableTo(otherType);
-  }
-
-  @Override
   public JGenericType isGenericType() {
     return null;
   }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
index 2411d2c..78a0779 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -27,7 +27,7 @@
 import java.util.Set;
 
 /**
- * Type representing a Java class or interface type.
+ * Type representing a Java class or interface type that a user would declare.
  */
 public class JRealClassType extends JClassType {
 
@@ -325,51 +325,6 @@
   }
 
   @Override
-  public boolean isAssignableFrom(JClassType otherType) {
-    if (otherType == this) {
-      return true;
-    }
-        
-    if (allSubtypes.contains(otherType)) {
-      // JGenericTypes should appear in the allSubtypes hierarchy - do nothing
-      return true;
-    } else if (this == getOracle().getJavaLangObject()) {
-      // This case handles the odd "every interface is an Object"
-      // but doesn't actually have Object as a superclass.
-      //
-      return true;
-    } else {
-      if (otherType.isTypeParameter() != null) {
-        return otherType.isAssignableTo(this);
-      }
-      
-      if (otherType.isWildcard() != null) {
-        return otherType.isAssignableTo(this);
-      }
-
-      if (otherType.isGenericType() != null) {
-        return otherType.isAssignableTo(this);
-      }
-      
-      if (otherType.isRawType() != null) {
-        return otherType.isAssignableTo(this);
-      }
-      
-      if (otherType.isParameterized() != null) {
-        return otherType.isAssignableTo(this);
-      }
-
-      // At this point we should only have JArrayTypes or JRealClassTypes from
-      // which we are not assignable.
-      return false;
-    }
-  }
-
-  public boolean isAssignableTo(JClassType possibleSupertype) {
-    return possibleSupertype.isAssignableFrom(this);
-  }
-
-  @Override
   public JClassType isClass() {
     return isInterface ? null : this;
   }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JTypeParameter.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JTypeParameter.java
index 4262c0e..874e4c4 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JTypeParameter.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JTypeParameter.java
@@ -118,24 +118,6 @@
   }
 
   @Override
-  public boolean isAssignableFrom(JClassType otherType) {
-    if (otherType == this) {
-      return true;
-    }
-    
-    return getBounds().isAssignableFrom(otherType);
-  }
-
-  @Override
-  public boolean isAssignableTo(JClassType otherType) {
-    if (otherType == this) {
-      return true;
-    }
-    
-    return getBounds().isAssignableTo(otherType);
-  }
-  
-  @Override
   public JGenericType isGenericType() {
     return null;
   }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JWildcardType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JWildcardType.java
index 20b8e53..a6d18dc 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JWildcardType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JWildcardType.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -41,6 +41,17 @@
   }
 
   @Override
+  public JClassType getErasedType() {
+    if (bounds.isLowerBound() != null) {
+      // ? super T erases to Object
+      return getOracle().getJavaLangObject();
+    }
+    
+    // ? extends T erases to T
+    return getFirstBound();
+  }
+
+  @Override
   public JField getField(String name) {
     return getBaseType().getField(name);
   }
@@ -74,30 +85,27 @@
   public String getSimpleSourceName() {
     return "?" + bounds.getSimpleSourceName();
   }
-
+  
   @Override
   public JClassType[] getSubtypes() {
+    // We are not sure what the correct behavior should be for lower bound
+    // wildcards.  ? super Number contains ? super T for all T extends Number,
+    // but it also includes T for Number extends T.  For example, Object is a 
+    // subtype.
     return bounds.getSubtypes();
   }
-
+  
   @Override
-  public boolean isAssignableFrom(JClassType otherType) {
-    if (otherType == this) {
-      return true;
+  public JClassType getSuperclass() {
+    if (bounds.isLowerBound() != null) {
+      // The only safe superclass for a ? super T is Object.
+      return getOracle().getJavaLangObject();
     }
     
-    return getBounds().isAssignableFrom(otherType);
+    // The superclass of an upper bound is the upper bound.
+    return getFirstBound();
   }
-
-  @Override
-  public boolean isAssignableTo(JClassType otherType) {
-    if (otherType == this) {
-      return true;
-    }
-    
-    return getBounds().isAssignableTo(otherType);
-  }
-
+  
   @Override
   public JGenericType isGenericType() {
     return null;
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JGenericTypeTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JGenericTypeTest.java
index 5a443f1..d3e9ef3 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/JGenericTypeTest.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JGenericTypeTest.java
@@ -184,9 +184,54 @@
 
     JClassType[] bounds = bound.getBounds();
     assertEquals(1, bounds.length);
-    assertEquals(moduleContext.getOracle().getJavaLangObject(), bounds[0]);
+    assertEquals(moduleContext.getOracle().getType(Serializable.class.getName()), 
+        bounds[0]);
+  }
+  
+  /**
+   * Test method for {@link
+   * com.google.gwt.core.ext.typeinfo.JGenericType#isAssignableFrom(JClassType)}.
+   * 
+   * @throws NotFoundException
+   */
+  public void testIsAssignableFrom() throws NotFoundException {
+    JGenericType genericType = getTestType();
+    
+    // Check that the generic type's superclass is assignable from the generic type
+    assertTrue(genericType.getSuperclass().isAssignableFrom(genericType));
+    
+    // Check that each implemented interface is assignable from the generic type
+    JClassType[] implementedInterfaces = genericType.getImplementedInterfaces();
+    for (JClassType implementedInterface : implementedInterfaces) {
+      assertTrue(implementedInterface.isAssignableFrom(genericType));
+      assertTrue(implementedInterface.isAssignableFrom(genericType.getRawType()));
+    }
+  }
+  
+  /**
+   * Test method for {@link
+   * com.google.gwt.core.ext.typeinfo.JGenericType#isAssignableTo(JClassType)}.
+   * 
+   * @throws NotFoundException
+   */
+  public void testIsAssignableTo() throws NotFoundException {
+    JGenericType genericType = getTestType();
+    
+    // Check that generic type is assignable to its superclass
+    assertTrue(genericType.isAssignableTo(genericType.getSuperclass()));
+    
+    // Check that the generic class is assignable to any implemented interface
+    JClassType[] implementedInterfaces = genericType.getImplementedInterfaces();
+    for (JClassType implementedInterface : implementedInterfaces) {
+      assertTrue(genericType.isAssignableTo(implementedInterface));
+      
+      if (implementedInterface.isParameterized() != null) {
+        assertTrue(genericType.isAssignableTo(implementedInterface.isParameterized().getRawType()));
+      }
+    }
   }
 
+  
   /**
    * Returns the generic version of {@link GenericClass}.
    */
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JParameterizedTypeTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JParameterizedTypeTest.java
index ca91c61..0b23f6b 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/JParameterizedTypeTest.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JParameterizedTypeTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -19,6 +19,7 @@
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.test.Base;
 import com.google.gwt.core.ext.typeinfo.test.Derived;
+import com.google.gwt.core.ext.typeinfo.test.ExtendsRawGenericClass;
 import com.google.gwt.core.ext.typeinfo.test.GenericClass;
 import com.google.gwt.core.ext.typeinfo.test.MyCustomList;
 import com.google.gwt.core.ext.typeinfo.test.MyIntegerList;
@@ -32,6 +33,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.Vector;
 
 /**
  * Test for {@link JParameterizedType}.
@@ -228,33 +230,43 @@
     TypeOracle oracle = moduleContext.getOracle();
     JGenericType genericList = (JGenericType) oracle.getType(List.class.getName());
 
+    // ?
     JWildcardType unboundWildcard = oracle.getWildcardType(new JUpperBound(
         oracle.getJavaLangObject()));
+    
+    // ? extends Number
     JWildcardType numUpperBoundWildcard = oracle.getWildcardType(new JUpperBound(
         oracle.getType(Number.class.getName())));
 
-    // List<?> should be assignable from List<? extends Number>
+    // List<?>
     JParameterizedType unboundList = oracle.getParameterizedType(genericList,
         new JClassType[] {unboundWildcard});
-    JParameterizedType numUpperBoundList = oracle.getParameterizedType(
+    
+    // List<? extends Number>
+    JParameterizedType listOfExtendsNumber = oracle.getParameterizedType(
         genericList, new JClassType[] {numUpperBoundWildcard});
-    assertTrue(unboundList.isAssignableFrom(numUpperBoundList));
-    assertFalse(unboundList.isAssignableTo(numUpperBoundList));
+    
+    // List<?> should be assignable from List<? extends Number>
+    assertTrue(unboundList.isAssignableFrom(listOfExtendsNumber));
+    assertFalse(unboundList.isAssignableTo(listOfExtendsNumber));
 
-    assertFalse(numUpperBoundList.isAssignableFrom(unboundList));
-    assertTrue(numUpperBoundList.isAssignableTo(unboundList));
+    assertFalse(listOfExtendsNumber.isAssignableFrom(unboundList));
+    assertTrue(listOfExtendsNumber.isAssignableTo(unboundList));
 
-    // List<? extends Number> should be assignable from List<? extends Integer>
+    // ? extends Integer
     JWildcardType intUpperBoundWildcard = oracle.getWildcardType(new JUpperBound(
         integerType));
 
-    JParameterizedType intUpperBoundList = oracle.getParameterizedType(
+    // List<? extends Integer>
+    JParameterizedType listOfExtendsInteger = oracle.getParameterizedType(
         genericList, new JClassType[] {intUpperBoundWildcard});
-    assertTrue(numUpperBoundList.isAssignableFrom(intUpperBoundList));
-    assertFalse(numUpperBoundList.isAssignableTo(intUpperBoundList));
 
-    assertFalse(intUpperBoundList.isAssignableFrom(numUpperBoundList));
-    assertTrue(intUpperBoundList.isAssignableTo(numUpperBoundList));
+    // List<? extends Number> should be assignable from List<? extends Integer>
+    assertTrue(listOfExtendsNumber.isAssignableFrom(listOfExtendsInteger));
+    assertFalse(listOfExtendsNumber.isAssignableTo(listOfExtendsInteger));
+
+    assertFalse(listOfExtendsInteger.isAssignableFrom(listOfExtendsNumber));
+    assertTrue(listOfExtendsInteger.isAssignableTo(listOfExtendsNumber));
 
     // List<? super Integer> should be assignable from List<? super Number>
     JWildcardType numLowerBoundWildcard = oracle.getWildcardType(new JLowerBound(
@@ -262,15 +274,83 @@
     JWildcardType intLowerBoundWildcard = oracle.getWildcardType(new JLowerBound(
         integerType));
 
-    JParameterizedType numLowerBoundList = oracle.getParameterizedType(
+    // List<? super Number>
+    JParameterizedType listOfSuperNumber = oracle.getParameterizedType(
         genericList, new JClassType[] {numLowerBoundWildcard});
-    JParameterizedType intLowerBoundList = oracle.getParameterizedType(
+    
+    // List<? super Interger>
+    JParameterizedType listOfSuperInteger = oracle.getParameterizedType(
         genericList, new JClassType[] {intLowerBoundWildcard});
 
-    assertTrue(intLowerBoundList.isAssignableFrom(numLowerBoundList));
-    assertFalse(intLowerBoundList.isAssignableTo(numLowerBoundList));
-    assertFalse(numLowerBoundList.isAssignableFrom(intLowerBoundList));
-    assertTrue(numLowerBoundList.isAssignableTo(intLowerBoundList));
+    assertTrue(listOfSuperInteger.isAssignableFrom(listOfSuperNumber));
+    assertFalse(listOfSuperInteger.isAssignableTo(listOfSuperNumber));
+    assertFalse(listOfSuperNumber.isAssignableFrom(listOfSuperInteger));
+    assertTrue(listOfSuperNumber.isAssignableTo(listOfSuperInteger));
+
+    JParameterizedType listOfObject = oracle.getParameterizedType(genericList,
+        new JClassType[] {oracle.getJavaLangObject()});
+
+    JClassType stringType = oracle.getType(String.class.getName());
+    JParameterizedType listOfString = oracle.getParameterizedType(genericList,
+        new JClassType[] {stringType});
+
+    // List<Object> is not assignable from List<String>
+    assertFalse(listOfObject.isAssignableFrom(listOfString));
+
+    // List<String> is not assignable from List<Object>
+    assertFalse(listOfString.isAssignableFrom(listOfObject));
+
+    // List<List<String>> is not assignable from List<Vector<String>>
+    JParameterizedType listOfListOfString = oracle.getParameterizedType(
+        genericList, new JClassType[] {listOfString});
+    
+    JGenericType genericVector = oracle.getType(Vector.class.getName()).isGenericType();
+    JParameterizedType vectorOfString = oracle.getParameterizedType(genericVector, new JClassType[] {stringType});
+    JParameterizedType listOfVectorOfString = oracle.getParameterizedType(genericList, new JClassType[] {vectorOfString});
+    
+    assertFalse(listOfListOfString.isAssignableFrom(listOfVectorOfString));
+    assertFalse(listOfVectorOfString.isAssignableFrom(listOfListOfString));
+    
+    // List<List> is not assignable from List<List<String>>
+    JClassType listOfRawList = oracle.getParameterizedType(genericList, new JClassType[] {genericList.getRawType()});
+    assertFalse(listOfRawList.isAssignableFrom(listOfListOfString));
+    assertFalse(listOfListOfString.isAssignableFrom(listOfRawList));
+    
+    JGenericType genericClass = oracle.getType(GenericClass.class.getName()).isGenericType();
+    JParameterizedType parameterizedGenericClass = oracle.getParameterizedType(genericClass, new JClassType[] {stringType});
+    JClassType extendsRawGenericClass = oracle.getType(ExtendsRawGenericClass.class.getName());
+
+    // GenericClass<String> is assignable from ExtendsRawGenericClass 
+    assertTrue(parameterizedGenericClass.isAssignableFrom(extendsRawGenericClass));
+    
+    // ExtendsRawGenericClass is not assignable from GenericClass<String>
+    assertFalse(extendsRawGenericClass.isAssignableFrom(parameterizedGenericClass));
+
+    // List<List<? extends Number>>
+    JClassType listOfListOfExtendsNumber = oracle.getParameterizedType(genericList, new JClassType[] {listOfExtendsNumber});
+
+    // List<List<? extends Integer>>
+    JClassType listOfListOfExtendsInteger = oracle.getParameterizedType(genericList, new JClassType[] {listOfExtendsInteger});
+  
+    assertFalse(listOfListOfExtendsNumber.isAssignableFrom(listOfListOfExtendsInteger));
+    
+    // List<Integer>
+    JClassType listOfInteger = oracle.getParameterizedType(genericList, new JClassType[] {integerType});
+    
+    // List<? extends Number> is assignable from List<Integer>
+    assertTrue(listOfExtendsNumber.isAssignableFrom(listOfInteger));
+    assertFalse(listOfExtendsNumber.isAssignableFrom(listOfObject));
+    
+    // List<? super Number> is not assignable from List<Integer>
+    assertFalse(listOfSuperNumber.isAssignableFrom(listOfInteger));
+    
+    // List<? super Number> is assignable from List<Object>
+    assertTrue(listOfSuperNumber.isAssignableFrom(listOfObject));
+  }
+
+  @Override
+  public void testIsAssignableTo() throws NotFoundException {
+    // This is covered as part of testIsAssignableFrom
   }
 
   public void testOverridableMethods_Base() throws NotFoundException {
@@ -396,9 +476,4 @@
 
     assertTrue(expectedMethods.isEmpty());
   }
-
-  @Override
-  public void testIsAssignableTo() throws NotFoundException {
-    // This is covered as part of testIsAssignableFrom
-  }
 }
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JTypeParameterTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JTypeParameterTest.java
index 9066707..55d4724 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/JTypeParameterTest.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JTypeParameterTest.java
@@ -23,11 +23,25 @@
 
 import java.io.Serializable;
 import java.util.Arrays;
+import java.util.Set;
 
 /**
  * Tests for {@link JTypeParameter}.
  */
 public class JTypeParameterTest extends JDelegatingClassTypeTestBase {
+  private static JClassType findParameterizationOf(JClassType classType,
+      JGenericType genericType) {
+    Set<JClassType> supertypes = JClassType.getFlattenedSuperTypeHierarchy(classType);
+    for (JClassType supertype : supertypes) {
+      JMaybeParameterizedType maybeParameterizedType = supertype.isMaybeParameterizedType();
+      if (maybeParameterizedType != null && maybeParameterizedType.getBaseType() == genericType) {
+        return supertype;
+      }
+    }
+
+    return null;
+  }
+
   private final boolean logToConsole = false;
   private final ModuleContext moduleContext = new ModuleContext(logToConsole
       ? new PrintWriterTreeLogger() : TreeLogger.NULL,
@@ -80,13 +94,13 @@
   }
 
   /*
-   * Checks that all non-local subtypes of the type parameter,
-   * T extends Serializable & Comparable<T> are actually assignable to 
-   * Serializable and the properly parameterized version of Comparable<T>.
+   * Checks that all non-local subtypes of the type parameter, T extends
+   * Serializable & Comparable<T> are actually assignable to Serializable and
+   * the properly parameterized version of Comparable<T>.
    */
   @Override
   public void testGetSubtypes() throws NotFoundException {
-    
+
     TypeOracle oracle = moduleContext.getOracle();
     JClassType testType = oracle.getType(MyCustomList.class.getName());
     JGenericType genericType = testType.isGenericType();
@@ -96,29 +110,48 @@
     JClassType serializableType = oracle.getType(Serializable.class.getCanonicalName());
     JGenericType comparableType = (JGenericType) oracle.getType(Comparable.class.getCanonicalName());
     JClassType[] computedSubtypes = typeParameter.getSubtypes();
-    
+
     for (JClassType computedSubtype : computedSubtypes) {
-      JParameterizedType parameterizedComparableType = oracle.getParameterizedType(
-          comparableType, new JClassType[] {computedSubtype});
       if (computedSubtype.isLocalType()) {
         // Ignore local types.
         continue;
       }
+      // Find the parameterized version of the Comparable interface.
+      JClassType comparableIntf = findParameterizationOf(computedSubtype,
+          comparableType);
+
       assertTrue(computedSubtype.isAssignableTo(serializableType));
-      assertTrue(computedSubtype.isAssignableTo(parameterizedComparableType));
+      assertTrue(computedSubtype.isAssignableTo(comparableIntf));
     }
   }
 
   @Override
   public void testIsAssignableFrom() throws NotFoundException {
     JTypeParameter testType = getTestType();
-    assertTrue(testType.isAssignableFrom(moduleContext.getOracle().getJavaLangObject()));
+    assertTrue(testType.isAssignableFrom(moduleContext.getOracle().getType(
+        Serializable.class.getName())));
+
+    // Check that the type parameter is assignable from each subtype
+    JClassType[] subtypes = testType.getSubtypes();
+    for (JClassType subtype : subtypes) {
+      assertTrue(testType.isAssignableFrom(subtype));
+    }
   }
 
   @Override
   public void testIsAssignableTo() throws NotFoundException {
     JTypeParameter testType = getTestType();
     assertTrue(testType.isAssignableTo(moduleContext.getOracle().getJavaLangObject()));
+
+    // Check that each bound is assignable to this type parameter.
+    JClassType[] typeBounds = testType.getBounds().getBounds();
+    for (JClassType typeBound : typeBounds) {
+      // Test that the type parameter is assignable to the type bound.
+      assertTrue(testType.isAssignableTo(typeBound));
+
+      // Test that the type parameter is assignable from the type bound.
+      assertTrue(typeBound.isAssignableFrom(testType));
+    }
   }
 
   @Override
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JWildcardTypeTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JWildcardTypeTest.java
index 367a39d..fa6c004 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/JWildcardTypeTest.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JWildcardTypeTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -24,6 +24,7 @@
 
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -57,6 +58,20 @@
     // Wildcard do not have nested types...
   }
 
+  @Override
+  public void testGetErasedType() throws NotFoundException {
+    TypeOracle oracle = moduleContext.getOracle();
+    JClassType numberType = oracle.getType(Number.class.getCanonicalName());
+    
+    // Tests that ? extends Number erases to number.
+    JWildcardType upperBoundWildcard = oracle.getWildcardType(new JUpperBound(numberType));
+    assertEquals(numberType, upperBoundWildcard.getErasedType());
+    
+    // Tests that ? super Number erases to Object
+    JWildcardType lowerBoundWildcard = oracle.getWildcardType(new JLowerBound(numberType));
+    assertEquals(oracle.getJavaLangObject(), lowerBoundWildcard.getErasedType());
+  }
+
   public void testGetMethods() throws NotFoundException {
     super.testGetMethods();
   }
@@ -112,8 +127,46 @@
   }
 
   @Override
-  public void testIsAssignableFrom() {
+  public void testIsAssignableFrom() throws NotFoundException {
     // Covered by the different testIsAssignableFrom*() variants below.
+    TypeOracle oracle = moduleContext.getOracle();
+    
+    
+    JClassType integerType = oracle.getType(Integer.class.getName());
+    JClassType numberType = oracle.getType(Number.class.getName());
+
+    // ? extends Number
+    JClassType extendsNumber = oracle.getWildcardType(new JUpperBound(numberType));
+    
+    // ? extends Integer
+    JClassType extendsInteger = oracle.getWildcardType(new JUpperBound(integerType));
+    
+    // Integer is not assignable from ? extends Number
+    assertFalse(integerType.isAssignableFrom(extendsNumber));
+    
+    // Integer is assignable from ? extends Integer
+    assertTrue(integerType.isAssignableFrom(extendsInteger));
+    
+    // Number is assignable from ? extends Integer
+    assertTrue(numberType.isAssignableFrom(extendsInteger));
+    
+    // ? super Integer
+    JClassType superInteger = oracle.getWildcardType(new JLowerBound(integerType));
+    
+    // Integer is assignable from ? super Integer
+    assertFalse(integerType.isAssignableFrom(superInteger));
+
+    // ? super Integer is assignable from Number
+    assertTrue(superInteger.isAssignableFrom(numberType));
+
+    JClassType superNumber = oracle.getWildcardType(new JLowerBound(numberType));
+    
+    // ? super Number is assignable from Integer
+    assertTrue(superNumber.isAssignableFrom(integerType));
+    
+    // ? super Number is assignable from Character
+    JClassType characterType = oracle.getType(Character.class.getName());
+    assertTrue(superNumber.isAssignableFrom(characterType));
   }
 
   /**
@@ -137,8 +190,7 @@
   }
 
   /**
-   * Tests that <? extends Number> is assignable from <? extends Integer> and
-   * that the reverse is not <code>true</code>.
+   * Tests that <? extends Object> is assignable to and from <? super Object>.
    */
   public void testIsAssignableFrom_Extends_Object_From_Super_Object() {
     TypeOracle oracle = moduleContext.getOracle();
@@ -147,16 +199,21 @@
     JLowerBound lowerBound = new JLowerBound(javaLangObject);
     JUpperBound upperBound = new JUpperBound(javaLangObject);
 
+    // ? super Object
     JWildcardType lowerWildcard = oracle.getWildcardType(lowerBound);
+    
+    // ? extends Object
     JWildcardType upperWildcard = oracle.getWildcardType(upperBound);
 
+    // ? extends Object assignable from ? super Object
     assertTrue(upperWildcard.isAssignableFrom(lowerWildcard));
-    assertFalse(lowerWildcard.isAssignableFrom(upperWildcard));
+    
+    // ? super Object assignable from ? extends Object
+    assertTrue(lowerWildcard.isAssignableFrom(upperWildcard));
   }
 
   /**
-   * Tests that <? super Integer> is assignable from <? super Number> and that
-   * the reverse is not <code>true</code>.
+   * Tests that <? super Integer> is assignable to and from <? super Number>.
    */
   public void testIsAssignableFrom_Super_Integer_From_Super_Number()
       throws NotFoundException {
@@ -170,15 +227,14 @@
     JWildcardType numberWildcard = oracle.getWildcardType(numberBound);
     JWildcardType integerWildcard = oracle.getWildcardType(integerBound);
 
-    assertFalse(numberWildcard.isAssignableFrom(integerWildcard));
+    assertTrue(numberWildcard.isAssignableFrom(integerWildcard));
     assertTrue(numberWildcard.isAssignableTo(integerWildcard));
     assertTrue(integerWildcard.isAssignableFrom(numberWildcard));
-    assertFalse(integerWildcard.isAssignableTo(numberWildcard));
+    assertTrue(integerWildcard.isAssignableTo(numberWildcard));
   }
 
   /**
-   * Tests that <? super Number> is assignable to <? super Integer> and that the
-   * reverse is not <code>true</code>.
+   * Tests that <? super Number> is assignable to and from <? super Integer>.
    */
   public void testIsAssignableFrom_Super_Number_To_Super_Integer()
       throws NotFoundException {
@@ -193,7 +249,7 @@
     JWildcardType integerWildcard = oracle.getWildcardType(integerBound);
 
     assertTrue(numberWildcard.isAssignableTo(integerWildcard));
-    assertFalse(integerWildcard.isAssignableTo(numberWildcard));
+    assertTrue(integerWildcard.isAssignableTo(numberWildcard));
   }
 
   @Override
@@ -222,8 +278,7 @@
   }
 
   /**
-   * Tests that <? super Number> is assignable to <? super Integer> and that
-   * the reverse is not <code>true</code>.
+   * Tests that <? super Number> is assignable to and from <? super Integer>.
    */
   public void testIsAssignableTo_Super_Number_To_Super_Integer()
       throws NotFoundException {
@@ -237,7 +292,7 @@
     JWildcardType numberWildcard = oracle.getWildcardType(numberBound);
     JWildcardType integerWildcard = oracle.getWildcardType(integerBound);
 
-    assertFalse(integerWildcard.isAssignableTo(numberWildcard));
+    assertTrue(integerWildcard.isAssignableTo(numberWildcard));
     assertTrue(numberWildcard.isAssignableTo(integerWildcard));
   }
 
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/ExtendsRawGenericClass.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/ExtendsRawGenericClass.java
new file mode 100644
index 0000000..f6a6bd9
--- /dev/null
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/ExtendsRawGenericClass.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2008 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.core.ext.typeinfo.test;
+
+/**
+ * Class used to test assignment between a parameterized type and a subclass
+ * of the raw version.
+ */
+public class ExtendsRawGenericClass extends GenericClass {
+}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericClass.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericClass.java
index 047b3af..f328c00 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericClass.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericClass.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -29,7 +29,7 @@
  * definition of GenericClass is as follows: class GenericClass<T extends
  * Serializable & Comparable<T>> implements Comparable<T> { ... }
  */
-public class GenericClass<T> implements Comparable<T> {
+public class GenericClass<T extends Serializable> implements Comparable<T>, Serializable {
   /**
    * Non-static, generic inner class.
    * 
@@ -65,8 +65,6 @@
    */
 //  GenericClass.NonGenericInnerClass rawNonGenericInnerClassField;
 
-  GenericClass<Integer>.Foo.Bar wtf;
-
   Class rawClazzField;
 
   /**
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericSubclass.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericSubclass.java
index 23187a6..5935087 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericSubclass.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericSubclass.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -15,10 +15,12 @@
  */
 package com.google.gwt.core.ext.typeinfo.test;
 
+import java.io.Serializable;
+
 /**
  * Test a generic class that extends a generic class.
  */
-public class GenericSubclass<U> extends GenericClass<U> {
+public class GenericSubclass<U extends Serializable> extends GenericClass<U> {
   GenericClass<Integer> child;
 
   public GenericSubclass(U t) {