Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6573446

javac infers a type bound where none should exist

XMLWordPrintable

    • generic
    • generic

      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.)

            dlsmith Dan Smith
            abuckley Alex Buckley
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: