JDK-6558557 : Overhaul specification of unchecked casts
  • Type: Bug
  • Component: specification
  • Sub-Component: language
  • Affected Version: 5.0,OpenJDK6
  • Priority: P5
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,linux
  • CPU: generic,unknown
  • Submitted: 2007-05-17
  • Updated: 2014-02-26
  • Resolved: 2011-07-21
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7 rcFixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
[Merged the description from 6717221]

Consider the following program:

import java.util.*;
class cast {
  Iterable<? extends Number>   x1 = null;
  Collection<? extends Number> x2 = (Collection<? extends Number>)x1; // javac generates a warning here
}

The JLS seems to mandate a warning (JLS 5.5) for a cast that can be considered 'statically-safe':

"A cast from a type S to a parameterized type (��4.5) T is unchecked unless at least one of the following conditions hold:
1) S <: T.
2) All of the type arguments (��4.5.1) of T are unbounded wildcards.
3) T <: S and S has no subtype XT , such that the erasures (��4.6) of X and T are the same. "

Here we have that:

1) S (Iterable<? extends Number>) is *not* a subtype of T (Collection<? extends Number>)
2) T's type argument (? extends Number) is *not* an unbounded wildcard
3) There are *infinite* subtypes of S of the kind J = Collection<? extends K>, with K <: Number, such that |J| == |T|

Thus the JLS wants the cast to raise a warning, when there is no need. In the following program, the JLS also wants a warning and javac doesn't give one:

class I1<T> {}
class I2<T> extends I1<T> {}
class Main {
  void f(I1<Integer> i1) { Object o = (I2<? extends Number>) i1; }
}

The code is safe and no warning is logically "necessary" because no heap pollution can result from the cast at runtime, but it is a shortcoming of the specification that it doesn't justify javac's behavior. In short, it is both a javac bug (it doesn't comply with the specification) and a specification bug (the spec should justify javac's current behavior).

This area of the JLS would benefit from an overhaul.

On 1/7/07, ... wrote:
We issue an unchecked cast warning on this:
        
        interface I1<T> {}
        class GC22<T> implements I1<T> {}
        class A {
                 I1<Short>[] x = null;
                 GC22<? extends Number>[] y = (GC22<? extends Number>[])x; 
        }
        
        but javac doesn't.  Is this because the rules in JLS 5.5 about unchecked
        casts refer to parameterized types, and an array of a parameterized type
        doesn't count as a parameterized type?

Comments
EVALUATION 5.5 says: a cast from a source type to a parameterized type T is safe if it's an upcast, or a downcast where |T| is the only possible target, or a cast where T is parameterized as generally as possible (so all information about the source type is lost, and we'll check T's relationship to the source type elsewhere). Casting I1<Integer> to I2<? extends Number> is a downcast where the only possible subtype of I1<Integer>, i.e. I2<Integer>, erases to the same as I2<? extends Number>. So, the cast is unchecked and needs a warning, which javac doesn't give. However, the Description is right that no heap pollution can occur; ultimately, if type arguments in T contain those in S, then the JLS should not require a warning. In additions to CR 6526446 (the master CR for JLS 5.5), JLS 5.5 should say: "A cast from a type S to a parameterized type (��4.5) T is unchecked unless at least one of the following conditions hold: ... 3) T <: S and S has no subtype X != T, such that ***the type arguments of X are not contained in the type arguments of T***." Casting I1<?> to I2<? extends Number> would be a different story, since I1<?> has many subtypes which all erase to the same as I2<? extends Number>, so an unchecked warning would be raised over heap pollution. In the case of: I1<Short>[] x = null; ... (GC22<? extends Number>[])x; JLS 5.5 states that the [] of both source and target are stripped off and a casting conversion from I1<Short> to GC22<? extends Number> is pertinent. This means to start from the "The remaining cases involve conversion..." text not the "The detailed rules for compile-time legality..." text, and I agree 5.5 could be clearer on that.
12-08-2008