8043179: Lambda expression can mutate final field

Archie Cobbs archie.cobbs at gmail.com
Sun Sep 25 21:02:32 UTC 2022


Hi folks,

Hello, I'm new here.

As a result of trying to be less of a complainer and more of a problem
solver in life, I've decided to try to contribute fixes to some javac bugs
that have particularly annoyed me over the years.

Unfortunately I already screwed up and submitted my first PR before
discovering The OpenJDK Developer's Guide <http://openjdk.java.net/guide/>
- my apologies. A very handy reference!

Now I'm enlightened, and so first I need to backfill and...

2. Socialize your change
>
> Once the OCA is signed, please restrain your urge to create a PR just a
> little while longer. In order to prepare the community for your patch,
> please socialize your idea on the relevant mailing lists.
>

OK let's talk about this bug and this fix. The bug JDK-8043179
<https://bugs.openjdk.org/browse/JDK-8043179> is really due to a more
general problem with the JLS, which is described in JDK-8043176
<https://bugs.openjdk.org/browse/JDK-8043176>:

Chapter 16 is missing rules for handling DA/DU analysis of lambda
> expressions... To detect assignments to blank final fields, a field is
> *never* DU before the lambda body. (The intuition is that the timing of the
> body invocation is unknown, so we don't know whether the variable has been
> initialized or not.)
>

That spec bug was fixed a long time ago; now the spec says
<https://docs.oracle.com/javase/specs/jls/se19/html/jls-16.html#jls-16.1.10>
:

> If an expression is a lambda expression, then the following rules apply:
>
>    -
>
>    V is [un]assigned after the expression iff V is [un]assigned before
>    the expression.
>    -
>
>    V is definitely assigned before the expression or block that is the
>    lambda body (§15.27.2
>    <https://docs.oracle.com/javase/specs/jls/se19/html/jls-15.html#jls-15.27.2>)
>    iff V is definitely assigned before the lambda expression.
>
>    No rule allows V to be definitely unassigned before a lambda body.
>    This is by design: a variable that was definitely unassigned before the
>    lambda body may end up being assigned to later on, so we cannot conclude
>    that the variable will be unassigned when the body is executed.
>
> I'm not a JLS expert, so I'd appreciate confirmation, but what I think
this is in effect saying is that the DA/DU rules for what you can do with
instance fields in a lambda are the same as if that lambda were replaced
with the equivalent anonymous inner class - which would make perfect sense!
Here's an example of the existing discrepancy:

    import java.util.function.*;
    public class WhyAreTheseDifferent {
        final Object obj;

        final Supplier<Object> supplier1 = new Supplier<Object>() {
            @Override
            public Object get() {
                return WhyAreTheseDifferent.this.obj;  // no error here
            }
        };

        final Supplier<Object> supplier2 =
                       () -> { return this.obj; };     // error here

        WhyAreTheseDifferent(Object obj) {
            this.obj = obj;
        }
    }

If the above interpretation is correct, then the good news is that this is
an easy three line fix
<https://github.com/openjdk/jdk/pull/10381/files#diff-8973dfc1d0ee2ff1319d8753daec3f0be7e9bd0a63e9512c38a0eeed68e5bcaa>,
which is to ignore instance fields when performing DA/DU analysis, in
exactly the same way we do when visiting any normal non-initial-constructor
method during flow analysis (see this code in Flow.java
<https://github.com/openjdk/jdk/blob/3675f4c2afd10b5042948fc79e62caee5f3874ce/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java#L2287-L2291>
).

Thanks for any comments/feedback.

-Archie

-- 
Archie L. Cobbs
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/compiler-dev/attachments/20220925/9954cc14/attachment.htm>


More information about the compiler-dev mailing list