Skip to content

Commit

Permalink
update spec for #1119 and rework the whole section on switch/case/else
Browse files Browse the repository at this point in the history
  • Loading branch information
gavinking committed Nov 20, 2014
1 parent aef6afe commit c1c40fc
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 111 deletions.
6 changes: 3 additions & 3 deletions en/modules/expressions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1454,7 +1454,7 @@ Digit{1,2} ":" Digit{2} ( ":" Digit{2} ( ":" Digit{3} )? )?
<literal>switch</literal> expression, a list of <literal>case</literal>
expressions, and, optionally, an <literal>else</literal> expression.</para>

<synopsis>SwitchCaseElseExpression: "switch" "(" Expression ")" CaseExpression ElseExpression</synopsis>
<synopsis>SwitchCaseElseExpression: Switch CaseExpression+ ElseExpression</synopsis>

<para>The type of an <literal>if/then/else</literal> expression with
<literal>case</literal> expressions of type <literal>X1</literal>,
Expand All @@ -1464,7 +1464,7 @@ Digit{1,2} ":" Digit{2} ( ":" Digit{2} ( ":" Digit{3} )? )?

<synopsis>ThenExpression: "then" Expression</synopsis>
<synopsis>ElseExpression: "else" Expression</synopsis>
<synopsis>CaseExpression: "case" "(" Case ")" Expression</synopsis>
<synopsis>CaseExpression: "case" CaseCondition Expression</synopsis>

<para>The expression following <literal>then</literal>,
<literal>else</literal>, and <literal>case</literal> is parsed with
Expand All @@ -1474,7 +1474,7 @@ Digit{1,2} ":" Digit{2} ( ":" Digit{2} ( ":" Digit{3} )? )?
<xref linkend="operatorprecedence"/>.</para>

<para>Each <literal>case</literal> expression includes a value case or
type case, as defined in <xref linkend="switchcaseelse"/>. Just like
type case, as defined in <xref linkend="caseconditions"/>. Just like
in a <literal>switch/case/else</literal> conditional statement:</para>

<itemizedlist>
Expand Down
221 changes: 113 additions & 108 deletions en/modules/statementblocks.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1888,62 +1888,83 @@ if (is Usable tx) { ... }</programlisting>
</itemizedlist>

</section>

<!--section id="subtypeconditions">
<title>Subtype conditions</title>
<para>A subtype condition specifies a <emphasis>specified type</emphasis> (first) and a
<emphasis>given type</emphasis> (second).</para>
<synopsis>SatisfiesCondition: "satisfies" Type Type</synopsis>
<para>The given type will be treated by the compiler as a subtype of the specified type
inside the block that immediately follows the condition.</para>
<para>The condition is satisfied if the given type is a subtype of the specified type when
the control structure containing the condition is executed.</para>

</section-->

<!--section id="exhaustivecaselists">
<title>Exhaustive lists of cases</title>
<para>A <literal>switch</literal> statement may be <emphasis>exhaustive</emphasis>.
To determine if a <literal>switch</literal> is exhaustive, we consider the
<emphasis>exhaustive list of cases</emphasis> of the <literal>switch</literal>
expression type.</para>
<section id="caseconditions">
<title>Case conditions</title>

<para>The <emphasis>exhaustive list of cases of an enumerated type</emphasis>
<literal>T</literal> comprises the following types:</para>
<para>The branches of a <literal>switch</literal> conditional each belong to a
<emphasis>case condition</emphasis>. There are two kinds of case condition:</para>

<itemizedlist>
<listitem>
<para>every case of <literal>T</literal> which is an anonymous class, and</para>
</listitem>
<listitem>
<para>every case of <literal>T</literal> which is not itself an enumerated
type, together with</para>
<para>a <emphasis>value case</emphasis>&mdash;a list of string literals,
character literals, integer literals, negated integer literals, and/or
value references to anonymous classes, or</para>
</listitem>
<listitem>
<para>the exhaustive list of cases of every case of <literal>T</literal>
which is itself an enumerated type.</para>
<para>a <emphasis>type case</emphasis>&mdash;an assignability condition
of form <literal>is V</literal> for some type <literal>V</literal>.</para>
</listitem>
</itemizedlist>

