Bug 149573 - [1.5][compiler] Improve readable name of wildcard captures
Summary: [1.5][compiler] Improve readable name of wildcard captures
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.2   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.3 M1   Edit
Assignee: Philipe Mulet CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-07-04 09:16 EDT by Philipe Mulet CLA
Modified: 2006-08-08 09:40 EDT (History)
5 users (show)

See Also:


Attachments
Proposed patch (6.97 KB, patch)
2006-07-04 09:21 EDT, Philipe Mulet CLA
no flags Details | Diff
Proposed patch (6.97 KB, patch)
2006-07-04 09:21 EDT, Philipe Mulet CLA
no flags Details | Diff
Better patch (84.80 KB, patch)
2006-07-06 07:03 EDT, Philipe Mulet CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Philipe Mulet CLA 2006-07-04 09:16:29 EDT
3.2.0

Currently, the following (invalid) program is rejected, but the error message is slightly misleading.


import java.util.List;

public class X {
	void foo(List<? extends Exception> l1, List<? extends Exception> l2) {
		l1.add(l2.get(0));
	}
}

Compiler says:
      The method add(capture-of ? extends Exception) in the type List<capture-of ? extends Exception> is not applicable for the arguments (capture-of ? extends Exception)

Note that there are 2 instances of captures, which end up being not distinguishable in the message. Along the lines of 
http://blogs.sun.com/ahe?entry=diagnosing_captured_wildcards, I am proposing to improve the rendering into something telling the capture number.


Like one of the following:

1-The method add(capture$1-of ? extends Exception) in the type List<capture$1-of ? extends Exception> is not applicable for the arguments (capture$2-of ? ? extends Exception)

