United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6531090 Cannot access methods/fields of a captured type belonging to an intersection type
JDK-6531090 : Cannot access methods/fields of a captured type belonging to an intersection type

Details
Type:
Bug
Submit Date:
2007-03-05
Status:
Closed
Updated Date:
2012-03-22
Project Name:
JDK
Resolved Date:
2011-05-18
Component:
tools
OS:
windows_xp
Sub-Component:
javac
CPU:
generic
Priority:
P2
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:

Related Reports
Relates:
Relates:
Relates:
Relates:

Sub Tasks

Description
JLS 4.4 Type Variables says:
The members of a type variable X with bound T & I1 ... In are the members of the intersection type (??4.9) T & I1 ... In appearing at the point where the type variable is declared.

JLS 4.9 Intersection Types
The values of an intersection type are those objects that are values of all of the types Ti, for 1in.
-------------------------------------------------------------------------

The test below declares the generic method "static <W extends F & I2> void method(C<? extends W> arg)" , 
where E - class, F - class that extends E and implements I1; I, I1 - interfaces;
C - generic class that declares type variable <T extends E & I>.
There occures a capture conversion from C<? extends W> to C<S>.

According to 5.1.10 Capture Conversion:
If Ti is a wildcard type argument of the form ? extends Bi, then Si is a fresh type variable whose upper bound is glb(Bi, Ui[A1 := S1, ..., An := Sn]) and whose lower bound is the null type, where glb(V1,... ,Vm) is V1 & ... & Vm. 

So, S has upper bound (E & I) & W.
So, the values of S are those objects that are values of all of the types E, I, W.

But test below fails.
-----------------Test code------------------------
import java.io.PrintStream;

class E {}
class F extends E implements I1 {}
interface I {}
interface I1 {}

class G extends F implements I {}

class C<T extends E & I> {
    T field;
}

public class type15302 {
    public static void main(String argv[]) {
        System.exit(run(argv, System.out) + 95/*STATUS_TEMP*/);
    }

    public static int run(String argv[], PrintStream out) {
        C<G> arg = new C<G>();
        arg.field = new G();
        method(arg);
        return 0/*STATUS_PASSED*/;
    }

    static <W extends F> void method(C<? extends W> arg) {
        F vf = arg.field;
        I vi = arg.field;
        I1 vi1 = arg.field;
        E ve = arg.field;
        W vt = arg.field;
    }
}
------------OutPut------------------------------
Information:Compilation completed with 4 errors and 0 warnings
Information:4 errors
Information:0 warnings
C:\JLS\JLS3\lang\tests\lang\TYPE\12_type153\type15302.java
    Error:Error:line (29)incompatible types
found   : capture#955 of ? extends W
required: javasoft.sqe.tests.lang.type153.type15302.F
    Error:Error:line (31)incompatible types
found   : capture#671 of ? extends W
required: javasoft.sqe.tests.lang.type153.type15302.I1
    Error:Error:line (32)incompatible types
found   : capture#442 of ? extends W
required: javasoft.sqe.tests.lang.type153.type15302.E
    Error:Error:line (33)incompatible types
found   : capture#274 of ? extends W
required: W

                                    

Comments
SUGGESTED FIX

see http://sa.sfbay.sun.com/projects/langtools_data/7/6531090
                                     
2007-12-18
EVALUATION

The descriptions refers to two unrelated bugs:

1) Assigments whose RHS type is an intersection type don't work. This may be regarded as a problem in javac's subtyping algorithm.

2) Method *and possibly field) lookup don't work on receivers whose type is a fresh type variable having as bound an intersection type.

Let's look at each error

1) Given a subtype test in the form S <: T, if S is a classtype, javac walks up in S's inheritance tree in order to find a type K that is a supertype of S such that |K| == |T|. Unfortunately a problem occur if S is an intersection type. In this case such a type K is not found and this, in turn, makes the subtyping test to fail. For example the first failing assignment of the above example is:

F vf = arg.field

where the type of "arg.field" is a captured type whose upper bound is the intersection type F&I. When javac checks the correctness of the above assignment, the subtyping test F&I <: F is issued. Since this subtyping test fails as described above (being F&I an intersection type), javac marks that assignment as wrong. 

In order to fix this problem the Types.asSuper() method needs to be fixed in order to yield the correct answer in case of intersection types.

2) This problem is due to the method/field resolution process not working properly on members of captured types. In the example reported in the "comments" subsection, all methods are invoked on a receiver that is a captured type (capture conversion comes from the former field access). The filed/method resolution lookup proceeds by recursively visiting all class types in the inheritance tree of a given type in which the field has to be accessed from. 

In the example we have that e.g. 

arg.fieldT.a()

so basically this triggers a method lookup for a() symbol inside the scope of arg.fieldT's symbol. arg.fieldT is the intersection type F&I, where F is a captured type whose upper bound is the intersection type B&I&I1. The resolution process thus fails when applied to F&I, since the supertype of F&I is F that is a captured type and not a class type as the resolver expects. 

A way to solve this problem would be to always perform method/field lookup on the upper bound of a given type. This wouldn't change the semantic of standard lookups involving classes, as the upper bound of a classtype is the classtype itself; on the other hand, it would allow for a smooth extension of the resolution process also to those types whose supertype(s) is not a class type.
                                     
2007-12-18



Hardware and Software, Engineered to Work Together