hg: lambda/lambda/langtools: 8008537: Missing method reference lookup error when unbound search finds a static method

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Fri Feb 22 02:40:45 PST 2013

I think the test - or  the types in the test, to be more precise, might 
be misleading you. The goal of this test is to check provisional 
applicability of method references, a new applicability step described 
in the spec EDR. When method reference happens to be 'stuck' - that is, 
when its target type contains inference variables in the parameter types 
of the functional descriptor (as it happens to be the case here), the 
compiler revert to a much more brittle applicability scheme. It 
essentially uses the target type to perform an arity based match of the 
available methods. So, assuming the target type is:


where Z is an inference variable and SAM is declared as follows:

interface SAM<X> {
     m(X x)

If you have something like:


whose target is SAM<Z>, the compiler will:

1) Look at the target type
2) See that the method reference is stuck (parameter types of functional 
descriptor contain Z)
3) See if Foo has a method matching with a 'jolly' parameter list (*) 
[where * stands for any type]
4) If the above condition is satisfied, the method is deemed applicable. 
Most specific then follows, and, once a most specific method has been 
selected you will have a precise check with all the inference bells and 

Now, if Foo is a class that has two methods:

g(String) //any type will do

The arity-based lookup described in (3) will match both methods.

This shows that, since the arity-based lookup is fuzzy (can match 
methods with different arities due to the bound/unbound lookup 
differences) - it is possible for two target types with different 
arities to both have a match. This _doesn't_ mean that the target type 
will make the method reference checkable - it merely means that the 
provisional applicability step is satisfied (which means the method 
featuring that particular target type as formal argument is applicable).

It is possible that, even removing one of the ambiguous methods you 
still get a compiler error down the road, because when the compiler 
starts to do full type-checking of the method reference it realizes 
something is wrong.

Now, one could argue that if a method reference cannot be type-checked 
against a formal, a method should never be deemed applicable; that's 
possible - and it's the way the compiler used to work (before the 
overload resolution rewrital which happened late last year). However, 
there are situations in which you can't tell as to whether a method 
would be applicable or not unless you look at the target type of the 
method call. And we wanted to preserve the invariant that the outcome of 
overload resolution was still expressible as a function between actual 
argument types and formal argument types. Hence the provisional 
applicability check and the fuzzy arity-based matching.

Of course, all of this only takes place when a method reference is stuck 
- which can only happen if you are calling a generic method.


On 21/02/13 22:27, Ali Ebrahimi wrote:
> Hi again maurizio,
> if i comment u(Sam2) method then we have one answer u(Sam1), correct?
> in that case, we woud have u(Sam1<String>) or u(Sam1<TargetType60>)?
> I think in any case this is not correct.
> u(Sam1<String>)   => TargetType60 s2 = u(TargetType60::n1);
> method u returns String and not compatible with TargetType60.
> u(Sam1<TargetType60>) => we missed n1 String parameter and fail at 
> runtime.
>     interface Sam1<X> {
>         void m(X x);
>     }
> void n1(String s) { }
> static <U> U u(Sam1<U> s) {    s.m((U)null)     return null; }
> static void testUnbound() {
>          TargetType60 s2 = u(TargetType60::n1);
> }
> main question: what is receiver of this method reff passed to u(Sam1)?
> Best Regards,
> Ali Ebrahimi
> On Fri, Feb 22, 2013 at 1:58 AM, Maurizio Cimadamore 
> <maurizio.cimadamore at oracle.com 
> <mailto:maurizio.cimadamore at oracle.com>> wrote:
>     On 21/02/13 21:16, Ali Ebrahimi wrote:
>>     Hi maurizio,
>>     are you sure this is ambiguous? I don't think so. (u(Sam2)  is
>>     not only answer?)
>>     TargetType60 s2 = u(TargetType60::n1); //ambiguous (u(Sam1),
>>     u(Sam2) apply)
>     They both apply - turned out I've misread the spec - the fact that
>     the method is static/non-static should not affect outcome of
>     method reference resolution. So, if target type has parameters P1
>     ... Pn, we do two lookups:
>     *) one (bound) with P1 ... Pn
>     *) one (unbound) with P2 ... Pn
>     The first lookup will cause the match in u(Sam1), while the second
>     lookup will match u(Sam2). Hence the ambiguity.
>     Maurizio
>>     Best Regards,
>>     Ali Ebrahimi
>>     On Wed, Feb 20, 2013 at 11:49 PM, <maurizio.cimadamore at oracle.com
>>     <mailto:maurizio.cimadamore at oracle.com>> wrote:
>>         Changeset: 66476d1c5e64
>>         Author:    mcimadamore
>>         Date:      2013-02-20 19:19 +0000
>>         URL:
>>         http://hg.openjdk.java.net/lambda/lambda/langtools/rev/66476d1c5e64
>>         8008537: Missing method reference lookup error when unbound
>>         search finds a static method
>>         ! src/share/classes/com/sun/tools/javac/comp/Attr.java
>>         ! src/share/classes/com/sun/tools/javac/comp/Resolve.java
>>         !
>>         src/share/classes/com/sun/tools/javac/resources/compiler.properties
>>         ! test/tools/javac/diags/examples.not-yet.txt
>>         ! test/tools/javac/diags/examples/NonStaticCantBeRefFragment.java
>>         ! test/tools/javac/lambda/MethodReference22.java
>>         ! test/tools/javac/lambda/MethodReference22.out
>>         ! test/tools/javac/lambda/MethodReference28.out
>>         ! test/tools/javac/lambda/MethodReference51.out
>>         ! test/tools/javac/lambda/TargetType60.java
>>         ! test/tools/javac/lambda/TargetType60.out

More information about the lambda-dev mailing list