2-The method add(capture#1-of ? extends Exception) in the type List<capture#1-of ? extends Exception> is not applicable for the arguments (capture#2-of ? ? extends Exception)

3-The method add(capture-1-of ? extends Exception) in the type List<capture-1-of ? extends Exception> is not applicable for the arguments (capture-2-of ? ? extends Exception)

4-The method add(capture1-of ? extends Exception) in the type List<capture1-of ? extends Exception> is not applicable for the arguments (capture2-of ? ? extends Exception)

5-The method add(capture[1]-of ? extends Exception) in the type List<capture[1]-of ? extends Exception> is not applicable for the arguments (capture[2]-of ? ? extends Exception)

6-The method add(capture'1-of ? extends Exception) in the type List<capture'1-of ? extends Exception> is not applicable for the arguments (capture'2-of ? ? extends Exception)

7-Other?

Please indicate your preference.
Comment 1 Philipe Mulet CLA 2006-07-04 09:21:40 EDT
Created attachment 45702 [details]
Proposed patch

Patch producing $-names.
e.g.
The method add(capture$1-of ? ? extends Exception) in the type List<capture$1-of ? ? extends Exception> is not applicable for the arguments (capture$2-of ? ? extends Exception)
Comment 2 Philipe Mulet CLA 2006-07-04 09:21:56 EDT
Created attachment 45703 [details]
Proposed patch

Patch producing $-names.
e.g.
The method add(capture$1-of ? extends Exception) in the type List<capture$1-of ? extends Exception> is not applicable for the arguments (capture$2-of ? extends Exception)
Comment 3 Gunnar Wagenknecht CLA 2006-07-04 09:25:04 EDT
I like the verbose (and user friendly) message found in the blog

../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);

But could also live with option one or two. But I have to admit that I still have problems understanding the generic problem, i.e. why is List<? extends Exception> different from List<? extends Exception>.
Comment 4 Jerome Lanneluc CLA 2006-07-04 09:25:54 EDT
I like capture#1 as it reads 'capture number one' and it indicates there are
several captures of the same wildcard type.
Also I vote against capture$1 as it looks like an inner-type name.
Comment 5 Markus Keller CLA 2006-07-04 09:41:59 EDT
I like proposal 2, or, even better, a javac6-style:
"The method add(capture#1 of ? extends Exception) in the type ...".

IMO, 1 and 5 could lead to confusion, since they resemble existing syntax for
other things (inner classes, array access). I can add arguments against all the others on request (i.e. if someone thinks they should be chosen).
Comment 6 Philipe Mulet CLA 2006-07-04 09:44:20 EDT
Re: comment 3

Basically, each time you use wildcard type argument (as in List<? extends Exception?), it reads: a list of some subtype of Exception, as opposed to a list of any subtype of Exception (note 'some' vs. 'any'). The compiler must ensure that you are talking about the same type when attempting to convert from one to another; since you cannot convert from arbitrary List<U> into List<V>.
The capture of 'List<? extends Exception>' produces a type: 'List<U>', where U is pretty much a type parameter generated on the fly, with upper bounds being a mix between original type parameter upper bounds and wildcard bound. This artifact is printing itself 'capture-of ? extends Exception'; i.e. it captures whatever type got supplied actually. 

Distinct references to List<? extends Exception> may denote different types, this is why the capture mechanism is performing for every single reference (which isn't what our current message is clearly saying).
Comment 7 Robert M. Fuhrer CLA 2006-07-05 10:07:42 EDT
I agree that proposal 2 ("capture#1-of ?") is probably best, as that syntax seems the least likely to be confused for anything else (anon/nested classes, array syntax, a half-mangled character literal, etc.).

Re: comment 5

I think that if one were willing to accept a space in between the number and "of" as appears in the javac6-style syntax ("capture#1 of ? extends Exception"), one might as well place another space for readability in between "capture" and "#1" as well, i.e. "capture #1 of ? extends Exception". I'm not sure I prefer either of these choices, though.
Comment 8 Walter Harley CLA 2006-07-05 21:27:54 EDT
Ah, template error messages... the bane of C++.  

I don't find any of the suggested alternatives very helpful, because I don't know what the "1" and "2" signify; I don't know in what order the compiler chooses to evaluate the captures.  Left to right?  Inside to outside?  (The example should perhaps use arg names 'a' and 'b' rather than 'l1' and 'l2', to avoid misdirection.)

One thing that makes this message confusing is the statement that "the method ... is not applicable for the arguments ...".  This is confusing because "argument" is overloaded to refer to both the declared argument and the actual value being passed.  It might be more clear to say something like "the type of the value being passed as argument [n] to method ... is '...', which is not compatible with that argument's type in the method declaration."

In this example, that would result in: "The type of the value being passed as argument 1 of method add(capture-of ? extends Exception) is 'capture-of ? extends Exception', which is not compatible with that argument's type in the method declaration."

But that is more verbose.  With less clarity, one could say "Incompatible types: passing 'capture-of ? extends Exception' as argument 1 of method add(capture-of ? extends Exception)."

That still leaves the frequently voiced confusion about why two seemingly identical types don't match; but that aspect of generics is a lot to explain in the context of an error message.  The most intuitive answer I know is that you cannot cast List<Tiger> or List<Poodle> to List<Mammal>, but can cast them to to List<? extends Mammal>.  So by treating two List<? extends Mammal> instances as if they were incompatible types, the compiler is trying to protect you from promising that a list contains only poodles and then adding a tiger to it.  If you are a sadist, there is a loophole: you can intentionally add both tigers and poodles to a List<Mammal>, and leave them to fight it out.  But at least in that case you never broke any promises.

Perhaps in the particular case where the text value of the types is identical (that is, both "capture-of ? extends X"), the error message could explain the situation: "Values of type 'capture-of ? extends X' are incompatible with arguments of that type, because the original types could be different."
Comment 9 Philipe Mulet CLA 2006-07-06 06:10:03 EDT
Walter: We are only talking about a cosmetical change avoiding ambiguities in presence of wildcard captures. Verbose messages are usually a bad idea, at least as a starting point, since you cannot easily see it all in the UI due to clipping, and people need to read a lot to figure what's going wrong. We could imagine some help context for error messages going more into details, but this is a more general issue which goes beyond the intent of this very defect.

Argument denotes the invocation argument, parameter denotes the declared parameter. All our message are phrased in consequence (if you spot some deviation from this rule, please let us know).
Comment 10 Philipe Mulet CLA 2006-07-06 07:03:15 EDT
Releasing change to HEAD, using 'capture#1-of' form.
Comment 11 Philipe Mulet CLA 2006-07-06 07:03:54 EDT
Created attachment 45830 [details]
Better patch

Patch including test changes
Comment 12 Frederic Fusier CLA 2006-08-03 08:47:41 EDT
Released for 3.3 M1
Comment 13 Frederic Fusier CLA 2006-08-08 09:40:47 EDT
Verified for 3.3 M1 using build I20060807-2000.