Incoherent invocation type inference?
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Sat Jan 14 00:42:05 UTC 2017
On 13/01/17 21:58, B. Blaser wrote:
> Hi,
>
> 2017-01-13 15:12 GMT+01:00 Maurizio Cimadamore <maurizio.cimadamore at oracle.com>:
>> I think that's correct behavior. When you say something like:
>>
>> li = get(null);
> i = get(null); // li = ... is OK ;-)
>
>> T will get two constraints:
>>
>> * an upper bound (from declared bound) : T <: Iterable<String>
>> * an upper bound (from return type compatibility) : T <: Integer
> Integer being final, a correct return type constraint would be <T =
> Integer>, leading to incompatible bounds {T <: Iterable<String>, <T =
> Integer>} and then javac should fail...?
Well, if the spec would ever add some special treatment for finality in
inference constraints (for instance cast conversion special cases final
classes to give better results), that woul dbe a way yes - but I'll
leave it to our spec experts.
In your examples though, what's really troublesome, is that you have a
generic method whose type-arguments are only instantiated from the
return type constraint. When you have a situation like that, and you mix
unchecked cast, things are going to blow up almost always - final or
not. I'd be more supportive for an optional Lint warning for cases where
inference doesn't get any constraints from the actual arguments - just
for a quick comparison, C# treats these cases as hard errors; that's not
the way Java inference has been designed from the start, but that
doesn't mean that we couldn't help programmers steer away from dubious
generic methods (like your 0-ary get() method below).
Maurizio
>
> Bernard
>
>> The language will then infer T = Integer & Iterable<String>, an intersection
>> type.
>>
>> Normally this would be fine - but the issue here is that Integer is a final
>> class, so that intersection type has no witnesses - e.g. there's no way for
>> get() to construct a type that is both an Integer and an Iterable<String> -
>> so that will almost always fail - unless get() returns null.
>>
>> That said, I'm not aware of any check in the spec for preventing an
>> intersection type to mention a final class as one of its components so,
>> while this does look weird, I think the compiler is doing what the language
>> spec says.
>>
>> Maurizio
>>
>>
>>
>> On 13/01/17 13:01, B. Blaser wrote:
>>> mport java.util.*;
>>>
>>> public class Issue {
>>> <T extends Iterable<String>> T get() { return (T)new
>>> ArrayList<String>(); }
>>> <T extends Iterable<String>> T get(T t) { return (T)new
>>> ArrayList<String>(); }
>>>
>>> void run() {
>>> List<String> li = null;
>>> LinkedList<String> ll = null;
>>> Integer i = null;
>>>
>>> li = get(null);
>>> i = get(null); // Shouldn't compile? and will fail at runtime.
>>> // i = get(li); // Fails as expected
>>>
>>> li = get();
>>> ll = get(); // OK, but will fail at runtime due to unchecked
>>> conversion in get().
>>> i = get(); // Shouldn't compile? and will fail at runtime.
>>> }
>>>
>>> public static void main(String... args) {
>>> new Issue().run();
>>> }
>>> }
>>
More information about the compiler-dev
mailing list