Generic ype inference with lower bounded types

Dan Smith daniel.smith at
Tue Jan 6 20:06:42 UTC 2015

TLDR: this is a known limitation, tracked here:

To be concrete, the problem is in the definition of the "least upper bound (lub)" function:

JLS 8 happens to sidestep the issue by using more contextual information during inference, avoiding the need to use lub, but you can still get the same problem with some tweaking of the test.

Type inference is trying to find a common supertype of the two arguments, superNumber and superInteger.  So it calls lub.  lub knows the answer is List<[something]>, and tries to find a wildcard to fill in [something].

You might think this rule would apply:
lcta(? super U, ? super V) = ? super glb(U, V)

Concretely, that would be:
lcta(? super Number, ? super Integer) = ? super Integer

But those aren't actually the types involved.  The reference to 'superNumber' has type List<CAP1> where CAP1 has lower bound Number (see JLS  Similarly, 'superInteger' has type List<CAP2> where CAP2 has lower bound Integer.

So we end up with this rule:
lcta(U, V) = U if U = V, otherwise ? extends lub(U, V)

That is,
lcta(CAP1, CAP2) = ? extends lub(CAP1, CAP2) = ? extends Object

So inference decides T=List<? extends Object>.

There's not a fundamental reason we can't do better; JDK-5052943 is being used to track any changes.


> On Jan 2, 2015, at 5:41 PM, Maurizio Cimadamore <maurizio.cimadamore at> wrote:
> Hi Sam,
> This works in JDK 8 (I think there's even a comment in SO saying that). Long story short, Java 5/6/7 inference typically ignored inference constraints coming from lower bounds; the treatment in Java 8 is much more consistent - as a result this program compiles as you'd expect (assuming you don't use -source 7).
> Maurizio
> On 03/01/15 00:07, Sam Munkes wrote:
>> Hi Guys,
>> A colleague of mine recently posted the following question to StackOverflow:
>> Does anyone on the list have insight into why the compiler does not infer lower bounded types?
>> static class Test {
>>     static <T> T pick(T one, T two) {
>>         return two;
>>     }
>>     static void testUpperBound() {
>>         List<? extends Integer> extendsInteger = new ArrayList<>();
>>         // List<? extends Integer> is treated as a subclass of List<? extends Number>
>>         List<? extends Number> extendsNumber = extendsInteger;
>>         // List<? extends Number> is inferred as the common superclass
>>         extendsNumber = pick(extendsInteger, extendsNumber);
>>     }
>>     static void testLowerBound() {
>>         List<? super Number> superNumber = new ArrayList<>();
>>         // List<? super Number> is treated as a subclass of List<? super Integer>
>>         List<? super Integer> superInteger = superNumber;
>>         // The inferred common type should be List<? super Integer>,
>>         // but instead we get a compile error:
>>         superInteger = pick(superNumber, superInteger);
>>         // It only compiles with an explicit type argument:
>>         superInteger = Test.<List<? super Integer>>pick(superNumber, superInteger);
>>     }
>> }
>> Thanks
>> --
>> Sam

More information about the compiler-dev mailing list