Search

Categories

Links

Referers

Diagnosing captured wildcards

Aug 30 2005, 07:15:53 PM PDT »Java»Compiler Comments [7]
I have never really been happy with the current state of affairs when it comes to how javac diagnose wildcards. Consider this program:
interface List<E> {}

class Test {
    <T> void merge(List<T> l1, List<T> l2) {}
    void test(List<? extends Test> list) {
	merge(list, list);
    }
}

The compiler says:

../Test.java:6: <T>merge(List<T>,List<T>) in Test cannot be applied to
(List<capture of ? extends Test>,List<capture of ? extends Test>)
        merge(list, list);
        ^
1 error

This is confusing because how is List<capture of ? extends Test> different from List<capture of ? extends Test>?

I'm trying to improve this diagnostic and am considering this error message:

../Test.java:6: <T>merge(List<T>,List<T>) in Test cannot be applied to
(List<E#0 (capture of ? extends Test)>,List<E#1 (capture of ? extends Test)>)
        merge(list, list);
        ^
1 error

It should now be clear that List<E#0 (capture of ? extends Test)> is different from List<E#1 (capture of ? extends Test)>.

UPDATE: what I would really like is something along these lines:

../Test.java:6: <T>merge(List<T>,List<T>) in Test cannot be applied to (List<E#0>,List<E#1>)
  where E#0 and E#1 are type variables
    and E#0 extends Test (capture of ? extends Test)
    and E#1 extends Test (capture of ? extends Test)
        merge(list, list);
        ^
1 error

However, I think this would require too much restructuring and prefer to defer this to Dolphin. The above is a fairly simple change to the compiler and is possible for Mustang.

Post a Comment:
Comments are closed for this entry.
Comments:

It's better -- but it's still a long way from good. I'm not sure that you can get there from here

Posted by David Hall on August 31, 2005 at 10:12 AM PDT #

How about List<(capture of ? extends Test)#0>,List<(capture of ? extends Test)#1>). Also the notation of wildcard capture itself could be reworked. This way the ambiguity between captures written in postfix form and e.g. arrays written in prefix form could be avoided.

Posted by Eugene Vigdorchik on August 31, 2005 at 11:02 AM PDT #

<code>E#0 extends Test (capture of ? extends Test)</code> seems a bit frightening. What about <code>capture-1 of ? extends Test</code> ?

Posted by Eamonn McManus on September 07, 2005 at 05:44 AM PDT #

Peter, i don't understand why there is an E in your error messages.
Why not replace E by T ?
../Test.java:6: <T>merge(List<T>,List<T>) in Test cannot be applied to
(List<T#0 (capture of ? extends Test)>,List<T#1 (capture of ? extends Test)>)
        merge(list, list);
        ^
1 error

Like Eamonn, i think an error message without parenthesis is more readable. For me, the wilcard signe (?) must be numbered not the capture.
So <tt>capture of ?1 extends Test</tt> have my vote.

I think the version for dolphin is too long and don't explain more that the mustang one. A 4 lines error message scary me more than it inform me.
Ok, it's less than a regular G++ message about template but that is not a reason.

Posted by Rémi Forax on September 07, 2005 at 02:24 PM PDT #

What I find most confusing about this example is that it <em>isn't</em> really an error. The same list is passed to merge and therefore it must have the same type!

Therefore my ideal would be for this example to pass! However there are probably other examples that should genuinely fail. Therefore any error message that adds a number to indicate that multiple captures are going on would help. I suggest something like:

../Test.java:6: <T>merge(List<T>,List<T>) in Test cannot be applied to
(List<capture 1 of (? extends Test)>,List<capture 2 of (? extends Test)>). Note: the captures are to the type checker different types even if they are in some way related (e.g. the same type).
        merge(list, list);
        ^
1 error

The main difference c.f. your original is that I have used English instead of symbols and added a clarifying note to the message.

PS I would encourage you to improve the error messages, it is an important area and one of the reasons I dislike C++ templates are that the error messages are hard to follow.

Posted by Howard Lovatt on September 20, 2005 at 08:47 PM PDT #

Based on the comments I think I'll go with something like this for Mustang:
../Test.java:6: <T>merge(List<T>,List<T>) in Test cannot be applied to
(List<capture#0 of ? extends Test>,List<capture#1 of ? extends Test>)
        merge(list, list);
        ^
1 error

Posted by Peter Ah&eacute; on September 20, 2005 at 09:09 PM PDT #

2nd try:
../Test.java:6: [T]merge(List[T],List[T]) in Test cannot be applied to
(List[capture 1 of (? extends Test)],List[capture 2 of (? extends Test)]). Note: the captures are to the type checker different types even if they are in some way related (e.g. the same type).
PS I substituted square braces for angle braces because it won't post with angle braces even if I use HTML escapes!

Posted by Howard Lovatt on September 20, 2005 at 09:21 PM PDT #

Java is a trademark of Sun Microsystems, Inc.
Copyright © 2006,2007 Peter von der Ahé