-
Notifications
You must be signed in to change notification settings - Fork 95
Dealing with var, parts 1 and 2 #1696
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: draft-v8
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -62,6 +62,61 @@ Each pattern form defines the set of values for which the pattern *matches* the | |
|
|
||
| The order of evaluation of operations and side effects during pattern-matching (calls to `Deconstruct`, property accesses, and invocations of methods in `System.ITuple`) is not specified. | ||
|
|
||
| The *identifier* `var` appearing in any *pattern* is bound using the normal identifier-resolution rules. The *identifier* `var` may appear in patterns only where the entity to which it resolves is valid in that position. When no declaration of the *identifier* `var` is in scope, the form `var` *designation* is recognised as a *var_pattern* ([§11.2.4](patterns.md#1124-var-pattern)); when any declaration of the *identifier* `var` is in scope, a *var_pattern* cannot be used. The verbatim identifier `@var` and Unicode-escaped equivalents are distinct identifiers from the contextual keyword `var` and are bound and used in patterns according to the entities they denote, like any other identifier. | ||
|
|
||
| > *Note*: When a declaration of the *identifier* `var` is in scope, the consequences of the rule above are: | ||
| > | ||
| > - If `var` denotes a type, then `var` may be the *type* of a *declaration_pattern* ([§11.2.2](patterns.md#1122-declaration-pattern)). | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this is incorrect, once If Or something like that! [*] This is testing for v8, for v9 |
||
| > - If `var` denotes a constant, then `var` may be the *constant_expression* of a *constant_pattern* ([§11.2.3](patterns.md#1123-constant-pattern)). | ||
| > - Otherwise (for example, when `var` denotes a field, property, local variable, parameter, or any other entity that is neither a type nor a constant), `var` is not valid in pattern position. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure what "in pattern position" means here. (I suspect just adding a couple of words will be fine.)
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whatever we decide to do, we should apply to line 191 as well.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jskeet – I think the intention is “is not valid as the first token of a pattern” |
||
| > | ||
| > *end note* | ||
|
|
||
| ### 11.2.3 Constant pattern | ||
|
jskeet marked this conversation as resolved.
|
||
|
|
||
| A *constant_pattern* is used to test the value of a pattern input value ([§11.1](patterns.md#111-general)) against the given constant value. | ||
|
|
||
| ```ANTLR | ||
| constant_pattern | ||
| : constant_expression | ||
| ; | ||
| ``` | ||
|
|
||
| When a declaration of the *identifier* `var` in scope resolves to a constant, `var` may appear as the *constant_expression* of a *constant_pattern*; the general rule for the *identifier* `var` in patterns is specified in [§11.2.1](patterns.md#1121-general). | ||
|
|
||
| A constant pattern `P` is *applicable to* a type `T` if there is an implicit conversion from the constant expression of `P` to the type `T`. | ||
|
|
||
| For a constant pattern `P`, its *converted value* is | ||
|
|
||
| - if the pattern input value’s type is an integral type or an enum type, the pattern’s constant value converted to that type; otherwise | ||
| - if the pattern input value’s type is the nullable version of an integral type or an enum type, the pattern’s constant value converted to its underlying type; otherwise | ||
| - the value of the pattern’s constant value. | ||
|
|
||
| Given a pattern input value *e* and a constant pattern `P` with converted value *v*, | ||
|
|
||
| - if *e* has integral type or enum type, or a nullable form of one of those, and *v* has integral type, the pattern `P` *matches* the value *e* if result of the expression `e == v` is `true`; otherwise | ||
| - the pattern `P` *matches* the value *e* if `object.Equals(e, v)` returns `true`. | ||
|
|
||
| > *Example*: The `switch` statement in the following method uses five constant patterns in its case labels. | ||
| > | ||
| > <!-- Example: {template:"standalone-console", name:"ConstantPattern1", replaceEllipsis:true, customEllipsisReplacements: ["\"xxx\""], ignoredWarnings:["CS8321"]} --> | ||
| > ```csharp | ||
| > static decimal GetGroupTicketPrice(int visitorCount) | ||
| > { | ||
| > switch (visitorCount) | ||
| > { | ||
| > case 1: return 12.0m; | ||
| > case 2: return 20.0m; | ||
| > case 3: return 27.0m; | ||
| > case 4: return 32.0m; | ||
| > case 0: return 0.0m; | ||
| > default: throw new ArgumentException(...); | ||
| > } | ||
| > } | ||
| > ``` | ||
| > | ||
| > *end example* | ||
|
|
||
| ### 11.2.2 Declaration pattern | ||
|
|
||
| A *declaration_pattern* is used to test that a value has a given type and, if the test succeeds, to optionally provide the value in a variable of that type. | ||
|
|
@@ -84,6 +139,10 @@ single_variable_designation | |
|
|
||
| A *simple_designation* with the token `_` shall be considered a *discard_designation* rather than a *single_variable_designation*. | ||
|
|
||
| When a declaration of the *identifier* `var` in scope resolves to a type, `var` may appear as the *type* of a *declaration_pattern*; the general rule for the *identifier* `var` in patterns is specified in [§11.2.1](patterns.md#1121-general). | ||
|
|
||
| The *type* of a *declaration_pattern* cannot be `dynamic`, because the runtime type test is defined in terms of the is-type operator ([§12.14.12.1](expressions.md#1214121-the-is-type-operator)), which does not permit `dynamic`. | ||
|
|
||
| The runtime type of the value is tested against the *type* in the pattern using the same rules specified in the is-type operator ([§12.14.12.1](expressions.md#1214121-the-is-type-operator)). If the test succeeds, the pattern *matches* that value. It is a compile-time error if the *type* is a nullable value type ([§8.3.12](types.md#8312-nullable-value-types)) or a nullable reference type ([§8.9.3](types.md#893-nullable-reference-types)). This pattern form never matches a `null` value. | ||
|
|
||
| > *Note*: The is-type expression `e is T` and the declaration pattern `e is T _` are equivalent when `T` is not a nullable type. *end note* | ||
|
|
@@ -123,55 +182,14 @@ Certain combinations of static type of the pattern input value and the given typ | |
| > | ||
| > The condition of the `if` statement is `true` at runtime and the variable `v` holds the value `3` of type `int` inside the block. After the block the variable `v` is in scope, but not definitely assigned. *end example* | ||
|
|
||
| ### 11.2.3 Constant pattern | ||
|
|
||
| A *constant_pattern* is used to test the value of a pattern input value ([§11.1](patterns.md#111-general)) against the given constant value. | ||
|
|
||
| ```ANTLR | ||
| constant_pattern | ||
| : constant_expression | ||
| ; | ||
| ``` | ||
|
|
||
| A constant pattern `P` is *applicable to* a type `T` if there is an implicit conversion from the constant expression of `P` to the type `T`. | ||
|
|
||
| For a constant pattern `P`, its *converted value* is | ||
|
|
||
| - if the pattern input value’s type is an integral type or an enum type, the pattern’s constant value converted to that type; otherwise | ||
| - if the pattern input value’s type is the nullable version of an integral type or an enum type, the pattern’s constant value converted to its underlying type; otherwise | ||
| - the value of the pattern’s constant value. | ||
|
|
||
| Given a pattern input value *e* and a constant pattern `P` with converted value *v*, | ||
|
|
||
| - if *e* has integral type or enum type, or a nullable form of one of those, and *v* has integral type, the pattern `P` *matches* the value *e* if result of the expression `e == v` is `true`; otherwise | ||
| - the pattern `P` *matches* the value *e* if `object.Equals(e, v)` returns `true`. | ||
|
|
||
| > *Example*: The `switch` statement in the following method uses five constant patterns in its case labels. | ||
| > | ||
| > <!-- Example: {template:"standalone-console", name:"ConstantPattern1", replaceEllipsis:true, customEllipsisReplacements: ["\"xxx\""], ignoredWarnings:["CS8321"]} --> | ||
| > ```csharp | ||
| > static decimal GetGroupTicketPrice(int visitorCount) | ||
| > { | ||
| > switch (visitorCount) | ||
| > { | ||
| > case 1: return 12.0m; | ||
| > case 2: return 20.0m; | ||
| > case 3: return 27.0m; | ||
| > case 4: return 32.0m; | ||
| > case 0: return 0.0m; | ||
| > default: throw new ArgumentException(...); | ||
| > } | ||
| > } | ||
| > ``` | ||
| > | ||
| > *end example* | ||
|
|
||
| ### 11.2.4 Var pattern | ||
|
|
||
| A *var_pattern* *matches* every value. That is, a pattern-matching operation with a *var_pattern* always succeeds. | ||
|
|
||
| A *var_pattern* is *applicable to* every type. | ||
|
|
||
| A *var_pattern* cannot be used when any declaration of the *identifier* `var` is in scope. See [§11.2.1](patterns.md#1121-general) for the interpretation of `var` in pattern position in that case. | ||
|
|
||
| ```ANTLR | ||
| var_pattern | ||
| : 'var' designation | ||
|
|
@@ -190,8 +208,6 @@ designations | |
|
|
||
| Given a pattern input value ([§11.1](patterns.md#111-general)) *e*, if *designation* is *discard_designation*, it denotes a discard ([§9.2.9.2](variables.md#9292-discards)), and the value of *e* is not bound to anything. (Although a declared variable with that name may be in scope at that point, that named variable is not seen in this context.) Otherwise, if *designation* is *single_variable_designation*, at runtime the value of *e* is bound to a newly introduced local variable ([§9.2.9](variables.md#929-local-variables)) of that name whose type is the static type of *e*, and the pattern input value is assigned to that local variable. | ||
|
|
||
| It is an error if the name `var` would bind to a type where a *var_pattern* is used. | ||
|
|
||
| If *designation* is a *tuple_designation*, the pattern is equivalent to a *positional_pattern* ([§11.2.5](patterns.md#1125-positional-pattern)) of the form `(var` *designation*, … `)` where the *designation*s are those found within the *tuple_designation*. For example, the pattern `var (x, (y, z))` is equivalent to `(var x, (var y, var z))`. | ||
|
|
||
| ### 11.2.5 Positional pattern | ||
|
|
@@ -213,6 +229,16 @@ subpattern | |
|
|
||
| Given a match of an input value to the pattern *type* `(` *subpatterns* `)`, a method is selected by searching in *type* for accessible declarations of `Deconstruct` and selecting one among them using the same rules as for the deconstruction declaration. | ||
| It is an error if a *positional_pattern* omits the type, has a single *subpattern* without an *identifier*, has no *property_subpattern* and has no *simple_designation*. This disambiguates between a *constant_pattern* that is parenthesized and a *positional_pattern*. | ||
|
|
||
| > *Note*: A tuple literal can be matched by patterns of several different forms, which are not interchangeable: | ||
| > | ||
| > - `(int, int) x` is a *declaration_pattern* with type `(int, int)` and *simple_designation* `x`. | ||
| > - `var (x, y)` is a *var_pattern* with a *tuple_designation*. | ||
| > - `(int x, int y)` is a *positional_pattern*. | ||
| > - `(int, int) (x, y)` is not a valid pattern. | ||
| > | ||
| > *end note* | ||
|
|
||
| In order to extract the values to match against the patterns in the list, | ||
|
|
||
| - If *type* is omitted and the input expression’s type is a tuple type, then the number of subpatterns shall to be the same as the cardinality of the tuple. Each tuple element is matched against the corresponding *subpattern*, and the match succeeds if all of these succeed. If any *subpattern* has an *identifier*, then that shall name a tuple element at the corresponding position in the tuple type. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about the verbatim identifier part - that would suggest this should compile:
... but it doesn't. I think you're trying to say that using
@varin a pattern isn't equivalent to usingvar, but if that's the case, we should be more explicit about it.