6559182: Cast from a raw type with non-generic supertype to a raw type fails unexpectedly
authormcimadamore
Wed, 09 Apr 2008 15:30:44 +0100
changeset 514 3942d9cdc81c
parent 513 39aee2be94a4
child 515 108201f3862c
6559182: Cast from a raw type with non-generic supertype to a raw type fails unexpectedly Summary: Javac doesn't conform to JLS 4.8 - all the supertypes of a raw type must be erased Reviewed-by: jjg
langtools/src/share/classes/com/sun/tools/javac/code/Type.java
langtools/src/share/classes/com/sun/tools/javac/code/Types.java
langtools/test/tools/javac/generics/Casting5.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java	Wed Apr 09 15:04:35 2008 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java	Wed Apr 09 15:30:44 2008 +0100
@@ -640,6 +640,10 @@
             return typarams_field;
         }
 
+        public boolean hasErasedSupertypes() {
+            return isRaw();
+        }
+
         public Type getEnclosingType() {
             return outer_field;
         }
@@ -711,6 +715,17 @@
         }
     }
 
+    public static class ErasedClassType extends ClassType {
+        public ErasedClassType(Type outer, TypeSymbol tsym) {
+            super(outer, List.<Type>nil(), tsym);
+        }
+
+        @Override
+        public boolean hasErasedSupertypes() {
+            return true;
+        }
+    }
+
     public static class ArrayType extends Type
             implements javax.lang.model.type.ArrayType {
 
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Wed Apr 09 15:04:35 2008 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Wed Apr 09 15:30:44 2008 +0100
@@ -1499,47 +1499,68 @@
      * type parameters in t are deleted.
      */
     public Type erasure(Type t) {
+        return erasure(t, false);
+    }
+    //where
+    private Type erasure(Type t, boolean recurse) {
         if (t.tag <= lastBaseTag)
             return t; /* fast special case */
         else
-            return erasure.visit(t);
+            return erasure.visit(t, recurse);
     }
     // where
-        private UnaryVisitor<Type> erasure = new UnaryVisitor<Type>() {
-            public Type visitType(Type t, Void ignored) {
+        private SimpleVisitor<Type, Boolean> erasure = new SimpleVisitor<Type, Boolean>() {
+            public Type visitType(Type t, Boolean recurse) {
                 if (t.tag <= lastBaseTag)
                     return t; /*fast special case*/
                 else
-                    return t.map(erasureFun);
+                    return t.map(recurse ? erasureRecFun : erasureFun);
             }
 
             @Override
-            public Type visitWildcardType(WildcardType t, Void ignored) {
-                return erasure(upperBound(t));
-            }
-
-            @Override
-            public Type visitClassType(ClassType t, Void ignored) {
-                return t.tsym.erasure(Types.this);
+            public Type visitWildcardType(WildcardType t, Boolean recurse) {
+                return erasure(upperBound(t), recurse);
             }
 
             @Override
-            public Type visitTypeVar(TypeVar t, Void ignored) {
-                return erasure(t.bound);
+            public Type visitClassType(ClassType t, Boolean recurse) {
+                Type erased = t.tsym.erasure(Types.this);
+                if (recurse) {
+                    erased = new ErasedClassType(erased.getEnclosingType(),erased.tsym);
+                }
+                return erased;
             }
 
             @Override
-            public Type visitErrorType(ErrorType t, Void ignored) {
+            public Type visitTypeVar(TypeVar t, Boolean recurse) {
+                return erasure(t.bound, recurse);
+            }
+
+            @Override
+            public Type visitErrorType(ErrorType t, Boolean recurse) {
                 return t;
             }
         };
+
     private Mapping erasureFun = new Mapping ("erasure") {
             public Type apply(Type t) { return erasure(t); }
         };
 
+    private Mapping erasureRecFun = new Mapping ("erasureRecursive") {
+        public Type apply(Type t) { return erasureRecursive(t); }
+    };
+
     public List<Type> erasure(List<Type> ts) {
         return Type.map(ts, erasureFun);
     }
+
+    public Type erasureRecursive(Type t) {
+        return erasure(t, true);
+    }
+
+    public List<Type> erasureRecursive(List<Type> ts) {
+        return Type.map(ts, erasureRecFun);
+    }
     // </editor-fold>
 
     // <editor-fold defaultstate="collapsed" desc="makeCompoundType">
@@ -1626,15 +1647,14 @@
                     if (t.supertype_field == null) {
                         List<Type> actuals = classBound(t).allparams();
                         List<Type> formals = t.tsym.type.allparams();
-                        if (actuals.isEmpty()) {
-                            if (formals.isEmpty())
-                                // Should not happen.  See comments below in interfaces
-                                t.supertype_field = supertype;
-                            else
-                                t.supertype_field = erasure(supertype);
-                        } else {
+                        if (t.hasErasedSupertypes()) {
+                            t.supertype_field = erasureRecursive(supertype);
+                        } else if (formals.nonEmpty()) {
                             t.supertype_field = subst(supertype, formals, actuals);
                         }
+                        else {
+                            t.supertype_field = supertype;
+                        }
                     }
                 }
                 return t.supertype_field;
@@ -1708,18 +1728,15 @@
                         assert t != t.tsym.type : t.toString();
                         List<Type> actuals = t.allparams();
                         List<Type> formals = t.tsym.type.allparams();
-                        if (actuals.isEmpty()) {
-                            if (formals.isEmpty()) {
-                                // In this case t is not generic (nor raw).
-                                // So this should not happen.
-                                t.interfaces_field = interfaces;
-                            } else {
-                                t.interfaces_field = erasure(interfaces);
-                            }
-                        } else {
+                        if (t.hasErasedSupertypes()) {
+                            t.interfaces_field = erasureRecursive(interfaces);
+                        } else if (formals.nonEmpty()) {
                             t.interfaces_field =
                                 upperBounds(subst(interfaces, formals, actuals));
                         }
+                        else {
+                            t.interfaces_field = interfaces;
+                        }
                     }
                 }
                 return t.interfaces_field;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/Casting5.java	Wed Apr 09 15:30:44 2008 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6559182
+ * @summary Cast from a raw type with non-generic supertype to a raw type fails unexpectedly
+ * @author Maurizio Cimadamore
+ *
+ * @compile Casting5.java
+ */
+
+class Casting5 {
+    static interface Super<P> {}
+    static class Y implements Super<Integer>{}
+    static interface X extends Super<Double>{}
+    static class S<L> extends Y {}
+    static interface T<L> extends X {}
+
+    public static void main(String... args) {
+        S s = null; // same if I use S<Byte>
+        T t = null; // same if I use T<Byte>
+        t = (T) s;
+    }
+}