On Thu, 4 Dec 2025 14:40:48 GMT, Jan Lahoda <[email protected]> wrote:

>> While I agree that having a timeout in weird/non-standard in javac, I 
>> believe it is the first time when we have a process that a) can run for a 
>> very long time; b) is not required for correctness. In all other cases I can 
>> recall, if some process is slow (including e.g. verifying exhaustiveness), 
>> then it is required for correctness. And so we cannot skip it based on 
>> criteria like time.
>> 
>> The timeout here provides a way to say how much real-world time is the user 
>> willing to invest to get the outcome - if more time is invested, more 
>> detailed missing patterns may possibly be computed. It is a somewhat weird 
>> approach for javac, but it is a limit that (I think) the user and javac can 
>> agree on.
>> 
>> We could introduce a limit on e.g. the depth to which we expand, but adding 
>> one level of nesting may affect performance significantly or almost not at 
>> all, depending on e.g. the record type form/shape.
>> 
>> E.g. having a record with many components, where each component is a sealed 
>> type with many permitted subtypes, one level of nesting may lead to a high 
>> number of newly generated patterns possibly taking a lot of time to go 
>> through them. But having a record that has a single component that is not a 
>> sealed type should only generate one pattern, and so have minimal impact.
>
> As an example, if I have:
> 
> package exhaustiveness.test;
> 
> public class Deep {
> 
>     public record Box0(Box1 v) {}
>     public record Box1(Box2 v) {}
>     public record Box2(Box3 v) {}
>     public record Box3(Box4 v) {}
>     public record Box4(Box5 v) {}
>     public record Box5(Box6 v) {}
>     public record Box6(Box7 v) {}
>     public record Box7(Box8 v) {}
>     public record Box8(Box9 v) {}
>     public record Box9(I v) {}
>     public sealed interface I {}
>     public final class C1 implements I {}
>     public final class C2 implements I {}
> 
>     public int test(Box0 box0) {
>         return switch (box0) {
>             case Box0(Box1(Box2(Box3(Box4(Box5(Box6(Box7(Box8(Box9(C1 
> _)))))))))) -> 0;
>         };
>     }
> }
> 
> 
> this runs very quickly on my laptop <1s in total, despite recursing quite 
> deep (and it finds the one missing pattern). If I have something like:
> 
> package exhaustiveness.test;
> 
> public class Shallow {
> 
>     public sealed interface Base {}
> 
>     public sealed interface I0 extends Base {}
>     public non-sealed interface L0 extends Base {}
> 
>     public non-sealed interface L1 extends I0 {}
>     public non-sealed interface L2 extends I0 {}
>     public non-sealed interface L3 extends I0 {}
> //    public non-sealed interface L4 extends I0 {}
> //    public non-sealed interface L5 extends I0 {}
> //    public non-sealed interface L6 extends I0 {}
> //    public non-sealed interface L7 extends I0 {}
> //    public non-sealed interface L8 extends I0 {}
> //    public non-sealed interface L9 extends I0 {}
>     public record Data(Base b1, Base b2, Base b3, Base b4) {}
>     public int test(Data d) {
>         return switch (d) {
>             case Data(I0 _, I0 _, I0 _, I0 _) -> 0;
>             case Data(L0 _, L0 _, L0 _, L0 _) -> 0;
>             case Data(I0 _,    _,    _,    _) -> 0;
>         };
>     }
> }
> 
> 
> the current run time on my laptop is ~25s; if I un-comment L4, the time is 
> ~2m15s. Also, in this case it is relatively difficult to reduce details, as 
> if the record pattern is not expanded, the less-detailed version is simply 
> `Data _`.
> 
> So, while there may be a way to estimate complexity, it depends on many 
> factors - the depth, the number of sealed types, but also the user-written 
> patterns (as those may make exhaustiveness computation faster or slower). 
> And, to me, it feels like a heuristic to the real factor, which is what 
> duration can be reasonably spent by this computation.

Hello. I have multiple very deep and wide real-world hierarchies that I could 
run this against as a simple test. They mix sealed interfaces, enums, and 
records. In case we want to see which commandline option is a better fit. For 
example, one project in particular that very much needed this example generator 
went up to about L6, but only 3 Data slots, and not quite as wide. I have 
multiple that are ready to test right now. The data might be useful.

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

PR Review Comment: https://git.openjdk.org/jdk/pull/27256#discussion_r2590781125

Reply via email to