United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6450290 Capture of nested wildcards causes type error
JDK-6450290 : Capture of nested wildcards causes type error

Details
Type:
Bug
Submit Date:
2006-07-19
Status:
Closed
Updated Date:
2011-05-18
Project Name:
JDK
Resolved Date:
2011-05-18
Component:
tools
OS:
linux
Sub-Component:
javac
CPU:
x86
Priority:
P4
Resolution:
Fixed
Affected Versions:
5.0
Fixed Versions:

Related Reports
Relates:

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.5.0_07"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_07-b03)
Java HotSpot(TM) Client VM (build 1.5.0_07-b03, mixed mode, sharing)


A DESCRIPTION OF THE PROBLEM :
In the attached code the capture of ? extends Box<?> is not treated right, allowing you to put a Box<B> in a Box<Box<A>>.
The code compiles without warnings, has no casts, but throws a ClassCastException.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile (and run) the code

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
An error from the compiler
ACTUAL -
Incorrect code compiles, and throws a ClassCastException

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.ClassCastException: B
        at CaptureBug6.main(CaptureBug6.java:9)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
// this code compiles without warnings, has no casts,
// but throws a ClassCastException
public class CaptureBug6 {
	public static void main(String[] args) {
		Box<Box<A,A	>,Box<A,A>> a = new Box<Box<A,A>,Box<A,A>>(new Box<A,A>(new 
A()));
		Box<?, ?> b = a;		
		b.value.same = new Box<B,B>(new B());
		A c = a.value.same.value;
	}
}

class Box<X extends Box<?,?>, T extends X> {
	Box (T v) {
		value = v;
	}

	Box () {}
		
	T value;
	Box<X, T> same;

}

class A extends Box<A,A> {}
class B extends Box<B,B> {}


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

                                    

Comments
SUGGESTED FIX

see http://sa.sfbay.sun.com/projects/langtools_data/7/6450290/
                                     
2008-02-26
EVALUATION

This is a javac bug. What is the type of the expression

b.value.same

where the type of B is Box<?,?> ?

Let's do one step at time. We should compute the type of b.value first, but in order to do this, we should first capture the type of b. This lead to the type Box<X,Y>, where the upperbound ub(X) = Box<?,?> and where ub(Y) = X, where both X and Y are captured type-variables.

Since the declared type of b.value is T, it turns out that the actual type of b.value is Y. So our problem is now to determine the type of the field 'same' of Box, where the site symbol is Y.

It's important to notice that when the site symbol is a type variable, javac assumes the site symbol to be the upper bound of the type variable. In this case, this means that javac looks for the field 'some' within the type ub(Y) = X.

Here's the problem, since the site symbol is still a type variable, capture conversion of the site symbol has no effect here and javac ends up in looking for 'same' again into the type ub(X) = B<?,?> and not into the type capture(ub(X)) == capture(B<?,?>) as it should be.

This lead to javac uncorrectly assume that the site symbol is indeed of type B<?,?>, so when the field 'same' is accessed, this field is of type B<?,?> (the same type as the site). This makes the assignment b.value.some = new Box<B,B>() to be wrongly marked as correct, since what the compiler is actually checking is:

Box<B,B> <: Box<?,?> (which is clearly accepted by the compiler) and not
Box<B,B> <: capture(Box<?,?>) as it should be.

The solution to this problem is to recursively walk the site symbol's upper bound until we found some type that is not itself a type variable and then apply capture conversion to that non-type variable type. In this case, when accessing 'some' in Y, javac should retrieve ub(Y) = X and then ub(X) = Box<?,?>, since X is itself a (captured) type-variable.
                                     
2008-02-26
SUGGESTED FIX

Note: one might notice that we could have used this line

site = types.upperBound(site). 

since the behaviour of types.upperBound() is exactly to walk recursively into the bounds of a given type finding the first non-type variable type.

Unfortunately the implementation of this method needs to distinguish between (i) captured type-variables and (ii) plain type-variables. In (i) the captured type-variable's bound is walked recursively. In (ii) the type-variable itself is returned. This is due to the way in which javac performs subtyping so changing this dicotomy would propagate almost everywhere! It's thus desirable to leave the implementation of types.upperBound() unchanged and to exploit a while loop that performs exactly the same steps we require (looking for the first non type-variable bound of a given type variable).
                                     
2008-04-09



Hardware and Software, Engineered to Work Together