Lambda and wildcard

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Thu Oct 9 11:46:03 UTC 2025


Yes, please!

Thanks
Maurizio

On 09/10/2025 10:18, Tagir Valeev wrote:

> Hello, Maurizio!
>
> Thank you for clarifying this. Should I file an issue?
>
> With best regards,
> Tagir Valeev
>
> On Thu, Oct 9, 2025 at 11:00 AM Maurizio Cimadamore 
> <maurizio.cimadamore at oracle.com> wrote:
>
>     Hi Tagir!
>
>     Nice cacth.
>
>     Here's a slightly different example which reveals a bit more of
>     what's happening:
>
>     ```
>     interface Main {
>         interface X<T> {
>             X<T> self();
>         }
>
>         static X<?> makeX() {return null;}
>
>         static <R> X<R> create(Supplier<? extends R> supplier) {return
>     null;}
>
>         static X<X<?>> methodRef() {
>             var s = (String)create(Main::makeX);
>         }
>
>         static X<X<?>> lambda() {
>             var s = (String)create(() -> makeX());
>         }
>     }
>     ```
>
>     This prints:
>
>     ```
>     error: incompatible types: X<X<?>> cannot be converted to String
>             var s = (String)create(Main::makeX);
>                                   ^
>     error: incompatible types: X<X<CAP#1>> cannot be converted to String
>             var s = (String)create(() -> makeX());
>                                   ^
>       where CAP#1 is a fresh type-variable:
>         CAP#1 extends Object from capture of ?
>     ```
>
>     So, the main difference between the two examples is that in the
>     lambda case, the return type of the makeX call is captured. But in
>     the method refreene case no capture occurs.
>
>     I believe the lambda case works as expected, but the method
>     reference case does not.
>
>     The JLS mandates a capture of the resolved method return type (JLS
>     15.13.2, emphasis mine):
>
>>     A method reference expression is /congruent/ with a function type
>>     if both of the following are true:
>>
>>      *
>>
>>         The function type identifies a single compile-time
>>         declaration corresponding to the reference.
>>
>>      *
>>
>>          One of the following is true:
>>
>>          o
>>
>>             The result of the function type is |void|.
>>
>>          o
>>
>>              The result of the function type is R, *and the result of
>>             applying capture conversion (§5.1.10
>>             <https://docs.oracle.com/javase/specs/jls/se25/html/jls-5.html#jls-5.1.10>)
>>             to the return type of the invocation type (§15.12.2.6
>>             <https://docs.oracle.com/javase/specs/jls/se25/html/jls-15.html#jls-15.12.2.6>)
>>             of the chosen compile-time declaration is R'* (where R is
>>             the target type that may be used to infer R'), and
>>             neither R nor R' is |void|, and R' is compatible with R
>>             in an assignment context.
>>
>     It seems like javac is missing this capture conversion and,
>     because of that, the behavior of the two examples diverge.
>
>     Cheers
>     Maurizio
>
>
>
>
>
>     On 07/10/2025 17:12, Tagir Valeev wrote:
>>     Hello!
>>
>>     I'm investigating a seemingly weird compilation case. Consider
>>     the following Java interface:
>>
>>     import java.util.function.Supplier;
>>
>>     interface Main {
>>         interface X<T> {
>>             X<T> self();
>>         }
>>
>>         static X<?> makeX() {return null;}
>>
>>         static <R> X<R> create(Supplier<? extends R> supplier)
>>     {return null;}
>>
>>         static X<X<?>> methodRef() {
>>             return create(Main::makeX).self();
>>         }
>>
>>         static X<X<?>> lambda() {
>>             return create(() -> makeX()).self();
>>         }
>>     }
>>
>>     I expect that either both methods 'methodRef' and 'lambda' should
>>     be compilable or both should be non-compilable. However, while
>>     'methodRef' compiles, 'lambda' is rejected by compiler (using
>>     javac build 25+36-3489):
>>
>>     Main.java:17: error: incompatible types: X<X<CAP#1>> cannot be
>>     converted to X<X<?>>
>>             return create(() -> makeX()).self();
>>                                              ^
>>       where CAP#1 is a fresh type-variable:
>>         CAP#1 extends Object from capture of ?
>>     1 error
>>     error: compilation failed
>>
>>     Could you please help me and clarify whether this is an expected
>>     behavior or not?
>>
>>     With best regards,
>>     Tagir Valeev
>
​
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/compiler-dev/attachments/20251009/042dd368/attachment-0001.htm>


More information about the compiler-dev mailing list