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