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>

Reply via email to