Feedback wanted: switch expression typing
daniel.smith at oracle.com
Fri Apr 20 17:15:10 UTC 2018
> On Mar 28, 2018, at 1:37 PM, Dan Smith <daniel.smith at oracle.com> wrote:
> At this point, we've got a choice:
> A) Fully mimic the conditional behavior in switch expressions
> B) Do target typing (when available) for all switch expressions, diverging from conditionals
> C) Do target typing (when available) for all switches and conditionals, accepting the incompatibilities
The consensus of this thread seemed to be (B) or (C), which means we know what we want to do for switch expressions, and can spin off potential changes to conditionals as a separate task. (TODO: To address that task, I may drill deeper into usage statistics and refine my scanning tool.)
To formalize the typing rules for switch expressions, here's a proposed specification. Some notes:
- The goal is fidelity with conditional expressions: a standalone switch expression has the same type as an equivalent standalone conditional expression. Also, of course, the result must not be order-dependent for cases with more than 2 result expressions (test case: (int, double, Comparable<Double>)).
- A proposed new rule that hasn't been previously discussed: to facilitate typing, there must be at least one result expression. (For example, all cases could throw, and this would be a compiler error.)
- We'll need to identify all the places that poly conditional expressions get special treatment (overload resolution, inference, conditional expression classification, ...) and update them to support switch expressions too.
A switch expression is a poly expression if it appears in an assignment context or an invocation context ([5.2], [5.3]). Otherwise, it is a standalone expression.
The _result expressions_ of a switch expression are ...
It is a compile-time error if a switch expression has no result expressions.
[Design note: without at least one result expression, there's not a particularly good choice for the standalone type of the expression. It could still work as a poly expression, but for consistency it's probably better to reject the expression in all contexts.]
Where a poly switch expression appears in a context of a particular kind with target type _T_, its result expressions similarly appear in a context of the same kind with target type _T_.
A poly switch expression is compatible with a target type _T_ if each of its result expressions is compatible with _T_.
The type of a poly switch expression is the same as its target type.
The type of a standalone switch expression is determined as follows:
- If the result expressions all have the same type (which may be the null type), then that is the type of the switch expression.
- Otherwise, if the type of each result expression is `boolean` or `Boolean`, unboxing conversion ([5.1.8]) is applied to each result expression of type `Boolean`, and the switch expression has type `boolean`.
- Otherwise, if the type of each result expression is convertible to a numeric type ([5.1.8]), the type of the switch expression is given by conditional numeric promotion ([5.6.3]) applied to the result expressions.
- Otherwise, boxing conversion ([5.1.7]) is applied to each result expression that has a primitive type, after which the type of the switch expression is the least upper bound ([4.10.4]) of the types of the result expressions.
5.6.3 Conditional numeric promotion
[Design note: this introduces a new n-ary variety of numeric promotion. The rules for conditional expression typing would be revised to refer to it. I'm not sure what to call it, don't love this name but it's what I've come up with for now.
Another approach—more invasive but perhaps cleaner—would be to use this for _all_ numeric promotions, and ask clients to specify if they want `int` as a "minimum type" (as is the case for all primitive operators).]
When a conditional expression or switch expression applies conditional numeric promotion to a set of result expressions, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order:
- If any result expression is of a reference type, it is subjected to unboxing conversion.
- Widening primitive conversion and narrowing primitive conversion are applied to some result expressions as specified by the follow rules:
- If any result expression is of type double, the others are widened, as necessary, to double.
- Otherwise, if any result expression is of type float, the others are widened, as necessary, to float.
- Otherwise, if any result expression is of type long, the others are widened, as necessary, to long.
- Otherwise, if any result expression is of type int and is not a constant expression, the others are widened, as necessary, to int.
- Otherwise, if any result expression is of type char, and every other result expression is either of type char, or of type byte, or a constant expression of type int with a value that is representable in the type char, then the byte results are widened to char and the int results are narrowed to char.
- Otherwise, if any result expression is of type short, and every other result expression is either of type short, or of type byte, or a constant expression of type int with a value that is representable in the type short, then the byte results are widened to short and the int results are narrowed to short.
- Otherwise, if any result expression is of type byte, and every other result expression is either of type byte or a constant expression of type int with a value that is representable in the type byte, then the int results are narrowed to byte.
- Otherwise, all the results are widened, as necessary, to int.
After the conversion(s), if any, value set conversion ([5.1.13]) is then applied to each operand.
More information about the amber-spec-observers