Closed mpalat closed 2 months ago
According to 14.11.1.1 a switch is exhaustive when (only listing cases relevant for primitives, my numbering):
- CE contains a pattern that is unconditional (14.30.3) for T.
- The type T is boolean or Boolean and CE contains both the constant true and the constant false.
- CE contains a type pattern with a primitive type P, and T is the wrapper class for the primitive type W, and the conversion from type W to type P is unconditionally exact (5.7.2).
Most directly, (2) is implemented in SwitchStatement.resolve()
in the check
lambda:
ResolvedCase
s: c
and otherResolvedCase
con.equals(c2)
) true
and one false
constantthis.switchBits |= Exhaustive
:heavy_check_mark: Next, (3) is implemented in Pattern.coversType()
, when the conversion route is one of
T -> W
, where W -> P
is identityW -> P
is unconditionally exactBaseTypeBinding.isExactWidening()
Final for (1) §14.30.3 has this:
A pattern p is said to be unconditional for a type T if every value of type T matches p, so that pattern matching requires no action at run time. It is defined as follows:
- A type pattern that declares a pattern variable of a type S is unconditional for a type T if there is a testing conversion that is unconditionally exact (5.7.2) from |T| to |S|.
This is implemented by the remaining branches of Pattern.coversType()
, where we see all four bullets from §5.7.2, corresponding to our PrimitiveConversionRoutes:
BaseTypeBinding.isExactWidening()
(see above)type.isSubtypeOf(this.resolvedType)
Furthermore, to avoid that isSubtypeOf()
is applied to byte<->char situations, that case explicitly returns false from WIDENING_AND_NARROWING_PRIMITIVE_CONVERSION.
:heavy_check_mark:
Case (2) directly sets SwitchStatement.Exhaustive
during SwitchStatement.resolve()
Cases (1) and (3) are implemented in Pattern.coversType()
which then is called from CaseStatement.resolveCasePattern()
and upon true
this will also set SwitchStatement.Exhaustive
.
The difference is due to the fact that in most cases involving primitives exhaustiveness has to be established by a single type pattern (no interaction with other patterns in this regard), but only for boolean two constants achieve the same.
I believe I'm done here :heavy_check_mark:
Resolved with #2878
Ref -https://cr.openjdk.org/~abimpoudis/instanceof/jep455-20240424/specs/instanceof-jls.html#jls-14.11
Since primitives can also make a switch enhanced the exhaustiveness rules have changes in conjunction with https://cr.openjdk.org/~abimpoudis/instanceof/jep455-20240424/specs/instanceof-jls.html#jls-5.7.2 - the unconditionally exact