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