JDK-8354304 : Lambda expression types can't be classes
  • Type: CSR
  • Component: tools
  • Sub-Component: javac
  • Priority: P3
  • Status: Draft
  • Resolution: Unresolved
  • Fix Versions: 25
  • Submitted: 2025-04-10
  • Updated: 2025-04-11
Related Reports
CSR :  
Description
Summary
-------

According to the `JLS 24`, lambda expressions are compatible in an assignment context, invocation context, or casting context with a target type `T` if `T` is a functional interface type. Javac is allowing the type of lambda expressions to be classes in some cases. We are proposing fixing this issue by synchronizing the javac compiler with the `JLS 24`.

Problem
-------

Javac is not in sync with the `JLS 24`, in particular the Javac compiler is allowing the type of lambda expressions to be classes in some cases.

For example this code is accepted by javac:

    class Test {
        void m() {
            Test r = (Test & Runnable) () -> System.out.println("Hello, World!");
        }
    }

here `Test&Runnable` is an intersection type but as we will see below in the referred specification sections a notional functional interface can't be induced from it as one of its components is a class different from `java.lang.Object`

Solution
--------

Synchronize the Javac compiler with the `JLS 24`. The compiler should not allow the type of lambda and method reference expressions to be classes.

Specification
-------------

This CSR is not proposing any specification change. But there is some normative specification text related to it. We are referring to section `§15.27.3 Type of a Lambda Expression` of the `JLS 24` in particular where it reads:

    A lambda expression is compatible in an assignment context, invocation context,
    or casting context with a target type T if T is a functional interface
    type (§9.8) and the expression is congruent with the function type of the
    ground target type derived from T .

Then from `§9.8 Functional Interfaces` we have that:

    The declaration of a functional interface allows a functional interface type to be
    used in a program. There are four kinds of functional interface type:
    • An intersection type (§4.9) that induces a notional functional interface

On the other hand section `§4.9 Intersection Types` says:

    Every intersection type T 1 & ... & T n induces a notional class or interface for the
    purpose of identifying the members of the intersection type, as follows:
    (...)
    • If C k is Object , a notional interface is induced; otherwise, a notional class
    is induced with direct superclass type C k . This class or interface has direct
    superinterface types T 1 ', ..., T n ' and is declared in the package in which the
    intersection type appears.

    
Comments
[~darcy], yes as [~liach] mentioned even if users were able to produce a class file, it was rejected by the verifier at execution time. So I think if should be safe to propose this change for all --source/--release levels
11-04-2025

> What are the operational semantics at runtime of the code that, erroneously, is accepted by javac today? This causes a LambdaConversionException or VerifyError upon executing the malformed call site, so there is little compatibility concern around this change.
10-04-2025

[~vromero], pre-review comments/questions: What are the operational semantics at runtime of the code that, erroneously, is accepted by javac today? Are you proposing this change for all support --source/--release levels or just 25? If it is all levels, that change would need more consideration, corpus runs, etc. to gauge the potential source compatibility impact.
10-04-2025