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