Type inference: bug or feature?

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Mon Jul 27 10:27:11 UTC 2020


On 27/07/2020 11:26, Maurizio Cimadamore wrote:
> CC'ing compiler-dev
>
> Hi Justin,
> the behavior you are observing is normal. For a Java expression to be 
> able to be influenced by type inference it has to be a poly expression 
> (where poly stands for _many_ as in, the same expression can have many 
> types).
>
> At the time we did Java 8 we briefly considered making cast 
> expressions part of the poly expression dance (like lambdas, method 
> references, method calls, parens, new creation expression, 
> conditionals and switch expression - see JLS 15.2), but the rule which 
> dictate cast conversion (JLS 5.5) are so complex (as they have to take 
> into account possibility for unchecked cast, etc.) that it felt like 
> touching them was a very risky move, with no clear benefit.
>
> The behavior you see is caused by the fact that the cast expression 
> acts as a "shield" - that is, whenever a method call appears after a 
> cast expression (as in your case), the method call is type-checked as 
> if it were in isolation, and _then_ the result of type checking is 
> validated against the cast. In other words, your example is no 
> different than doing:
>
> var x = (List<Integer>)(Object)emptyList(Number.class);
>
>
> That is, the emptyList call will see no meaningful target type (just 
> Object), so Number will be inferred and a List<Number> will be 
> returned, which will then be incompatible with the type of the cast 
> expression (List<Integer>).
>
> Your second set of examples, since it does not make use of cast 
> expressions, works as expected, as the target type can freely flow 
> inside the method call typing, and thus influence the type inference 
> result (e.g. the inference engine now sees two constraints, for 
> Integer and for Number, and is of course able to pick the "best" one).
>
> Hope this helps.
>
> Cheers
> Maurizio
>
> On 26/07/2020 18:22, Justin Dekeyser wrote:
>> Dear all,
>>
>> I'm not sure but I think I've found a bug in Java type inference 
>> mechanism.
>> It may also be a feature, so I'll expose the problem to you below; in 
>> terms
>> of Integer, Number and List, although you'll quickly realize it will 
>> work
>> wrong in any similar situation.
>>
>> Let's assume I have
>>
>> static <U, V extends U> List<U> emptyList(Class<U> magnet) {
>>     return Collections.emptyList();
>> }
>>
>> Then the following codes does not compile (for the same reason):
>>
>> var x = (List<Integer>) emptyList(Number.class);
>> List<Integer> x = (List<Integer>) emptyList(Number.class);
>>
>> incompatible types: List<Number> cannot be converted to List<Integer>
>>
>> however, the following do compile:
>>
>> var x = emptyList(Number.class); // inferred to List<Number>
>> List<Integer> x = emptyList(Number.class); // no mistake here, it's 
>> Integer
>> on the left
>>
>> Is this the expected behavior? Why does casting operation here interfere
>> with type inference like this?
>>
>> Regards,
>>
>> Justin Dekeyser
>>
>>
>>
>>
>> <https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> 
>>
>> Garanti
>> sans virus. www.avast.com
>> <https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> 
>>
>> <#DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>


More information about the compiler-dev mailing list