JDK-8037789 : Surprising more-specific results for lambda bodies with no return expressions
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2014-03-18
  • Updated: 2016-01-21
  • Resolved: 2016-01-08
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 9
9 b102Fixed
Related Reports
Relates :  
Relates :  
Description
As pointed out in JDK-8037788, the specification of more-specific function type return types fails to account for the possibility that the a lambda body has no return expressions.  javac has the same problem, causing many types are considered "more specific" than many others, even when this is illogical.  The effect is surprising ambiguities and surprising explanations for ambiguities.

The following should succeed under both the current spec, and as revised by JDK-8037788, but produces an error:

interface I { Object run(); }
interface J { String run(); }

void m(I arg) {}
void m(J arg) {}

void test() {
    m(() -> { throw new RuntimeException(); });
}

Comments
Turns out changing the logic results in the same user-visible behavior: - If one return type is a primitive and one is a reference, then the old logic says they're both more specific than the other, and the new logic says neither is more specific. Either way, ambiguity error. - If the return types are unrelated functional interface types (however this is defined -- see JDK-8037804), then the old logic says they're both more specific than the other, and the new logic says neither is more specific. Either way, ambiguity error. - If the return types are related functional interface types, then the old logic doesn't even consider the lambda's return expressions; either way, one is more specific than the other iff first return <: second return, and not vice versa. The third case differs from the spec change (JDK-8037788) -- under the old spec, determining whether one functional interface was related to the other fell under the "for each return expression" quantifier, so got skipped when there were 0 return expressions. But javac wasn't implemented that way. So: it's not possible to write a top-level test to demonstrate this as a bug (not after JDK-8034223, anyway). However, it's a useful fix from the perspective of code maintainability.
18-12-2015

JDK-8034223 also addresses the example appearing in this bug's description. This bug remains open, however, to allow for the spec changes of JDK-8037788 to be reflected in javac.
19-03-2014

JDK-8034223 fixes one case, when one of the return types is 'void' and another is not.
18-03-2014