JDK-8029718 : Should always use lambda body structure to disambiguate overload resolution
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2013-12-07
  • Updated: 2020-04-08
  • Resolved: 2014-04-22
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u20 b13Fixed 9Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Description
"Potential compatibility" is specified as follows for a lambda expression:

A lambda expression (15.27) is potentially compatible with a functional interface type (9.8) if all of the following are true:
- The arity of the targeted type's function type is the same as the arity of the lambda expression.
- If the targeted type's function type has a void return, then the lambda body is either a statement expression (14.8) or a void-compatible block (15.27.2).
- If the targeted type's function type has a (non-void) return type, then the lambda body is either an expression or a value-compatible block (15.27.2).

The current javac implementation seems to only take the lambda expression's arity into account, completely ignoring the lambda body.

Example:

 interface I { 
  String foo(String [] x, String y); 
 } 

 interface J { 
  void foo(int x, int y); 
 } 

 public class X { 
     static void goo(J j) { 
         System.out.println("goo(J)"); 
     } 
     static void goo(I i) { 
         System.out.println("goo(I)"); 
     } 
     public static void main(String[] args) throws InterruptedException { 
        goo((x, y) -> { return x[0] += 1; }); // expected: print goo(I); actual: ambiguity error
     } 
 }

Originally reported on lambda-dev@openjdk.java.net:
http://mail.openjdk.java.net/pipermail/lambda-dev/2013-November/011394.html
Comments
Verified
08-08-2014

Most of the current overload resolution process for lambda expressions was introduced to fix JDK-8005244
14-03-2014

There are multiple bugs described here, and they should be addressed separately. 1) The example in the description involves the disambiguation mechanism for _implicitly-typed_ lambdas (and inexact method references). Currently, this mechanism is implemented as an arity check during applicability testing. But the correct behavior is to perform both an arity check and a more-or-less structural check of the body to ensure it is compatible with the void-ness of the targeted return. 2) The Function vs. Consumer example is not a bug. The implicitly-typed lambda 's->System.gc()' has arity 1 and a statement expression body, so it is potentially compatible with both Function and Consumer. There is, by design, no mechanism to disambiguate. 3) The Function vs. PartialFunction example (from the lambda-dev mailing list link) is (primarily) concerned with the treatment of an _explicitly-typed_ lambda when targeting two functional interface types that do or do not have wildcards. I need to look more closely at how the wildcard case is handled, but in any case there is no mechanism to disambiguate based on the 'throws' clause of a functional interface, so an ambiguity error would be expected. It is surprising that this does not happen when there are no wildcards.
06-03-2014

check also the implications for this bug from the test case reported in: http://mail.openjdk.java.net/pipermail/lambda-dev/2014-February/011910.html
25-02-2014

raising the priority to P2, the fix for this bug should provide a missing feature that it's important for lambda expressions, and has been noticed and reported by several users.
11-02-2014

Another example: public class Tmp { <T> void foo(Function<String,T> function){} void foo(Consumer<String> consumer){} void test() { foo( s->System.gc() ); // javac: foo is ambiguous } } provided by Zhong Yu on lambda-dev list.
19-12-2013

Release team: Approved for deferral.
12-12-2013

8-defer-request: This issue is important but it's a corner case, also solving this issue is not trivial and may introduce regression issues. We think that it's better to wait till 8u20 to fix this.
08-12-2013