Lambda and wildcard
Vicente Romero
vicente.romero at oracle.com
Fri Oct 10 15:05:03 UTC 2025
Hi Tagir,
I had already created [1]. Sorry for not sending an update yesterday,
Thanks,
Vicente
[1] https://bugs.openjdk.org/browse/JDK-8369517
On 10/10/25 09:26, Tagir Valeev wrote:
> Here it is:
>
> https://bugs.openjdk.org/browse/JDK-8369565
>
> I checked a few random OpenJDK builds I have on my machine, and it
> looks like the behavior was like this since Java 8.
>
> With best regards,
> Tagir Valeev
>
> On Thu, Oct 9, 2025 at 1:46 PM Maurizio Cimadamore
> <maurizio.cimadamore at oracle.com> wrote:
>
> 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/20251010/e5db56d2/attachment-0001.htm>
More information about the compiler-dev
mailing list