Assignments to finals in switch guards

Gavin Bierman gavin.bierman at oracle.com
Wed Apr 5 11:15:27 UTC 2023


Good catch Robbe! Guards should not assign to variables declared outside the guard, otherwise the DA/DU analysis becomes very challenging, and we will end up removing the possibility of optimising switches.

Thanks,
Gavin

On 25 Mar 2023, at 21:45, Robbe Pincket <robbepincket at live.be> wrote:

Hi all

It seems that the following code still compiles in Java 20.

```java
class Test {
    public static void main(String[] args) {
        System.out.println("Got: " + Test(17));
    }

    static boolean log(Object o) {
        System.out.println("Log:" + o);
        return false;
    }

    static String test(Object o) {
        final String s;

        switch (o) {
            case Integer i when (s = "a") != null && log(s) -> {
                return s;
            }
            case Integer i when (s = "b") != null && log(s) -> {
                return s;
            }
            case Integer i when (s = "c") != null && log(s) -> {
                return s;
            }
            case Object o1 when (s = "d") != null && log(s) || true -> {
                return s;
            }
            default -> {
                throw new IllegalStateException("Unreachable");
            }
        }
    }
}
```

The code above reassigns the final variable `s` multiple times and prints:

```
Log: a
Log: b
Log: c
Log: d
Got: d
```

Similarly  the following code:

```java
class Test {
    public static void main(String[] args) {
        System.out.println("Got: " + new Test(17).s);
    }

    boolean log(Object o) {
        System.out.println("Log: " + o + ", " + this.s);
        return false;
    }

    final String s;

    Test(Object o) {
        switch (o) {
            case Integer i when(s = "a") != null && log(s) -> {

            }
            case Integer i when(s = "b") != null && log(s) -> {

            }
            case Integer i when(s = "c") != null && log(s) -> {

            }
            case Object o1 when(s = "d") != null && log(s) || true -> {

            }
            default -> {
                throw new IllegalStateException("Unreachable");
            }
        }
    }
}
```

Also compiles and produces the following

```
Log: a, a
Log: b, b
Log: c, c
Log: d, d
Got: d
```

Showing the final field being reassigned multiple times.

Right before sending this email, I just remembered that
the first example shouldn't compile, as in each `return s;`
the `s` variable shouldn't be considered to be
definite assigned.

Kind regards
Robbe Pincket

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20230405/81a1f5ba/attachment-0001.htm>


More information about the amber-dev mailing list