RFR: 8326616: tools/javac/patterns/Exhaustiveness.java intermittently Timeout signalled after 480 seconds

Aggelos Biboudis abimpoudis at openjdk.org
Tue Sep 3 14:46:20 UTC 2024


On Tue, 3 Sep 2024 12:31:18 GMT, Jan Lahoda <jlahoda at openjdk.org> wrote:

> 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 ...

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java line 1030:

> 1028:          * $record($prefix$, $resultOfReduction, $suffix$)
> 1029:          *
> 1030:          * useHashes: when true, patterns will be a subject to exact equivalence;

- will be ~a~ subject
- two binding~s~ patterns

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/20836#discussion_r1742201117


More information about the compiler-dev mailing list