A couple of Bugs
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Tue Jun 7 04:32:44 PDT 2011
On 07/06/11 12:04, Ali Ebrahimi wrote:
> Hi Maurizio,
> for this:
> Array.array();
> I think, since this invocation does not have receiver object(static
> method call) then in method resolution phase non-static methods shoud
> be excluded from consideration. In this case both JDK 6/JDK 7 fails.
> now since compiler does not exclude non-static methods then it fails.
> But if I commented (excluded ) non-static method, compiler can
> resolve this invocation to static form, the thing that compiler can do
> itself for above invocation. the compiler even does not examine static
> method.
Hi Ali,
the odd behavior you describe is the result of JLS 15.12.1/2/3
15.12.1 describes what is the class/interface to search:
"If [the method name] it is a qualified name of the form TypeName .
Identifier, then the name of the method is the Identifier and the class
to search is the one named by the TypeName. If TypeName is the name of
an interface rather than a class, then a compile-time error occurs,
because this form can invoke only static methods and interfaces have no
static methods."
In your example, this means that the class to search in Array.array is
the class Array.
15.12.2.1 defines the concept of potentially applicable methods:
" member method is potentially applicable to a method invocation if and
only if all of the following are true:
The name of the member is identical to the name of the method in the
method invocation.
The member is accessible (§6.6) to the class or interface in which the
method invocation appears.
The arity of the member is lesser or equal to the arity of the method
invocation.
If the member is a variable arity method with arity n, the arity of the
method invocation is greater or equal to n-1.
If the member is a fixed arity method with arity n, the arity of the
method invocation is equal to n.
If the method invocation includes explicit type parameters, and the
member is a generic method, then the number of actual type parameters is
equal to the number of formal type parameters."
Note that the fact that the method is static/non-static never comes into
play here. Hence, there are two potentially applicable methods here,
Array.array() and Array.array(A...), respectively.
Now 15.12.2.2/3/4 describe how the method applicability check is
performed using subtyping, method conversion and variable arity
conversion, respectively. If a step fails to find at least one
candidate, resolution proceed to the following step.
In your example, 15.12.2.2 is applied (invocation by subtyping) when
considering Array.array and, since the method is virtually applicable by
subtyping, this is the only candidate applicable at this stage, and
overload resolution stops here (since the other method is a varargs
method, therefore not applicable by subtyping only).
Now, since we selected a candidate Array.array() we now have to apply
the post resolution check described in 15.12.3:
"If the method invocation has, before the left parenthesis, a MethodName
of the form TypeName.Identifier, or if the method invocation , before
the left parenthesis, has the form TypeName.NonWildTypeArguments
Identifier, then the compile-time declaration should be static. If the
compile-time declaration for the method invocation is for an instance
method, then a compile-time error occurs. (The reason is that a method
invocation of this form does not specify a reference to an object that
can serve as this within the instance method.)"
This is all to say that the current compiler behavior is justified ;-)
The thing that triggers this seemingly odd behavior lies in the fact
that the set of potentially applicable methods is built regardless of
whether the methods are static/non-static (and to whether the current
context is static or not). This means that, during overload resolution,
all methods (both static and non-static) are treated the same (except
few corner cases in which the receiver is an interface) - only after
overload resolution has been performed we eventually end up rejecting
the selected method on the basis of static-ness.
In JDK 6 your example used to work because it was as if the non-static
method was commented out - javac was not adding it to the list of
potentially applicable methods because a type-parameter was supplied to
a non-generic method. But, as it can be seen in the above text
(15.12.2.1) this behavior was overly restrictive, and has been corrected
in an early JDK 7 build. In your particular case, this unfortunately
means that, by augmenting the set of potentially applicable methods,
javac now comes up with different overload resolution candidate, hence
the error.
Maurizio
>
> Best Regards
> Ali Ebrahimi
>
>
> On Tue, Jun 7, 2011 at 1:28 PM, Maurizio Cimadamore
> <maurizio.cimadamore at oracle.com
> <mailto:maurizio.cimadamore at oracle.com>> wrote:
>
> On 07/06/11 10:17, Ali Ebrahimi wrote:
>> Hi Maurizio,
>> No, I don't think so.
>> java 6 compiler correctly resolve this invocation to static
>> varargs method.
>>
>> In this case we have two array method in Test class, on static (
>> and generic) with single varargs parameter that returns Array<A> and
>> other member method without any params that returns A[]. and
>> compiler incorrectly try to resolve two later once.
> One method is static and generic, the other method is
> non-static/non-generic. Since the invocation contains the explicit
> type-arguments, JDK 6 compiler only sees the static/generic method
> - on the other hand, JDK 7 doesn't have this restriction and sees
> both methods as potentially applicable.
>
> Try this:
>
> class Array<X> {
>
> public static <A> Array<A> array(final A... a) {
> return null;
> }
>
> public X[] array() {
> return null;
> }
> }
>
> class Test {
>
> static void test() {
> Array.<String>array(); //ok with JDK 6, fails with JDK 7
> Array.array(); //static error here in both JDK 6/JDK 7
> }
>
> }
>
>
> Maurizio
>
>>
>> public static<A> Array<A> array(final A... a) {
>> return new Array<A>(a);
>> }
>>
>> public A[] array() {
>> return null;
>> }
>>
>> public static<A> Array<A> test() {
>>
>> return Array.<A>array();
>>
>> }
>>
>> I think this clears Issue.
>>
>> Best Regards
>> Ali Ebrahimi
>>
>>
>> On Tue, Jun 7, 2011 at 12:14 PM, Maurizio Cimadamore
>> <maurizio.cimadamore at oracle.com
>> <mailto:maurizio.cimadamore at oracle.com>> wrote:
>>
>> Hi Ali,
>> the static error you are seeing is a result of the fix for
>> 5081782 (type arguments to non-generic methods) - if you
>> remove the explicit type-argument from the following invocation:
>>
>>
>> public static <A> Array<A> test() {
>> return Array.<A>array();
>> }
>>
>> You get the very same error in JDK 6. Thus, the new error in
>> JDK 7 is caused by the fact that the method Array.array() is
>> not excluded anymore from overload resolution because of
>> explicit type-arguments.
>>
>> The other is a problem with overload resolution and nested
>> lambda expression, and will be fixed.
>>
>> Maurizio
>>
>>
>>
>> On 07/06/11 04:53, Ali Ebrahimi wrote:
>>
>> class Test {
>>
>> static class Array<A> {
>> private A[] data;
>>
>> Array(A[] data) {
>> this.data = data;
>> }
>>
>> public static<A> Array<A> array(final A... a) {
>> return new Array<A>(a);
>> }
>>
>> public A[] array() {
>> return null;
>> }
>>
>> public boolean forAll(final F<A, Boolean> f) {
>> for (final A x : data)
>> if (f.f(x))
>> return true;
>>
>> return false;
>> }
>>
>> }
>>
>> public interface F<A, B> {
>> B f(A a);
>> }
>>
>> public static<A> Array<A> test() {
>> return Array.<A>array();
>> }
>>
>> public static Array<Character> fromString(final
>> String s) {
>> List<Character> cs = Collections.emptyList();
>>
>> for (int i = s.length() - 1; i>= 0; i--)
>> cs.add(s.charAt(i));
>>
>> return new Array<Character>(cs.toArray(new
>> Character[0]));
>> }
>>
>> public static void main(String[] args) {
>>
>> final Array<String> a = Array.array("Hello",
>> "There", "what", "DAY",
>> "iS", "iT");
>> final boolean b = a.forAll(#{String s ->
>> fromString(s).forAll(#{
>> Character c -> isLowerCase(c)}) }); //***********
>> System.out.println(b); // true ("what" provides
>> the only example;
>> try removing it)
>> }
>> }
>>
>>
>>
>
>
More information about the lambda-dev
mailing list