> Consider code like:
> 
> package test;
> public class Test {
>     private int test(Root r) {
>         return switch (r) {
>             case Root(R2(R1 _), R2(R1 _)) -> 0;
>             case Root(R2(R1 _), R2(R2 _)) -> 0;
>             case Root(R2(R2 _), R2(R1 _)) -> 0;
>         };
>     }
>     sealed interface Base {}
>     record R1() implements Base {}
>     record R2(Base b1) implements Base {}
>     record Root(R2 b2, R2 b3) {}
> }
> ``` 
> 
> This is missing a case for `Root(R2(R2 _), R2(R2 _))`. javac will produce an 
> error correctly, but the error is not very helpful:
> 
> $ javac test/Test.java
> .../test/Test.java:4: error: the switch expression does not cover all 
> possible input values
>         return switch (r) {
>                ^
> 1 error
> 
> 
> The goal of this PR is to improve the error, at least in some cases to 
> something along these lines:
> 
> $ javac test/Test.java 
> .../test/Test.java:4: error: the switch expression does not cover all 
> possible input values
>         return switch (r) {
>                ^
>   missing patterns:
>       Root(R2(R2 _), R2(R2 _))
> 1 error
> 
> 
> The (very simplified) way it works in a recursive (or induction) way:
> - start with defining the missing pattern as the binding pattern for the 
> selector type. This would certainly exhaust the switch.
> - for a current missing pattern, try to enhance it:
>     - if the current type is a sealed type, try to expand to its (direct) 
> permitted subtypes. Remove those that are not needed.
>     - if the current (binding pattern) type is a record type, expand it to a 
> record type, generate all possible combinations of its component types based 
> on sealed hierarchies. Remove those that are not needed.
> 
> This approach relies heavily on our ability to compute exhaustiveness, which 
> is evaluated repeatedly in the process.
> 
> There are some cases where the algorithm does not produce ideal results (see 
> the tests), but overall seems much better than what we have now.
> 
> Another significant limitation is the speed of the process. Evaluating 
> exhaustiveness is not a fast process, and this algorithm evaluates 
> exhaustiveness repeatedly, potentially for many combinations of patterns 
> (esp. for record patterns). So part of the proposal here is to have a time 
> deadline for the computation. The default is 5s, and can be changed by 
> `-XDexhaustivityTimeout=<timeout-in-ms>`.
> 
> There's also an open possibility for select tools to delay the more detailed 
> computation to some later time, although that would need to be tried and 
> evaluated.

Jan Lahoda has updated the pull request with a new target base due to a merge 
or a rebase. The pull request now contains 49 commits:

 - Avoiding repeated code as suggested.
 - Merge remote-tracking branch 'upstream/master' into JDK-8367530
 - Fixing test.
 - Merge branch 'master' into JDK-8367530-3
 - Reflecting review feedback: using multi-line diagnostics; passing 
PatternDescriptions through the diagnostics to format it at the end.
 - Fixing cases that are based on review feedback.
 - Merge branch 'master' into JDK-8367530
 - Fixing trailing whitespaces.
 - Cleanup, reflecting review feedback.
 - Apply suggestions from code review
   
   Co-authored-by: Aggelos Biboudis <[email protected]>
 - ... and 39 more: https://git.openjdk.org/jdk/compare/6f6966b2...e41e7268

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

Changes: https://git.openjdk.org/jdk/pull/27256/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=27256&range=11
  Stats: 1467 lines in 19 files changed: 1369 ins; 50 del; 48 mod
  Patch: https://git.openjdk.org/jdk/pull/27256.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/27256/head:pull/27256

PR: https://git.openjdk.org/jdk/pull/27256

Reply via email to