Control flow analysis for exhaustive pattern-switch statement
Gavin Bierman
gavin.bierman at oracle.com
Mon Feb 7 16:31:17 UTC 2022
Thanks Tagir. I’ll take a look at the spec issue and report back.
Gavin
> On 3 Feb 2022, at 05:41, Tagir Valeev <amaembo at gmail.com> wrote:
>
> Hello!
>
> JLS requires (14.11.2) that the new "enhanced" switch statement (not
> expressions) must be exhaustive. In particular, for the switch over
> sealed abstract type, it's required to list all the permitted subtypes
> or provide a total/default branch. This is good. However, this means
> that from CFG point of view exactly one switch branch must always be
> visited. This is indeed so if we take a look at the bytecode: the
> synthetic default branch throws IncompatibleClassChangeError(). But
> compiler ignores this fact and refuses to compile the code like this
> (tried 18-ea+33-2077):
>
> sealed interface Parent {}
> record A() implements Parent {}
> record B() implements Parent {}
>
> void test(Parent p) {
> int x;
> switch (p) {
> case A a -> x = 1;
> case B b -> x = 2;
> }
> System.out.println(x); // error: variable x might not have been initialized
> }
>
> I think this is a mistake that should be corrected: in this code, `x`
> should be considered as definitely assigned.
>
> I understand that the same reasoning does not apply for switch over
> enums, as for compatibility reasons, default behavior is to do
> nothing. However, for patterns, uninitialized `x` cannot appear after
> the switch, even if we recompile the sealed interface separately
> adding one more inheritor.
>
> I try to understand what's written in 16.2.9 regarding this [1].
> Unfortunately, its current state looks confusing to me. Sorry if I'm
> missing something, as I'm not very experienced in reading chapter 16
> of JLS. Nevertheless, it says:
>
> V is [un]assigned after a switch statement (14.11) iff all of the
> following are true:
> ...
> Original spec:
> - If there is no default label in the switch block, or if the switch
> block ends with a switch label followed by the } separator, then V is
> [un]assigned after the selector expression.
> Preview spec:
> - If the switch block covers the type of the selector expression, or
> if the switch block ends with a switch label followed by the }
> separator, then V is [un]assigned after the selector expression.
>
> It looks strange that "no default label" (~= non-exhaustive) was
> replaced with "covers the type" (= exhaustive). Was negation lost
> somewhere? In current state it looks like, all exhaustive switches
> (which is almost all switches), including ones with `default` branch
> cannot definitely assign a variable, which contradicts the previous
> state.
>
> If negation is actually lost, then the sample above should compile, as
> it's exhaustive.
>
> Sorry if this was already discussed.
>
> With best regards,
> Tagir Valeev
>
> [1] https://cr.openjdk.java.net/~gbierman/jep406/jep406-20210608/specs/patterns-switch-jls.html#jls-16.2.9
More information about the amber-spec-experts
mailing list