JDK-6467183 : javac fails to raise unchecked warning on cast of parameterized generic subclass
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 5.0,6
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,linux
  • CPU: generic,x86
  • Submitted: 2006-09-05
  • Updated: 2012-01-13
  • Resolved: 2012-01-13
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 b51Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0-rc"
Java(TM) SE Runtime Environment (build 1.6.0-rc-b98)
Java HotSpot(TM) Client VM (build 1.6.0-rc-b98, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Linux coco-laptop 2.6.15-26-686 #1 SMP PREEMPT Thu Aug 3 03:13:28 UTC 2006 i686 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
In the exact construct used in the Collections.emptyList() method, javac fails to raise an unchecked warning where it should.  The test case shows the bug; and it also shows that an equally uncheckable cast, without a subtype introduced, does raise the warning.

It seems to appear to me that the author of the collections class may have used this technique thinking that since the returned object never operates on any object of its type argument type that it turns out to be safe to perform this cast.  Unfortunately it must lead to a warning.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create some generic class.
2. Create a subclass with a given type argument type.
3. Create an instance of the subclass.
4. Cast the subclass to the superclass type with some other generic argument type.

The case will not raise a warning though it should.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The unchecked warning.
ACTUAL -
No warning.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
If the casted object does in fact contain some reference of a type not matching the type given in the cast expression then a runtime exception can occur.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
(Compile this class with the "-Xlint" option and see that no warnings are raised.  Then run it and see a runtime exception due to an unchecked erroneous cast.  Uncomment the optional code to see another path to attempting the same cast which does raise a warning.)


// A generic class:
public class TypedCastBug<T> {
    
    // A parameterized subclass, typed with Object:
    static class Child extends TypedCastBug<Object> { }
    
    
    // ** This method performs an unchecked cast that javac
    //    erroneously does not issue a warning for:
    static <U> TypedCastBug<U> create() {
        Child child = new Child();
        child.set(new Object());
        return (TypedCastBug<U>) child;
    }
    
    
    // Run this to see a runtime exception caused through the cast in create():
    public static void main(String[] args) {
        TypedCastBug<Number> c = create();
        Number n = c.get();
    }
    
    
    // Instance data and methods:
    T t;
    void set(T t) { this.t = t; }
    T get() { return t; }
    
    
    // An example of a similar API that does cause javac to raise a warning:
//    static TypedCastBug<Object> willWarn = new TypedCastBug<Object>();
//    static <U> TypedCastBug<U> raisesTheWarning() {
//        return (TypedCastBug<U>) willWarn;  // Effectively the same as above
//    }
    
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Note that any cast to a parameterized type is not checkable:

(List<XXX>)

The actual argument type (XXX) is not known at runtime.

Comments
SUGGESTED FIX A webrev of this fix is available at the following URL: http://hg.openjdk.java.net/jdk7/tl/langtools/rev/850869f70213
05-03-2009

EVALUATION Javac has problems in performing upcasts where the target type contains a type variable as in: Object o = (List<T>)new ArrayList<Object>(); This problem is due to the way in which the cast conversion algorithm is implemented in javac - a rewriting logic is implemented so that type variables are replaced by bounded wildcards (see 6790039) - this logic affects also the way in which unchecked diagnostics are generated because, in the above cast, javac sees the following conversion: Object o = (List<? extends Object>)new ArrayList<Object>(); This should still raise an unchecked warning according to JLS 5.5 (the target type is generic and exists a subtype X of List<? extends Object> such that |X| = |ArrayList<Object>| and that X != List<? extends Object>). But, since javac rules for determining unchecked cast are more liberal (e.g. the above cast is always safe, since ? extends Object contains Object - for this reason javac thinks that the original cast is type-safe when it's not - it's the rewritten one that it's safe and an unchecked warning should still be generated. The unchecked warning detection algorithm should use non-rewritten types.
23-01-2009

EVALUATION A bug in the compiler, a warning should be emitted. In JDK 5.0, the compiler refused to compile this program. That is also incorrect, the program should compile but with a warning on this line: return (TypedCastBug<U>) child;
05-09-2006