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>