RFR: 8326616: tools/javac/patterns/Exhaustiveness.java intermittently Timeout signalled after 480 seconds
Jan Lahoda
jlahoda at openjdk.org
Tue Sep 3 12:36:53 UTC 2024
This patch revisits the fix for JDK-8325215 (PR: https://github.com/openjdk/jdk/pull/17949). The problem in that bug was along the following lines.
Consider this code:
sealed interface B permits S1, S2 {}
final class S1 implements B {}
final class S2 implements B {}
record R(B b, B s) {}
private void test(R r) {
switch (r) {
case R(B _, S1 _) -> {}
case R(S1 _, B _) -> {}
case R(S2 _, S2 _) -> {}
}
}
The `switch` is exhaustive, but before the fix for JDK-8325215, javac considered it not exhaustive. If ` case R(S1 _, B _)` is preplaced with ` case R(S1 _, S2 _)`, javac will consider the `switch` to be exhaustive.
This problem is because to prove that the `switch` is exhaustive, it is necessary to merge `R(S1 _, B _)` and `R(S2 _, S2 _)` into `R(B _, S2 _)`, which then can be merged with `R(B _, S1 _)` to form `R(B _, B_)`, and then just `R _`, which means the `switch` is exhaustive.
But, before JDK-8325215, javac could merge `R(S1 _, B _)` and `R(S2 _, S2 _)` into `R(B _, S2 _)`, because it was looking at the two patterns, set the mismatching component to `0`, and was looking at the patterns in all other components, if they are precisely the same - but they are not, so javac failed to merge the patterns. Note that it is permitted to replace a type pattern with a more specific type pattern (i.e. replace `B _` with `S2 _`).
The solution in JDK-8325215 was to expand all type patterns in all the patterns in the set into their possible permitted subtypes. I.e. in the above case `R(S1 _, B _)` was expanded to `R(S1 _, B _)`, `R(S1 _, S1 _)` and `R(S1 _, S2 _)`. As a consequence, the merging could proceed, and javac would consider the `switch` to be exhaustive.
The problem with this solution is that it sometimes leads to a very big pattern set, which the javac then processes very slowly/too slowly.
The proposal alternate fix for the original problem proposed herein is to avoid the creation of the very big pattern set, and rather permit javac to merge `R(S1 _, B _)` and `R(S2 _, S2 _)`, because `B` is a supertype of (more general pattern than) `S2`. This is a bit tricky, as the code that searches for merge candidates is using hashes for the patterns, and the hashes speed up the search very significantly (and the use of the hashes is not compatible with the use of the subtyping relation). So, the proposal is to use hashing when possible, and use the subtyping relation when no more patterns can be merged.
I ran the `Exhaustiveness` test many times with this change, without a timeout so far.
-------------
Commit messages:
- Cleanup.
- Cleanup.
- 8326616: tools/javac/patterns/Exhaustiveness.java intermittently Timeout signalled after 480 seconds
Changes: https://git.openjdk.org/jdk/pull/20836/files
Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=20836&range=00
Issue: https://bugs.openjdk.org/browse/JDK-8326616
Stats: 73 lines in 2 files changed: 21 ins; 35 del; 17 mod
Patch: https://git.openjdk.org/jdk/pull/20836.diff
Fetch: git fetch https://git.openjdk.org/jdk.git pull/20836/head:pull/20836
PR: https://git.openjdk.org/jdk/pull/20836
More information about the compiler-dev
mailing list