Lambda and wildcard
Tagir Valeev
amaembo at gmail.com
Fri Oct 10 13:26:54 UTC 2025
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:
>> -
>>
>> The result of the function type is void.
>> -
>>
>> 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/25d2efdf/attachment-0001.htm>
More information about the compiler-dev
mailing list