|
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
|