RFR: 8326129: Java Record Pattern Match leads to infinite loop
Jan Lahoda
jlahoda at openjdk.org
Wed Feb 21 15:11:02 UTC 2024
Consider code like:
private int test(Box b) {
return switch (b) {
case Box(Integer i) -> 0;
case Box(Object o) when check(o) -> 1;
case Box(Object o) -> 2;
};
}
public record Box(Object o) {}
Note the nested `Object o` both accept `null`.
javac will compile this using two nested switches, like:
int $restartIndex = 0;
return switch (b, $restartIndex) { //will start matching as $restartIndex
case Box $b -> {
int $nestedRestartIndex = 0;
yield switch ($b.o(), $nestedRestartIndex) { //will start matching as $nestedRestartIndex
case Integer i -> 0;
case null, Object o -> {
if (!check(o)) {
$nestedRestartIndex = 2;
continue-nested-switch; //goto to the start of the nested switch again, with the updated $nestedRestartIndex
}
yield 1;
}
default -> {
$restartIndex = 1;
continue-main-switch; //goto to begining of the main switch again, with the updated $restartIndex
}
};
case Box(Object o) -> 2;
}
javac uses the restart index to implement (especially) guards - if the guard returns true, the matching (the whole switch) is restarted on the next case. javac tries to merge multiple cases with patterns with the same prefix into the same case, to reduce unnecessary matching.
There's a problem with the restarts, and that is that for `case null`, the restart index is ignored. I.e. even though the nested switch in `case null, Object o` sets the `$nestedRestartIndex` to 2, the switch will jump to `null` again after being restarted. This is because for the `null` selector, `SwitchBootstraps.typeSwitch` always returns `-1`.
The solution proposed here is to avoid factoring the nullable patterns into nested switches with any other patterns, as we cannot keep the semantics for the nested switch in such a case.
-------------
Commit messages:
- 8326129: Java Record Pattern Match leads to infinite loop
Changes: https://git.openjdk.org/jdk/pull/17951/files
Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=17951&range=00
Issue: https://bugs.openjdk.org/browse/JDK-8326129
Stats: 84 lines in 2 files changed: 82 ins; 0 del; 2 mod
Patch: https://git.openjdk.org/jdk/pull/17951.diff
Fetch: git fetch https://git.openjdk.org/jdk.git pull/17951/head:pull/17951
PR: https://git.openjdk.org/jdk/pull/17951
More information about the compiler-dev
mailing list