JDK-8068542 : 18.4: Improve resolution where lub is incompatible with an upper bound
  • Type: Enhancement
  • Component: specification
  • Sub-Component: language
  • Affected Version: 8
  • Priority: P5
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2015-01-06
  • Updated: 2015-12-17
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 :  
Description
Consider this bound set:

{ C<CAP1> <: t, C<CAP2> <: t, t <: C<? super Integer> }
(where CAP1 super Number and CAP2 super Integer)

18.4 says we should attempt to resolve t to 'lub(C<CAP1>, C<CAP2>)'.  Due to limitations of lub (see JDK-5052943), this is 'C<? extends Object>'.  But that type is not within the upper bound, C<? super Integer>, so resolution must fall back to generating a fresh variable.

A better solution would be to simply choose the upper bound -- it is, after all, known to be compatible with the lower bounds.

If lub were perfect, always providing an optimal answer, then this would be unnecessary.  But lub is not perfect, and probably never will be (not just because of practical constraints, but because, by design, the type system is not required to have perfect lubs).

Here's a test that should fail given the current 18.4 behavior:

public class LubVsUpper {

    interface C<T> {
        void take(C<T> arg);
    }

    static <T> C<T> pick(T one, T two, C<? super T> c) {
        return null;
    }

    static void testLowerBound(C<? super Number> superNumber, C<? super Integer> superInteger,
                                C<C<? super Integer>> cc) {
        pick(superNumber, superInteger, cc).take(cc);
        // C<CAP1> <: t, C<CAP2> <: t, t <: C<? super Integer>
    }
}

In practice, javac's implementation manages to come up with t=C<? super Integer>.  It's not clear what logic it's using to get there.