Incoherent invocation type inference?
B. Blaser
bsrbnd at gmail.com
Sun Jan 15 10:34:47 UTC 2017
Hi,
2017-01-14 14:12 GMT+01:00 B. Blaser <bsrbnd at gmail.com>:
> Hi,
>
> 2017-01-14 1:42 GMT+01:00 Maurizio Cimadamore <maurizio.cimadamore at oracle.com>:
>>
>>
>> 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 that case, I suggest something like below (line 899 in a more
> recent version).
>
> http://hg.openjdk.java.net/jdk9/dev/langtools/file/b6960e2da008/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java#l899
>
>> 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 don't agree with that. Let "Iterable -> List -> ArrayList" be an
unique hierarchy. In our example, "li = get()" is meaningful and won't
ever fail, but "i = get()" will always blow up!
>> I'd be more
>> supportive for an optional Lint warning for cases where inference doesn't
>> get any constraints from the actual arguments
> As unchecked cast produces a warning, javac should probably also emit
> at least a warning in our situation; but I'm not sure this would be
> really satisfying?
Could we express a rule for a "lint" warning (this is not
straightforward, I think)? Speaking of rules and inference, I was
wondering if it could be imaginable to express facts about known types
and bounds with formal logic rules; and then infer type variables
using built-in systems like Prolog?
> diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
> b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
> @@ -966,9 +966,11 @@
> //if 's' is 'null' there's no instantiated type U for which
> //U <: s (but 'null' itself, which is not a valid type)
> return false;
> + } else if ((s.tsym.flags() & Flags.FINAL) != 0) {
> + t.addBound(InferenceBound.EQ, s, Types.this);
> + } else {
> + t.addBound(InferenceBound.UPPER, s, Types.this);
> }
> -
> - t.addBound(InferenceBound.UPPER, s, Types.this);
> return true;
> }
>
>
>> - 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).
I think so, too...
>> 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