<para>The <emphasis>exhaustive list of cases of a union type</emphasis>
<literal>T|U|V|...</literal> comprises the following types:</para>
<synopsis>CaseCondition: "(" (ValueCase | TypeCase) ")"</synopsis>
<synopsis>ValueCase: CaseValue ("|" CaseValue)*</synopsis>
<synopsis>TypeCase: "is" Type</synopsis>
<synopsis>CaseValue: LiteralCase | BaseExpression</synopsis>
<synopsis>LiteralCase: "-"? IntegerLiteral | CharacterLiteral | StringLiteral | VerbatimStringLiteral</synopsis>

<para>Every case condition has a type:</para>

<itemizedlist>
<listitem>
<para>every type belonging to the union which is not an enumerated type,
together with</para>
<para>for a value case, the type is the union of the types of the values,
and</para>
</listitem>
<listitem>
<para>the exhaustive list of cases of every type belonging to the union
which is an enumerated type.</para>
<para>for a type case, the type is the specified type.</para>
</listitem>
</itemizedlist>

<para>The type of every case condition must be a subtype of the
switched type, as defined below in <xref linkend="switchcaseelse"/>.</para>

<para>For a value case, each value reference must be to an anonymous class that
is a subtype of <literal>Identifiable|Null</literal>.</para>

<para>For a type case of type <literal>U</literal>, and a switched type
<literal>V</literal>, the intersection type <literal>V&amp;U</literal> must not
be exactly <literal>Nothing</literal>. Then the <literal>switch</literal>
variable or, if there is no inline variable declared by the <literal>switch</literal>,
the value referred by the <literal>switch</literal> expression, will be treated
by the compiler as having the type <literal>V&amp;U</literal> inside the
<literal>case</literal> block.</para>

<para>As a special exception to the above, if a <literal>switch</literal> occurs
in a <literal>dynamic</literal> block, and there is no switched type, the
<literal>switch</literal> variable, or the value referred by the
<literal>switch</literal> expression will be treated by the compiler as having
the type <literal>V</literal> inside the <literal>case</literal> block.</para>

<comment><para>Note: a type case may narrow to an intersection or union type.</para>
<programlisting>case (is Persistent &amp; Serializable) { ... }</programlisting>
<programlisting>case (is Integer | Float) { ... }</programlisting></comment>

</section>

<!--section id="subtypeconditions">
<title>Subtype conditions</title>
<para>A subtype condition specifies a <emphasis>specified type</emphasis> (first) and a
<emphasis>given type</emphasis> (second).</para>
<synopsis>SatisfiesCondition: "satisfies" Type Type</synopsis>
<para>The given type will be treated by the compiler as a subtype of the specified type
inside the block that immediately follows the condition.</para>
<para>The condition is satisfied if the given type is a subtype of the specified type when
the control structure containing the condition is executed.</para>
</section-->

