JDK-6557960 : 4.4: Allow array type as bound of type variable
  • Type: Enhancement
  • Component: specification
  • Sub-Component: language
  • Affected Version: 6
  • Priority: P5
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2007-05-16
  • Updated: 2015-04-29
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.
Other
tbd_majorUnresolved
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
From: 	Neal Gafter <###@###.###>
Subject: 	javac bug? spec bug? (array type as a bound)
Date: 	Fri, 22 Sep 2006 12:11:29 -0700


Javac rejects this:

class X<T extends Object[]> {}


While examining JLS3 to see if it is allowed, I find 3.3 says

Type variables have an optional bound, T & I1 ... In. The bound consists of either a type variable, or a class or interface type T possibly followed by further interface types I 1 , ..., In.  ...


According to 4.3, array types are not class types, so javac is correct.  However, JLS does allow a type argument to be an array type: 

interface Foo<T> {}
class Main {
  public static void main(String[] args) {
    Foo<Object[]> f = null;
  }
}


Here's the problem: the capture conversion as specified will infer a type variable with an array as a bound, even though no such type exists according to 3.3:

interface Foo<T> {}
class Main {
  static <T> Foo<? extends T> foo(T t) { return null; }
  public static void main() {
    int x = foo(new Integer[0]);
  }
}

// X.java: incompatible types
// found   : Foo<capture of ? extends java.lang.Integer[]>
// required: int
//     int x = foo(new Integer[0]);
//                ^


Further, there are various places in the spec (particularly 15.12.2.7) that say things like "If X is a type variable with an upper bound that is an array type...", even though such bounds are forbidden by 3.3.

I recommend that the JLS and javac uniformly allow array types as bounds for type variables in the surface syntax.

Comments
EVALUATION Because of the way type inference is specified, I think only the first part of a bound needs to be allowable as an array type; the later parts must all continue to be interfaces: "Type variables have an optional bound, T & I1 ... In. The bound consists of a reference type T possibly followed by further interface types I1...In." The syntaxes in sections 4 and 18 are OK. But there is a difficulty in the calculation of an intersection type T[] & I1 ... In. I have noted elsewhere (mail with Yulia Novozhilova) that the JLS is not intuitive in the calculation of members of T1 & ... & Tn, and that rather than always using a "synthetic" interface IT_j to capture the members of T_j, we could capture the members explicitly in some cases. The first step in calculating members finds a deepest common supertype; the possibility that the supertype is an array type is already admitted. That is, given intersection type Integer[], Ck is Integer[]; given intersection type Integer[] & I1, Ck is Object. Then we could say: (2) For 1<=j<=n, if T_j is a type variable, then let S_j be the set of public, protected and package-private members of T_j. Otherwise, if T_j is an interface, then let IT_j be T_j. (3) Then the intersection type has the same members as a reference type with direct supertype C_k, direct superinterfaces IT_j and additional members S_j (1<=j<=n); and declared in the same package in which the intersection type appears. Finally, Maurizio discovered that members of an intersection type can be "standalone" wildcards: class A<X> { public X m() {..} } class B<Y extends A<?>> { Y f; } // What is the return type of f.m() This is very undesirable. A<?> is not a valid supertype for a class declaration, and we would like to ban types in bounds that cannot appear as supertypes in normal declarations. It should be no hardship for Y to extend A<Object>, if Y doesn't care about how A is parameterized. Unfortunately, the idiom is used widely in the JDK, e.g. Collections.sort: static <T extends Comparable<? super T>> void sort(List<T> list) The only reasonable option, and to a large extent the technically correct one, is to capture-convert the types of members in an intersection type when those members are computed. Clause (3) above should note that the type of each member is the capture conversion of the type of the corresponding member in the notional reference type.
16-05-2007