Skip to content

Commit c8a9923

Browse files
RexJaeschkeBillWagnergafterNigel-Ecmajnm2
authored
Add support for new pattern kinds (dotnet#873)
* add new implicit conversion * add support for new pattern kinds * add support for new pattern kinds * add support for new pattern kinds * fix new grammar rule * separate consecutive block quotes * separate note and example * use correct grammar rule name * fix example annotation formatting * fix md formatting * Update patterns.md * fix links * Addressed most comments in the patterns PR. * Change "governing expression" to *selector_expression* * Apply suggestions from code review Commit agreed suggestions Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com> Co-authored-by: Bill Wagner <wiwagn@microsoft.com> * Apply suggestions from code review Agreed Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com> * Update standard/expressions.md Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com> * Update standard/patterns.md Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com> * Update standard/patterns.md Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com> * Update standard/patterns.md Co-authored-by: Joseph Musser <me@jnm2.com> * Update standard/patterns.md Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com> * Update standard/patterns.md Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com> * Update standard/statements.md Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com> * Fix grammar with discard. * Fix bullet indentation. * Remove unnecessary paragraph. * Fix markdown lint * Update standard/patterns.md * Update standard/expressions.md * Update standard/expressions.md * remove old tarball * add new tarball * Update necessary samples. --------- Co-authored-by: Bill Wagner <wiwagn@microsoft.com> Co-authored-by: Neal Gafter <neal@gafter.com> Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com> Co-authored-by: Joseph Musser <me@jnm2.com>
1 parent 6426065 commit c8a9923

36 files changed

Lines changed: 20897 additions & 20466 deletions
51 Bytes
Binary file not shown.

standard/conversions.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,10 @@ An implicit conversion exists from a *default_literal* ([§12.8.21](expressions.
380380
381381
While throw expressions do not have a type, they may be implicitly converted to any type.
382382
383+
### §switch-expression-conversion Switch expression conversion
384+
385+
There is an implicit conversion from a *switch_expression* (§switch-expression-new-clause) to every type `T` for which there exists an implicit conversion from each *switch_expression_arm*'s *switch_expression_arm_expression*'s to `T`.
386+
383387
## 10.3 Explicit conversions
384388
385389
### 10.3.1 General

standard/expressions.md

Lines changed: 97 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,9 @@ The precedence of an operator is established by the definition of its associated
148148
> | **Subclause** | **Category** | **Operators** |
149149
> | ----------------- | ------------------------------- | -------------------------------------------------------|
150150
> | [§12.8](expressions.md#128-primary-expressions) | Primary | `x.y` `x?.y` `f(x)` `a[x]` `a?[x]` `x++` `x--` `x!` `new` `typeof` `default` `checked` `unchecked` `delegate` `stackalloc` |
151-
> | [§12.9](expressions.md#129-unary-operators) | Unary | `+` `-` `!x` `~` `^` `++x` `--x` `(T)x` `await x` |
151+
> | [§12.9](expressions.md#129-unary-operators) | Unary | `+` `-` `!` `~` `^` `++x` `--x` `(T)x` `await x` |
152152
> | [§12.10](expressions.md#1210-range-operator) | Range | `..` |
153+
> | §switch-expression-new-clause | Switch | `switch { … }` |
153154
> | [§12.11](expressions.md#1211-arithmetic-operators) | Multiplicative | `*` `/` `%` |
154155
> | [§12.11](expressions.md#1211-arithmetic-operators) | Additive | `+` `-` |
155156
> | [§12.12](expressions.md#1212-shift-operators) | Shift | `<<` `>>` |
@@ -162,7 +163,7 @@ The precedence of an operator is established by the definition of its associated
162163
> | [§12.15](expressions.md#1215-conditional-logical-operators) | Conditional OR | `\|\|` |
163164
> | [§12.16](expressions.md#1216-the-null-coalescing-operator) and12.17](expressions.md#1217-the-throw-expression-operator) | Null coalescing and throw expression | `??` `throw x` |
164165
> |12.19](expressions.md#1219-conditional-operator) | Conditional | `?:` |
165-
> | [§12.22](expressions.md#1222-assignment-operators) and [§12.20](expressions.md#1220-anonymous-function-expressions) | Assignment and lambda expression | `=` `= ref` `*=` `/=` `%=` `+=` `-=` `<<=` `>>=` `&=` `^=` `\|=` `=>` `??=` |
166+
> |12.22](expressions.md#1222-assignment-operators) and12.20](expressions.md#1220-anonymous-function-expressions) | Assignment and lambda expression | `=` `= ref` `*=` `/=` `%=` `+=` `-=` `<<=` `>>=` `&=` `^=` `\|=` `=>` `??=` |
166167
>
167168
> *end note*
168169
@@ -3875,6 +3876,74 @@ A lifted ([§12.4.8](expressions.md#1248-lifted-operators)) form of the range op
38753876

38763877
The range operator is non-associative ([§12.4.2](expressions.md#1242-operator-precedence-and-associativity)).
38773878

3879+
## §switch-expression-new-clause Switch expression
3880+
3881+
A *switch_expression* provides `switch`-like semantics in an expression context.
3882+
3883+
```ANTLR
3884+
switch_expression
3885+
: range_expression
3886+
| switch_expression 'switch' '{' switch_expression_arms? '}'
3887+
;
3888+
3889+
switch_expression_arms
3890+
: switch_expression_arm (',' switch_expression_arm)* ','?
3891+
;
3892+
3893+
switch_expression_arm
3894+
: pattern case_guard? '=>' switch_expression_arm_expression
3895+
;
3896+
3897+
switch_expression_arm_expression
3898+
: expression
3899+
;
3900+
```
3901+
3902+
There is a *switch expression conversion* (§switch-expression-conversion) from a switch expression to a type `T`
3903+
if there is an implicit conversion from every *switch_expression_arm_expression* of each of the switch expression's *switch_expression_arm*s to `T`.
3904+
3905+
If a switch expression is not subject to a *switch expression conversion*, then
3906+
3907+
- The type of the *switch_expression* is the best common type [§12.6.3.16](expressions.md#126316-finding-the-best-common-type-of-a-set-of-expressions)) of the *switch_expression_arm_expression*s of the *switch_expression_arm*s, if such a type exists, and each *switch_expression_arm_expression* can be implicitly converted to that type.
3908+
- It is an error if no such type exists.
3909+
3910+
It is an error if some *switch_expression_arm*'s pattern cannot affect the result because some previous pattern and guard will always match.
3911+
3912+
A switch expression is said to be *exhaustive* if every value of its input is handled by at least one arm of the switch expression. The compiler shall produce a warning if a switch expression is not exhaustive.
3913+
At runtime, the result of the *switch_expression* is the value of the *expression* of the first *switch_expression_arm* for which the expression on the left-hand-side of the *switch_expression* matches the *switch_expression_arm*'s pattern, and for which the *case_guard* of the *switch_expression_arm*, if present, evaluates to `true`. If there is no such *switch_expression_arm*, the *switch_expression* throws an instance of the exception `System.Runtime.CompilerServices.SwitchExpressionException`.
3914+
3915+
> *Example*: The following converts values of an enum representing visual directions on an online map to the corresponding cardinal directions:
3916+
>
3917+
> <!-- Example: {template:"code-in-class-lib", name:"SwitchExpression1", ignoredWarnings:["CS8321"]} -->
3918+
> ```csharp
3919+
> static Orientation ToOrientation(Direction direction) => direction switch
3920+
> {
3921+
> Direction.Up => Orientation.North,
3922+
> Direction.Right => Orientation.East,
3923+
> Direction.Down => Orientation.South,
3924+
> Direction.Left => Orientation.West,
3925+
> _ => throw new ArgumentOutOfRangeException(direction.ToString()),
3926+
> };
3927+
>
3928+
> public enum Direction
3929+
> {
3930+
> Up,
3931+
> Down,
3932+
> Right,
3933+
> Left
3934+
> }
3935+
>
3936+
> public enum Orientation
3937+
> {
3938+
> North,
3939+
> South,
3940+
> East,
3941+
> West
3942+
> }
3943+
> ```
3944+
>
3945+
> *end example*
3946+
38783947
## 12.11 Arithmetic operators
38793948
38803949
### 12.11.1 General
@@ -3883,10 +3952,10 @@ The `*`, `/`, `%`, `+`, and `-` operators are called the arithmetic operators.
38833952
38843953
```ANTLR
38853954
multiplicative_expression
3886-
: range_expression
3887-
| multiplicative_expression '*' range_expression
3888-
| multiplicative_expression '/' range_expression
3889-
| multiplicative_expression '%' range_expression
3955+
: switch_expression
3956+
| multiplicative_expression '*' switch_expression
3957+
| multiplicative_expression '/' switch_expression
3958+
| multiplicative_expression '%' switch_expression
38903959
;
38913960
38923961
additive_expression
@@ -4346,7 +4415,12 @@ equality_expression
43464415
;
43474416
```
43484417

4349-
> *Note*: Lookup for the right operand of the `is` operator must first test as a *type*, then as an *expression* which may span multiple tokens. In the case where the operand is an *expression*, the pattern expression must have precedence at least as high as *shift_expression*. *end note*
4418+
> *Note*: Lookup for the right operand of the `is` operator must first test as a *type*, then as an *expression* which may span multiple tokens. In the case where the operand is an *expression*, the pattern expression must have precedence at least as high as *shift_expression*. *end note*
4419+
4420+
<!-- markdownlint-disable MD028 -->
4421+
4422+
<!-- markdownlint-enable MD028 -->
4423+
> *Note*: There is a grammar ambiguity between *type* and *constant_pattern* in a `relational_expression` on the right-hand-side of `is`; either might be a valid parse of a qualified identifier. In such a case, only if it fails to bind as a type (for compatibility with previous versions of the language), is it resolved to be the first thing found (which must be either a constant or a type). This ambiguity is only present on the right-hand side of such an expression.
43504424
43514425
The `is` operator is described in [§12.13.12](expressions.md#121312-the-is-operator) and the `as` operator is described in [§12.13.13](expressions.md#121313-the-as-operator).
43524426

@@ -4713,24 +4787,24 @@ There are two forms of the `is` operator. One is the *is-type operator*, which h
47134787

47144788
The *is-type operator* is used to check if the run-time type of an object is compatible with a given type. The check is performed at runtime. The result of the operation `E is T`, where `E` is an expression and `T` is a type other than `dynamic`, is a Boolean value indicating whether `E` is non-null and can successfully be converted to type `T` by a reference conversion, a boxing conversion, an unboxing conversion, a wrapping conversion, or an unwrapping conversion.
47154789

4716-
The operation is evaluated as follows:
4790+
The operation `E is T` is evaluated as follows:
47174791

47184792
1. If `E` is an anonymous function or method group, a compile-time error occurs.
4793+
1. If `T` is a nullable reference type ([§8.9.3](types.md#893-nullable-reference-types)), a compile-time error occurs.
47194794
1. If `E` is the `null` literal, or if the value of `E` is `null`, the result is `false`.
47204795
1. Otherwise:
4721-
1. Let `R` be the runtime type of `E`.
4722-
1. Let `D` be derived from `R` as follows:
4723-
1. If `R` is a nullable value type, `D` is the underlying type of `R`.
4724-
1. Otherwise, `D` is `R`.
4725-
1. The result depends on `D` and `T` as follows:
4726-
1. If `T` is a reference type, the result is `true` if:
4727-
- an identity conversion exists between `D` and `T`,
4728-
- `D` is a reference type and an implicit reference conversion from `D` to `T` exists, or
4729-
- Either: `D` is a value type and a boxing conversion from `D` to `T` exists.
4730-
Or: `D` is a value type and `T` is an interface type implemented by `D`.
4731-
1. If `T` is a nullable value type, the result is `true` if `D` is the underlying type of `T`.
4732-
1. If `T` is a non-nullable value type, the result is `true` if `D` and `T` are the same type.
4733-
1. Otherwise, the result is `false`.
4796+
1. Let `R` be the runtime type of `E`.
4797+
1. Let `D` be derived from `R` as follows:
4798+
1. If `R` is a nullable value type, `D` is the underlying type of `R`.
4799+
1. Otherwise, `D` is `R`.
4800+
1. The result depends on `D` and `T` as follows:
4801+
1. If `T` is a reference type, the result is `true` if:
4802+
- an identity conversion exists between `D` and `T`, or
4803+
- `D` is a reference type and an implicit reference conversion from `D` to `T` exists, or
4804+
- `D` is a value type and a boxing conversion from `D` to `T` exists.
4805+
1. If `T` is a nullable value type, the result is `true` if `D` is the underlying type of `T`.
4806+
1. If `T` is a non-nullable value type, the result is `true` if `D` and `T` are the same type.
4807+
1. Otherwise, the result is `false`.
47344808

47354809
User defined conversions are not considered by the `is` operator.
47364810

@@ -4758,6 +4832,8 @@ For an expression of the form `E is P`, where `E` is a relational expression of
47584832
- `E` does not designate a value or does not have a type.
47594833
- The pattern `P` is not applicable ([§11.2](patterns.md#112-pattern-forms)) to the type `T`.
47604834

4835+
Every *single_variable_designation* of the pattern introduces a new local variable that is *definitely assigned* ([§9.4](variables.md#94-definite-assignment)) when the corresponding *relational_expression* tests `true`.
4836+
47614837
### 12.13.13 The as operator
47624838

47634839
The `as` operator is used to explicitly convert a value to a given reference type or nullable value type. Unlike a cast expression ([§12.9.8](expressions.md#1298-cast-expressions)), the `as` operator never throws an exception. Instead, if the indicated conversion is not possible, the resulting value is `null`.

standard/lexical-structure.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,11 @@ The rules for identifiers given in this subclause correspond exactly to those re
423423
identifier
424424
: Simple_Identifier
425425
| contextual_keyword
426+
| discard_token
427+
;
428+
429+
discard_token
430+
: '_'
426431
;
427432
428433
Simple_Identifier

0 commit comments

Comments
 (0)