change in inference of unchecked calls after JDK-8147493

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Tue Jan 26 21:35:58 UTC 2016



On 26/01/16 20:09, Liam Miller-Cushon wrote:
> Thanks for the quick investigation. I wondered if this was related to 
> JDK-8135087 / JDK-6791481, but if the root cause is losing track of 
> the unchecked warning then it sounds like the similarity is superficial.
No, although you are right that these are problems with similar surface 
area. In this case the issue is that when some eager instantiation 
occurs during 18.5.2, we ignore it, and leave uninstantiated types in 
the method types; those types will eventually be replaced correctly - 
but it will be too late to issue an unchecked warning, as the enclosing 
context will already have completed resolution/inference, so any 
unchecked warning will have no effect w.r.t. erasing return types there.

I did a simple experiment with this slightly tweaked source:

abstract class Test {

  interface R<Z> {}
  interface Q<Y> {}
  interface T { <N> Q<N> n(R<N> r); }
  abstract <I> *R* isA(Class<I> t);
  abstract <W> S<W> w(W t);
  interface S<X> { S<X> t(X value); }

  void f(T t, Q<String> q) {
    w(t.n(isA(R.class))).t(q);
  }
}

Where the return type of isA() is manifestly raw. In this case javac has 
no issues. In your case the problem is a combination of eager 
instantiation and delayed checks which then causes the warning to be 
late to the overload party. Ideally the logic for the check deferral 
should be smart enough to execute checks as soon as possible, so as not 
to miss events - but in reality we only go back and look at deferred 
checks at specific points in time (i.e. when all variables in a context 
are solved), which is sometimes too late.

Maurizio
>
> On Tue, Jan 26, 2016 at 4:36 AM, Maurizio Cimadamore 
> <maurizio.cimadamore at oracle.com 
> <mailto:maurizio.cimadamore at oracle.com>> wrote:
>
>
>
>     On 26/01/16 10:18, Maurizio Cimadamore wrote:
>>     I will look into this. Thanks.
>     Update: I believe this problem has been there for a long time, but
>     the fact that unchecked conversion were not propagated correctly
>     allowed this program to compile (in fact, if you check with an
>     earlier JDK 8 build, there are some spurious unchecked warnings
>     generated as a result).
>
>     I believe the program should be accepted - I've alpha-renamed
>     type-variables in your example to make matters a bit clearer:
>
>     abstract class Test {
>
>      interface R<Z> {}
>      interface Q<Y> {}
>      interface T { <N> Q<N> n(R<N> r); }
>      abstract <I> I isA(Class<I> t);
>      abstract <W> S<W> w(W t);
>      interface S<X> { S<X> t(X value); }
>
>      void f(T t, Q<String> q) {
>        w(t.n(isA(R.class))).t(q);
>      }
>     }
>
>     The big issue occurs when we call 't.n' - performing applicability
>     inference of its argument means evaluating the expression
>     constraint isA() -> R<N>, and such a constraint should be
>     evaluated by performing invocation type inference (18.5.2).
>
>     According to 18.5.2, given that isA() returns a bare inference
>     variable ('I') and given that this inference variable has an
>     equality constraints (R) and given that there's no
>     paramaterization of the target type R<N> such that R <: R<N>,
>     eager instantiation of 'I' should occur.
>
>     Then, following 18.5.2 we should set up a type compatibility
>     constraints of the kind R -> R<N>, and that kind of compatibility
>     constraint clearly generates an unchecked warning (as per 18.2.2).
>     So, popping back, we have found an unchecked warning while proving
>     applicability of 't.n'. This should mean that invocation
>     type-inference for 't.n' we should effectively erase the return type:
>
>     "If unchecked conversion was necessary for the method to be
>     applicable during constraint set reduction in §18.5.1
>     <https://docs.oracle.com/javase/specs/jls/se8/html/jls-18.html#jls-18.5.1>,
>     the constraint formula ‹|R| → T› is reduced and incorporated with
>     B_2 ."
>
>     Which should mean W = |Q|, and then W<Q>'s member 't' should have
>     a type (Q)S<Q>, which should be compatible with Q<String>.
>
>
>
>     In terms of the implementation, javac loses the unchecked warning
>     that is generated when evaluating isA() -> R<N>; this means that
>     the method call is not treated as unchecked.
>
>     I've filed: https://bugs.openjdk.java.net/browse/JDK-8148213
>
>     Maurizio
>>
>>     Maurizio
>>
>>     On 26/01/16 04:03, Liam Miller-Cushon wrote:
>>>     The fix for JDK-8147493 (regression when type-checking unchecked
>>>     method calls) prevents the following code from compiling. It is
>>>     accepted by 8, and earlier versions of 9-dev. The return type of
>>>     w(...) is now being inferred as S<Q<Object>>. Shouldn't the
>>>     unchecked call cause return types to be erased?
>>>
>>>     abstract class Test {
>>>
>>>      interface R<E> {}
>>>      interface Q<T> {}
>>>      interface T { <E> Q<E> n(R<E> r); }
>>>      abstract <T> T isA(Class<T> t);
>>>      abstract <T> S<T> w(T t);
>>>      interface S<T> { S<T> t(T value); }
>>>
>>>      void f(T t, Q<String> q) {
>>>        w(t.n(isA(R.class))).t(q);
>>>      }
>>>     }
>>>
>>>
>>>     error: incompatible types: Q<String> cannot be converted to
>>>     Q<Object>
>>>        w(t.n(isA(R.class))).t(q);
>>>                               ^
>>>
>>>     Thanks,
>>>     Liam
>>
>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20160126/721f231e/attachment-0001.html>


More information about the compiler-dev mailing list