JDK-8025290 : javac implicit versus explicit lambda compilation error
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2013-09-24
  • Updated: 2013-11-19
  • Resolved: 2013-10-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
8 b115Fixed
Related Reports
Duplicate :  
Description
This code:

import java.util.ArrayList;
import java.util.List;
import static java.util.Comparator.comparing;
import static java.util.Comparator.nullsFirst;

public class Test<T>
{
    private void Test()
    {
        List<String> list = new ArrayList<>();
        list.sort(nullsFirst(comparing((String e) -> e.trim())));
    }
}

fails with:

Test.java:11: error: incompatible types: cannot infer type-variable(s) T,U
        list.sort(nullsFirst(comparing((String e) -> e.trim())));
                                      ^
    (argument mismatch; Function<String,CAP#1> cannot be converted to Function<? super Object,? extends String>)
  where T,U are type-variables:
    T extends Object declared in method <T,U>comparing(Function<? super T,? extends U>)
    U extends Comparable<? super U> declared in method <T,U>comparing(Function<? super T,? extends U>)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends String from capture of ? extends String
1 error

but if the lambda is implicit: e -> e.trim(), it compiles just fine.

Reported by Zhong Yu through lambda-dev@...
Comments
Thanks Dan for the example and the additional explanation, quite helpful.
14-10-2013

The specification is unclear here, and needs to be more explicit. But the expected behavior is something like this (referring to my simplified example in the previous comment): 1) Applicability testing tries to infer whether (String e)->true is compatible with P<? super t, u> (where t, u are inference variables) 2) Some new inference variables, a1 and a2, are introduced, such that the target type is P<a1,a2>, and we get a2=u (trivially) and a1=String (from equality assertion about the parameter type) 3) Because a1 is a supertype of t, we get the bound t <: String 4) Inference resolves to t=String, u=Object 5) The method is applicable
10-10-2013

A simpler case that exposes the same bug: interface P<X,Y> { boolean test(X arg); } public static <T, U> void m(P<? super T, U> p) {} m((String e) -> true); Gets a similar unexpected compiler error. Strangely, if I eliminate the (useless) second type parameter of P, it compiles without error.
10-10-2013

I fail to see the issue, your code compiles with ? extends because here you don't use the return type. If the callsite is: Comparator<String> c = mycomparing((Object e) -> e.toString()); the version with ? extends fails to compile too which is the expected behavior. So the bug here is that the version with ? super fails to compile but it should not.
10-10-2013

... or strong implications for the compiler inference engine ...
10-10-2013

After taking another look at this bug I have found that this is not an implicit versus explicit problem. This highly simplified test: -------------------------------------------------------------------------- import java.util.ArrayList; import java.util.List; import java.util.Comparator; import java.util.function.Function; public class Test { private void Test() { mycomparing((String e) -> e.toString()); } public static <Tmycomparing, Umycomparing extends Comparable<? super Umycomparing>> Comparator<Tmycomparing> mycomparing( - Function<? super Tmycomparing, ? extends Umycomparing> keyExtractor) + Function<? extends Tmycomparing, ? extends Umycomparing> keyExtractor) { return null; } } Fails with the line with the "-" symbol and works fine with the line with the "+" symbol. Check that the lambda is explicit. I think that we should consider if this is a bug or it's just that the inference machine don't have enough information to infer all the type variables. This may have strong implications for the current JDK API definition. @Brian, @Dan comments are welcomed!
10-10-2013