Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 6559182
Votes 0
Synopsis Cast from a raw type with non-generic supertype to a raw type fails unexpectedly
Category java:compiler
Reported Against b105
Release Fixed 7(b27)
State 10-Fix Delivered, bug
Priority: 5-Very Low
Related Bugs 6542952
Submit Date 18-MAY-2007
Description
interface Super<P> {}
class Y implements Super<Integer>{}
interface X extends Super<Double>{}
class S extends Y {}
interface T extends X{}

public class Test{
    public static void main(String argv[]) {
        S s = null;
        T t = null;
        t = (T) s;
    }
}
Posted Date : 2007-05-18 02:18:55.0

interface Super<P> {}
class Y<A> implements Super<Integer>{}
interface X<A> extends Super<Double>{}
class S extends Y {}
interface T extends X{}

public class Test{

    public static void main(String argv[]) {
        S s = null;
        T t = null;
        t = (T) s;
    }
}
Posted Date : 2007-05-18 02:18:55.0

Compile-time error:

interface Super<P> {}
class Y implements Super<Integer>{}
interface X extends Super<Double>{}
class S<L> extends Y {}
interface T<L> extends X{}

public class Test{
    public static void main(String argv[]) {
        S s = null; // also if I use S<Byte>
        T t = null; // also if I use T<Byte>
        t = (T) s;
    }
}

Looks like a bug.  The program should compile because you cast to the  
*raw* type T.
Posted Date : 2007-05-18 02:18:55.0

Compile-time error:

interface Super<P> {}
class Y<A> implements Super<Integer>{}
interface X<A> extends Super<Double>{}
class S extends Y<Object> {}
interface T extends X<Object>{}

public class Test{
    public static void main(String argv[]) {
        S s = null;
        T t = null;
        t = (T) s;
    }
}

Yes.  Distinct supertypes: Super<Integer> and Super<Double>.
Posted Date : 2007-05-18 02:18:55.0

interface Super<P> {}
class Y<A> implements Super<Integer>{}
interface X<A> extends Super<Double>{}
class S<L> extends Y<Object> {}
interface T<L> extends X<Object>{}

public class Test{
    public static void main(String argv[]) {
        S s = null; // same if I use S<Byte>
        T t = null; // same if I use T<Byte>
        t = (T) s;
    }
}

This should not fail.  T is raw in the cast.
Posted Date : 2007-05-18 02:18:55.0
Work Around
N/A
Evaluation
Let's consider only example 3 (which is clearly buggy. In that example, T<L> has the following supertypes:

*) T<L>
*) X
*) Super<Double>

while S<L> has the following supertypes

*) S<L>
*) Y
*) Super<Integer>

In our example we have a cast from a type S (raw) to a type T (raw). Since the target type is an interface, the rule to be used for cast is the folowing (from JLS 5.5):

"If [source] is a class type:
    [...]
    * If [target] is an interface type:
          o If [source] is not a final class (§8.1.1), then, if there exists a supertype X of 	[target], and a supertype Y of [source], such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs. Otherwise, the cast is always legal at compile time (because even if [source] does not implement [target], a subclass of S might)." 

At first it may seems that a compiler error should be raised since there are indeed two provably distinct supertypes of T<L> and S<L>, namely Super<Double> and Super<Integer>. But in the example the target type is a raw type so JLS 4.8 applies

"The superclasses (respectively, superinterfaces) of a raw type are the erasures of the superclasses (superinterfaces) of any of its parameterized invocations."

The supertypes of the target type T can be rewritten as follows:

*) T
*) X
*) Super

it can be seen how, after we pick the correct supertypes for the raw T, the conflict between Super<Integer> and Super<Double> simply disappear. So this code should indeed compile.

The problem with this code is due to the fact that javac exploits a lazy scheme for supertypes resolution. The decision whether the supertype should be erased or not is based upon the current type being a raw type or not. So javac thinks the correct supertype list for the raw T is:

*) T
*) X (erasure of X is X)
*) Super<Double> (no erasure here since we are computing the supertype of X that is not raw)!
Posted Date : 2008-03-11 14:00:24.0
Comments
  
  Include a link with my name & email   


PLEASE NOTE: JDK6 is formerly known as Project Mustang