JDK-6573446 : javac infers a type bound where none should exist
  • Type: Bug
  • Component: specification
  • Sub-Component: language
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 2007-06-25
  • Updated: 2024-04-12
  • Resolved: 2013-07-02
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
tbdResolved
Related Reports
Duplicate :  
Duplicate :  
Description
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.)

Comments
The two linked issues (JDK-6480391, JDK-5052943) cover the spec changes proposed to address this example. The inconsistent behavior of javac is due to the unclear distinction between "?" and "? extends Object", again covered by JDK-6480391.
02-07-2013

The request to improve handling of "? super" wildcards in lub is covered by JDK-5052943.
02-07-2013

The change proposed by 6480391 would make '?' and '? extends Object' equivalent, addressing part of the concern here.
02-07-2013