<section id="ifelse">
Expand Down Expand Up @@ -2000,112 +2021,94 @@ else {
<para>The <literal>switch/case/else</literal> conditional has the following
form:</para>

<synopsis>SwitchCaseElse: Switch Cases</synopsis>

<synopsis>Switch: "switch" "(" Expression ")"</synopsis>

<synopsis>Cases: CaseItem+ DefaultCaseItem?</synopsis>
<synopsis>SwitchCaseElse: Switch Case+ DefaultCase?</synopsis>

<synopsis>CaseItem: "case" "(" Case ")" Block</synopsis>
<para>Every <literal>switch</literal> conditional has a
<literal>switch</literal> clause.</para>

<synopsis>DefaultCaseItem: "else" Block</synopsis>
<synopsis>Switch: "switch" "(" SwitchVariableOrExpression ")"</synopsis>

<para>Every <literal>switch</literal> conditional construct has a
<literal>switch</literal> clause. The construct must include:</para>
<para>The <literal>switch</literal> clause has either:</para>

<itemizedlist>
<listitem>
<para>a chain of an arbitrary number of child
<literal>case</literal> clauses, and/or</para>
<para>an expression, or</para>
</listitem>
<listitem>
<para>an <literal>else</literal> clause.</para>
<para>an inline variable declaration together with a specified
expression.</para>
</listitem>
</itemizedlist>

<para>Each <literal>case</literal> is either:</para>
<synopsis>SwitchVariableOrExpression: Expression | Variable Specifier</synopsis>

<para>The <emphasis>switched type</emphasis> is the type of the expression
or inline variable.</para>

<para>If a <literal>switch</literal> has a type case condition, and does not
declare an inline variable, then the <literal>switch</literal> expression must
be an unqualified value reference to a non-<literal>variable</literal>,
non-<literal>default</literal> reference.</para>

<para>In addition, every <literal>switch</literal> conditional must include:</para>

<itemizedlist>
<listitem>
<para>a <emphasis>value case</emphasis>&mdash;a list of string literals,
character literals, integer literals, negated integer literals, and/or
value references to anonymous classes, or</para>
<para>a chain of one or more child <literal>case</literal> clauses,
and,</para>
</listitem>
<listitem>
<para>a <emphasis>type case</emphasis>&mdash;an assignability condition
of form <literal>is V</literal> for some type <literal>V</literal>.</para>
<para>optionally, an <literal>else</literal> clause.</para>
</listitem>
</itemizedlist>

<synopsis>Case: CaseValue ("|" CaseValue)* | "is" Type</synopsis>
<synopsis>CaseValue: LiteralCase | BaseExpression</synopsis>
<synopsis>LiteralCase: "-"? IntegerLiteral | CharacterLiteral | StringLiteral | VerbatimStringLiteral</synopsis>
<synopsis>Case: "case" CaseCondition Block</synopsis>

<synopsis>DefaultCase: "else" Block</synopsis>

<para>Every <literal>case</literal> has a type:</para>
<para>Two <literal>case</literal>s are said to be <emphasis>disjoint</emphasis>
if:</para>

<itemizedlist>
<listitem>
<para>for a value case, the type is the union of the types of the values,
and</para>
<para>the intersection of the types of their case conditions is
exactly <literal>Nothing</literal>, as defined by
<xref linkend="disjointtypes"/>, or</para>
</listitem>
<listitem>
<para>for a type case, the type is the specified type.</para>
<para>if they are both value cases with no literal value or
anonymous class value reference in common.</para>
</listitem>
</itemizedlist>

<para>The type of a case must be a subtype of the <literal>switch</literal>
expression type.</para>

<para>For a value case, each value reference must be to an anonymous class that
is a subtype of <literal>Identifiable|Null</literal>.</para>

<para>For a type case of type <literal>V</literal>, the intersection type
<literal>V&amp;U</literal> must not be exactly <literal>Nothing</literal>.</para>

<para>Two <literal>case</literal>s are said to be <emphasis>disjoint</emphasis>
if the intersection of their types is exactly <literal>Nothing</literal>, as
defined by <xref linkend="disjointtypes"/>, or if they are both value cases with
distinct literal values. In every <literal>switch</literal> statement, all
<literal>case</literal>s must be mutually disjoint.</para>

<para>In every <literal>switch</literal> statement, all <literal>case</literal>s
must be mutually disjoint.</para>

<para>If an <literal>else</literal> block is specified, then the <literal>switch</literal>
variable or, if there is no inline variable declared by the <literal>switch</literal>,
the value referred by the <literal>switch</literal> expression, will be treated
by the compiler as having the type <literal>V~U</literal> inside the
<literal>case</literal> block, where <literal>V</literal> is the switched type,
and <literal>U</literal> is the union type formed by the types of the case
conditions of the <literal>switch</literal>.</para>

<para>A <literal>switch</literal> is <emphasis>exhaustive</emphasis> if there
are no literal values in its <literal>case</literal>s, and the union type formed
by the types of the <literal>case</literal>s of the <literal>switch</literal>
covers the <literal>switch</literal> expression type, as defined by
<xref linkend="coverage"/>.</para>
by the types of the case conditions of the <literal>switch</literal>
covers the switched type, as defined by <xref linkend="coverage"/>.</para>

<para>If no <literal>else</literal> block is specified, the <literal>switch</literal>
must be exhaustive.</para>

<comment><para>Note: On the other hand, even if the <literal>switch</literal>
<emphasis>is</emphasis> exhaustive, an <literal>else</literal> block may be
specified, in order to allow a <literal>switch</literal> that accommodates additional
cases without resulting in a compilation error.</para></comment>
specified, in order to allow a <literal>switch</literal> that accommodates
additional cases without resulting in a compilation error.</para></comment>

<para>As a special exception to the above, if a <literal>switch</literal> occurs in
a <literal>dynamic</literal> block, and the <literal>switch</literal> expression
<para>As a special exception to the above, if a <literal>switch</literal> occurs
in a <literal>dynamic</literal> block, and the <literal>switch</literal> expression
has no type, the cases are not statically type-checked for exhaustion.</para>

<comment><para>Note: an assignability condition <literal>case</literal> may narrow to
an intersection or union type.</para>
<programlisting>case (is Persistent &amp; Serializable) { ... }</programlisting>
<programlisting>case (is Integer | Float) { ... }</programlisting></comment>

<para>If a <literal>switch</literal> has an assignability condition <literal>case</literal>,
then the <literal>switch</literal> expression must be an unqualified value reference
to a non-<literal>variable</literal>, non-<literal>default</literal> reference.</para>

<para>For an assignability condition <literal>case</literal>, the value referred by the
<literal>switch</literal> expression will be treated by the compiler as having the
intersection type of its declared type with the specified type inside the <literal>case</literal>
block. This intersection type must not be exactly <literal>Nothing</literal>.</para>

<para>As a special exception to the above, if a <literal>switch</literal> occurs in
a <literal>dynamic</literal> block, and the <literal>switch</literal> expression
has no type, the value referred by the <literal>switch</literal> expression will be
treated by the compiler as having the the specified type inside the <literal>case</literal>
block.</para>

<programlisting>Boolean? maybe = ... ;
switch (maybe)
case (null | false) {
Expand All @@ -2124,7 +2127,7 @@ case (is Float) {
return sqrt(number);
}</programlisting>

<para>A Java-style overloaded method may be emulated as follows:</para>
<!--para>A Java-style overloaded method may be emulated as follows:</para>
<programlisting>shared void print&lt;Printable&gt;(Printable printable)
given Printable of String | Integer | Float {
Expand All @@ -2138,7 +2141,7 @@ case (is Float) {
case (is Float) {
print(formatFloat(printable, 2));
}
}</programlisting>
}</programlisting-->

<!--para>Or, even better:</para>
Expand Down Expand Up @@ -2256,7 +2259,9 @@ while (n&lt;=max) {

<synopsis>TryCatchFinally: Try Catch* Finally?</synopsis>

<synopsis>Try: "try" ("(" Resource ("," Resource) ")")? Block</synopsis>
<synopsis>Try: "try" ResourceList? Block</synopsis>

<synopsis>ResourceList: "(" Resource ("," Resource) ")"</synopsis>

<synopsis>Catch: "catch" "(" Variable ")" Block</synopsis>

Expand Down

0 comments on commit c1c40fc

Please sign in to comment.