Type Inference Question

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed May 30 08:26:59 PDT 2012


On 30/05/12 16:14, Jan Finis wrote:
>
> Thank you very much for your comments,
>
>
> On 05/30/2012 04:38 PM, Maurizio Cimadamore wrote:
>>
>>
>> I'll leave the spec-related discussion to our spec gurus - but javac 
>> infers List<String> in such cases (i.e. no wildcard), as can be 
>> demonstrated by the following example: class Test {
>> <Z> Z m(Z z) { return null; }
>>     void test(java.util.List<String> ls) {
>>         ls = m(ls); //ok!
>>     }
>> }
>>
> I don't understand this one. This example compiles fine with my 
> compiler (which strictly adheres to the spec and calls 
> lub(List<String>) which results in List<String> in my implemention ).  
> I also get no wildcards here.
>
>
> On 05/30/2012 04:38 PM, Maurizio Cimadamore wrote:
>>
>> Javac workarounds the problem by using the capture of the upper bound 
>> of an argument type during method checking. This allows inference to 
>> infer less captured types, which, at the time the javac 
>> implementation with generics was rolled out, it was believed to be 
>> better in terms of usability.
>
> Can you try to explain that in more detail? I have tried to replace 
> captured types by their upper bounds, which makes my example compile:
>
>
> keySet = UnmodifiableMap.unmodifiableSet(m.keySet()); //Now, the upper 
> bound of "Capture of ? extends K" is used, which is K, and everything 
> compiles fine
>
>
>  However, the standard example from the spec does not compile then:
>
> public class captureConversion {
>     public static void reverse(List<?> list) {
>         rev(list);
>     }
>
>     private static <T> void rev(List<T> list) {
>         List<T> tmp = new ArrayList<T>();
>         for (int i = 0; i < list.size(); i++) {
>             list.set(i, tmp.get(list.size() - i - 1));
>         }
>     }
> }
>
> Here, the compiler correctly infers "Capture of ?" as type of T. If I 
> would infer the upper bound of that type, which is Object, then the 
> method would not compile because I cannot hand a List<?> to a method 
> wanting a List<Object>.

I haven't been clear - it's not the inference process (as described in 
15.12.2.7) that should be adjusted - it's the way in which you compute 
the actual argument types. I.e. if your argument is an expression E, the 
actual argument type to be used during method checking is 
capture(upper(typeof(E))).

Then you do inference as per JLS.

In your first example, since typeof(E) was a captured variable, this 
strategy might help you out - in the example above, the type of E is 
List<?>, so doing upper(typeof(E)) won't change things.
>
> By the way: Do I have to create a new capture type whenever capture 
> conversion is performed? I currently do it, but it creates quite some 
> capture types which are only used during the checking of single 
> expressions (because the next expression receives a new capture, even 
> if the captured argument was already captured before). It seems like 
> the eclipse jdt compiler does that, since its enumerats the captures. 
> Having ten expressions with capture conversion results in "Capture #1 
> of ..." up to Capture #10 of ...".
You should always create a new captured type for each new expression. 
Then some tricks should be used to avoid type-mismatch caused by 
slightly different capture of the same expression (I don't want to spoil 
all the fun ;-))
>
> Is the type inference part of javac open source? If so, can you give 
> me a hint where I can find it? The code might make many things clearer...

Everything is open source - look for Resolve.java, Infer.java, Attr.java 
here:

http://hg.openjdk.java.net/jdk8/jdk8/langtools/file/tip/src/share/classes/com/sun/tools/javac/comp/

Maurizio
>
> Best regards and thanks again for your help,
> Jan Finis
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20120530/7b85a1b5/attachment.html 


More information about the compiler-dev mailing list