You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Fix issues with Positional Patterns
Fixes#1647
Rewrite §11.2.5 Positional pattern in patterns.md so the three matching strategies and their priority order are unambiguous, and add System.Runtime.CompilerServices.ITuple to the standard library annex. Roslyn-verified: named subpatterns are rejected when matching goes through ITuple, so that prohibition stays in the spec.
I had to add the `System.Runtime.CompilerServices.ITuple` interface to Annex C.3. I followed the practice we agreed to in the last meeting to add `///` comments that describe the necessary semantics for the type.
* temporary fix to enable tools
* Remove link text
* Address feedback
1. **§11.2.5 intro** — Remove the `[§12.7](expressions.md#127-deconstruction)` link from the opening sentence. §12.7 defines deconstruction as a source-level transformation producing a tuple-literal; that model doesn't match pattern-matching's direct use of `Deconstruct`.
2. **Move disambiguation rule out of §11.2.5 into §11.2.1.** Delete the paragraph ("It is an error if a *positional_pattern* omits the *type*..."). Add a new paragraph immediately after the `pattern` grammar block, modeled on the deconstructing_assignment disambiguation — e.g. *"If the input can be syntactically recognised as both a `constant_pattern` (whose constant expression is parenthesized) and a `positional_pattern` with a single subpattern lacking an identifier, no property_subpattern, and no simple_designation, then the `constant_pattern` shall be chosen."*
3. **§11.2.5 bullet 2 (Deconstruct form)** — Rewrite to state explicitly: if *type* is present, search *type*; otherwise search the static type of the input value. Drop the second `§12.7` link. Break the long sentence into smaller ones.
4. **Clarify per-bullet error semantics** — Add a sentence before the numbered list stating that once a bullet's selection conditions are satisfied, that strategy is committed; any "compile-time error" inside that bullet is reported (no fall-through). Addresses "compile-time error means move to next bullet?" question. Rewrite each bullet for clarity on "this case applies"
* Apply suggestions from code review
Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com>
* respond to feedback from meeting
This should now be ready to merge.
---------
Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com>
Copy file name to clipboardExpand all lines: standard/patterns.md
+12-10Lines changed: 12 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -30,6 +30,8 @@ pattern
30
30
;
31
31
```
32
32
33
+
If the input can be syntactically recognised as both a *constant_pattern* and a *positional_pattern* then the *constant_pattern* shall be chosen.
34
+
33
35
Some *pattern*s can result in the declaration of a local variable.
34
36
35
37
Each pattern form defines the set of types for input values that the pattern may be applied to. A pattern `P` is *applicable to* a type `T` if `T` is among the types whose values the pattern may match. It is a compile-time error if a pattern `P` appears in a program to match a pattern input value ([§11.1](patterns.md#111-general)) of type `T` if `P` is not applicable to `T`.
@@ -60,7 +62,7 @@ Each pattern form defines the set of types for input values that the pattern may
60
62
61
63
Eachpatternformdefinesthesetofvaluesfor which the pattern *matches* the value at runtime.
62
64
63
-
The order of evaluation of operations and side effects during pattern-matching (callsto `Deconstruct`, propertyaccesses, andinvocationsofmethodsin `System.ITuple`) isnotspecified.
65
+
The order of evaluation of operations and side effects during pattern-matching (callsto `Deconstruct`, propertyaccesses, andinvocationsofmembersof `System.Runtime.CompilerServices.ITuple`) isnotspecified.
64
66
65
67
### 11.2.2 Declaration pattern
66
68
@@ -200,7 +202,9 @@ If *designation* is a *tuple_designation*, the pattern is equivalent to a *posit
200
202
201
203
### 11.2.5 Positional pattern
202
204
203
-
A *positional_pattern* checks that the input value is not `null`, invokes an appropriate `Deconstruct` method ([§12.7](expressions.md#127-deconstruction)), and performs further pattern matching on the resulting values. It also supports a tuple-like pattern syntax (without the type being provided) when the type of the input value is the same as the type containing `Deconstruct`, or if the type of the input value is a tuple type, or if the type of the input value is `object` or `System.ITuple` and the runtime type of the expression implements `System.ITuple`.
205
+
A *positional_pattern* checks that the input value is not `null`, extracts a sequence of values from it, and matches each extracted value against a corresponding *subpattern*. The values are extracted in one of three ways: by treating the input as a tuple, by invoking a `Deconstruct` method, or by indexing the input through `System.Runtime.CompilerServices.ITuple`.
206
+
207
+
> *Note*: The use of `Deconstruct` here is distinct from the source-level deconstruction transformation defined in [§12.7](expressions.md#127-deconstruction). *end note*
204
208
205
209
```ANTLR
206
210
positional_pattern
@@ -215,14 +219,12 @@ subpattern
215
219
;
216
220
```
217
221
218
-
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.
219
-
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*.
220
-
In order to extract the values to match against the patterns in the list,
222
+
Let *n* be the number of *subpattern*s appearing between the parentheses. The matching strategy is selected at compile time by applying the following cases in order; the first case whose conditions are satisfied is used, and the remaining cases are not considered. Once a case is selected, that strategy is committed: any compile-time error stated within that case is reported, and matching does not fall through to a subsequent case.
221
223
222
-
-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.
223
-
- Otherwise, if a suitable `Deconstruct` exists as a member of *type*, it is a compile-time error if the type of the input value is not pattern-compatible ([§11.2.2](patterns.md#1122-declaration-pattern)) with *type*. At runtime the input value is tested against *type*. If this fails, then the positional pattern match fails. If it succeeds, the input value, viewed as an expression of *type*, is deconstructed ([§12.7](expressions.md#127-deconstruction)) using that `Deconstruct`, and each element of the resulting tuple is matched against the corresponding *subpattern*. Each value that was received 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 parameter at the corresponding position of `Deconstruct`.
224
-
-Otherwise, if *type* is omitted, and the input value is of type `object`or some type that can be converted to `System.ITuple` by an implicit reference conversion, and no *identifier* appears among the subpatterns, then the match uses `System.ITuple`.
225
-
- Otherwise, the pattern is invalid and a compile-time error shall be issued.
224
+
1.**Tuple form.**If *type* is omitted and the static type of the input value is a tuple type ([§8.3.11](types.md#8311-tuple-types)) or if the input value is a tuple literal (§12.8.6), then this case applies. It is a compile-time error if *n* is not equal to the arity of that tuple type. At runtime, each tuple element is matched against the corresponding *subpattern*; the match succeeds if all of these succeed. If any *subpattern* has an *identifier*, that *identifier*shall name the tuple element at the corresponding position in the tuple type.
225
+
2. **Deconstruct form.** Otherwise, if either *type* is present, or *type* is omitted and the static type of the input value contains an accessible `Deconstruct` method (§12.7), then this case applies. Let *D* be *type* if *type* is present; otherwise let *D* be the static type of the input value. A `Deconstruct` method is selected from *D* using the same overload-resolution rules as for a deconstruction declaration, with the additional requirement that its number of `out` parameters is equal to *n*; it is a compile-time error if no such method exists. If *type* is present, it is a compile-time error if the static type of the input value is not pattern compatible (§11.2.2) with *type*; at runtime the input value is tested against *type* and, if that test fails, the positional pattern match fails. Otherwise, the input value is converted to *D* and the selected `Deconstruct` method is invoked with fresh variables receiving its `out` parameters. Each received value is matched against the corresponding *subpattern*, and the match succeeds if all of these succeed. If any *subpattern* has an *identifier*, that *identifier* shall name the parameter at the corresponding position of `Deconstruct`.
226
+
3.**ITuple form.**Otherwise, if *type* is omitted, no *subpattern* has an *identifier*, and the static type of the input value is `object`, `System.Runtime.CompilerServices.ITuple`, or a type that has an implicit reference conversion to `System.Runtime.CompilerServices.ITuple`, then this case applies. At runtime, the input value is tested for being a non-`null` instance of `System.Runtime.CompilerServices.ITuple`; if that test fails, the positional pattern match fails. Otherwise, the value's `Length` property is read and, if it is not equal to *n*, the positional pattern match fails. Otherwise, for each *i* from 1 to *n*, the value obtained by indexing the input value with *i* − 1 is matched against the *i*-th *subpattern*, and the match succeeds if all of these succeed.
227
+
4. Otherwise, no case applies and the *positional_pattern* is a compile-time error.
226
228
227
229
The order in which subpatterns are matched at runtime is unspecified, and a failed match might not attempt to match all subpatterns.
228
230
@@ -314,7 +316,7 @@ It is a compile-time error if the *type* is a nullable value type ([§8.3.12](ty
0 commit comments