More type inference changes

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed Feb 3 21:54:34 UTC 2016


Adding Dan

On 03/02/16 18:41, Liam Miller-Cushon wrote:
> I noticed three more javac9 type inference incompatibilities, each of 
> which only occurs once in the codebase I've been testing against.
>
> 1) The following code is rejected by javac9 at head, and accepted by 
> earlier versions. The first bad revision is 3211.
>
> http://hg.openjdk.java.net/jdk9/dev/langtools/rev/3211
> http://bugs.openjdk.java.net/browse/JDK-8147493
>
> abstract class Test {
>
>   interface O<A> {}
>   interface R<B> {}
>   interface S<C> { S<C> t(C x); }
>   abstract <D> D a(Class<D> methodCall);
>   abstract R<Number> g(O<Number> q, String s);
>   abstract <E> S<E> w(E m);
>
>   S<R<Number>> f(R<Number> r) {
>     return w(g(a(O.class), a(String.class))).t(r);
>   }
> }
>
> error: incompatible types: S<R> cannot be converted to S<R<Number>>
>     return w(g(a(O.class), a(String.class))).t(r);
This looks ok to me?

I.e. the call to 'a' with O.class is fine (not unchecked) - but the next 
call to 'g' is unchecked, as the return type for 'a' is simply O and the 
target type is O<Number> - that triggers the unchecked call and that 
means that the return type of 'g' is erased to R, and then the inference 
variable of 'w' (E) is inferred as R, meaning that the return type is 
S<R> - which means the signature of 't' inside S<R> is (R)S<R>, so 
indeed the return type of that method (S<R>) seems not compatible with 
the return type of your 'f' (S<R<Number>>). Would you agree?

>                                               ^
>
> 2) This is also rejected at head, and accepted by earlier versions. 
> The first bad revision is 3030.
>
> http://hg.openjdk.java.net/jdk9/dev/langtools/rev/3030
> http://bugs.openjdk.java.net/browse/JDK-8078093
>
> abstract class Test {
>
>   interface One<A> {}
>   interface Two<B extends Three, C extends Four> {}
>   interface Three {}
>   interface Four {}
>   abstract <D> One<D> h(Class<D> clazz);
>   abstract void g(One<? extends Two<Three, Four>> x);
>
>   void f() {
>     g(h(Two.class));
>   }
> }
>
> error: incompatible types: One<Two> cannot be converted to One<? 
> extends Two<Three,Four>>
>     g(h(Two.class));
>        ^
On this one, I'm also not sure: h(Two.class) means that D is inferred as 
the raw Two. So 'h' returns One<Two>. Is One<Two> compatible with One<? 
extends Two<Three, Four>> ? This essentially means asking as to whether

Two <: Two<Three, Four>

Since containment use strict subtyping, and not unchecked, I think this 
means that this is not compatible? [For what it's worth, Eclipse agrees 
on this one]


>
> 
> 3) This one is accepted at head, and also by earlier versions. It was 
> briefly rejected between 3030 and 3109. Was the fix in 3109 deliberate?
I don't think it was deliberate to change this (in both changesets), so 
I will need to study the inference graphs before/after; Eclipse hangs 
(at least the version I tried to use) when compiling this. It seems like 
this should pass - an extra synthetic inference variable should be 
introduced for the wildcard, so that it's One<A, U> <: One<D, E>, which 
means:

A == D
U == E

and they are all inferred as Object.

Maurizio
>
> First bad revision:
> http://hg.openjdk.java.net/jdk9/dev/langtools/rev/3030
> https://bugs.openjdk.java.net/browse/JDK-8078093
>
> First good revision:
> http://hg.openjdk.java.net/jdk9/dev/langtools/rev/3109
> http://bugs.openjdk.java.net/browse/JDK-8067767
>
> abstract class Test {
>
>   interface One<G, H extends One<G, H>> {}
>   abstract <D, E extends One<D, E>> void g(One<D, E> f);
>   abstract <A> One<A, ?> h();
>
>   void f() {
>     g(h());
>   }
> }
>
> error: method g in class Test cannot be applied to given types;
>     g(h());
>     ^
>   required: One<D,E#1>
>   found: One<Object,CAP#1>
>   reason: inferred type does not conform to upper bound(s)
>     inferred: E#2
>     upper bound(s): One<Object,E#2>,One<Object,<captured wildcard>>
>   where D,E#1,E#2,<captured wildcard> are type-variables:
>     D extends Object declared in method <D,E#1>g(One<D,E#1>)
>     E#1 extends One<D,E#1> declared in method <D,E#1>g(One<D,E#1>)
>     E#2 extends One<Object,<captured wildcard>>
>     <captured wildcard> extends One<Object,E#2>
>   where CAP#1 is a fresh type-variable:
>     CAP#1 extends One<Object,CAP#1> from capture of ?
>



More information about the compiler-dev mailing list