Lambda and wildcard
Tagir Valeev
amaembo at gmail.com
Thu Oct 9 09:18:03 UTC 2025
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/20251009/f47cfe92/attachment.htm>
More information about the compiler-dev
mailing list