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