Type variable as wildcard bound

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Thu Nov 17 04:43:45 PST 2011


On 15/11/11 23:23, Zhong Yu wrote:
> Hi team, I don't understand the behavior of javac7 u2 b11 on the following code:
>
>     class G<N extends Number>  {}
>
>     <T>  void f1(G<? extends T>  k){} //error. why?
>
>     <T>  void f2(G<? super   T>  k){} //ok. why?
>
> With capture conversion applied, in f1, we have upper bound T&Number,
> lower bound null. I don't see any problem here, even if for some T,
> T&Number=null. Is the combination of T&Number illegal?
>
> In f2, we have upper bound Number, lower bound T. Since it's not true
> that T<:Number, I don't see why this should compile.
The failure you are seeing is caused by the following statement in JLS 
section 5.1.10:

"If/T_i /is a wildcard type argument of the form|? extends|/B_i /, 
then/S_i /is a fresh type variable whose upper bound is/glb(B_i /,/U_i 
[A_1 /:=/S_1 , ..., A_n /:=/S_n ]/) and whose lower bound is the null 
type, where/glb(V_1 ,... ,V_m )/is/V_1 & ... & V_m /. _It is a 
compile-time error if for any two classes (not interfaces)__/V_i 
/and/V_j ,V_i /is not a subclass of/V_j /__or vice versa._"

Historically, javac has always interpreted the underlined text very 
strictly - meaning that glb(T, Number) where T is a type-variable (whose 
bound is Object) does not exist, as neither T <: Number nor Number <: T. 
As such, the capture conversion for G<? extends T> does not exist.

While Javac 1.6 didn't complain about that specific code, it still ended 
up in calculating an erroneous glb - which then led to bad programs like 
the following to compile without errors:

class G<N extends Number> {
    private N n;
    G(N n) { this.n = n; }
    N g() { return n; };
}

class Test {
    static <T> void f1(G<? extends T> k){ String s = k.g(); }

    public static void main(String[] args) {
       Test.f1(new G<Integer>(1)); //throws CCE at runtime!!!
    }
}

In JDK 7 we made these error manifests, so that the glb computation 
failure is now explicit. This way no unsound programs will be accepted 
(and, as a side-effect, we got rid of a number of javac crashes related 
to the fact that javac needed to hanlde this erroneous captured type).

We will consider as to whether the above JLS paragraph needs rewording 
and, perhaps, to be loosened, in order to allow glb(T, Number) to yield 
T & Number.

Thanks
Maurizio
> Both f1() and f2() compiles under javac 6.

> cheers,
> Zhong Yu

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20111117/fd723b85/attachment.html 


More information about the compiler-dev mailing list