From an email discussion with Philippe:
> Looking at the following paragraph on top of page 453, I was wondering why
> no capture conversion is applied to V when recursively applying inference
> to V << U.
> ...
> Otherwise, if the constraint has the form A <<F
> ...
> If F = U[], where the type U involves Tj, then if A is an array type
> V[], or a type variable with an upper bound that is an array type V[], where V
> is a reference type, this algorithm is applied recursively to the constraint
> V <<U.
Capture conversion was applied to A back in the 15.12.2.2 and 15.12.2.3, where the type of the actual argument expressions is taken. By 6.5.6.1, this type is after capture conversion. An array type won't be capture-converted, but this turns out not to be a problem...keep reading.
> If not applying capture conversion, then the following two programs fail
> for different reasons, which feels counter intuitive to me.
> (NOTE: these programs are intended to fail to compile, but what is
> interesting is the error message revealing different inference results).
>
> The first program behaves as expected. Inference is fed with 2 captured
> type, and yields a List<Comparator<? extends Object>>.
>
> import java.util.*;
> public class X {
> public static <T> Comparator<T> compound(Comparator<? super T> a,
> Comparator<? super T> b,
> Comparator<? super T>... rest) {
> int j = asList2(a, b);
> }
> public static <E> List<E> asList2(E a, E b) {
> return null;
> }
> }
The constraints set up by overload resolution are:
Comparator<X> << E // X,Y are fresh type variables
Comparator<Y> << E
(X's upper bound is Object and lower bound is T. Similarly for Y.)
which reduce to
E >: Comparator<X>
E >: Comparator<Y>
javac is following the spec literally:
lci(Comparator<X>, Comparator<Y>) = Comparator<lcta(X,Y)>
lcta(X,Y) = ? extends lub(X,Y) = ? extends Object
(A better lci of Comparator<X> and Comparator<Y> - given the lower bounds of X and Y - is Comparator<? super T>. The JLS cannot currently infer this type...keep reading.)
> The second program fails with a different error message resulting from the
> fact that no capture occured on array type (fair), and thus a wildcard is
> directly injected into the inferred constraints thanks to the JLS
> paragraph I pointed above.
>
> import java.util.*;
> public class X {
> public static <T> Comparator<T> compound(Comparator<? super T> a,
> Comparator<? super T> b,
> Comparator<? super T>... rest) {
> int i = asList(a, b, rest);
> }
> public static <E> List<E> asList(E a, E b, E... rest) {
> return null;
> }
> }
Capture conversion does not apply to Comparator<? super T>[], but this is not a problem: the third actual argument can cause this constraint:
Comparator<? super T>[] << E[]
reducing to
Comparator<? super T> << E
and the lci/lcta functions are perfectly capable of dealing with Comparator<? super T> directly:
lci(Comparator<X>, Comparator<Y>, Comparator<? super T>)
lci(lci(Comparator<X>, Comparator<Y>), Comparator<? super T>)
= lci( Comparator<? extends Object>, Comparator<? super T>)
= Comparator<?>
javac obtains Comparator<? super T> here, which is strictly speaking a compiler bug. The Eclipse compiler obtains Comparator<?>.
(Sidebar: It's obvious that E should be Comparator<? super T> in both programs. The problem is that we forget the 'super T'-ness of X and Y, so inference for the first program gets a bad result. Even capture-converting the component type of the array type would not help, because we'd forget its T bound too. The right thing to do is improve lcta in the JLS to use the known bounds of type variables, whether they're captured or not.)