-
Notifications
You must be signed in to change notification settings - Fork 92
Add support for new pattern kinds #873
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
Add support for new pattern kinds #873
Conversation
0d6dda3 to
237570c
Compare
|
Successfully rebased on the updated |
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.
I haven't managed to work my way through all of this yet but am submitting what I have so far. Overall this seems to have carried over too much non-Standardese from the original proposals and some issues repeating/rewording stuff already in the Standard.. There are also grammar issues that may break expression parsing…
| : switch_expression | ||
| | multiplicative_expression '*' switch_expression | ||
| | multiplicative_expression '/' switch_expression | ||
| | multiplicative_expression '%' switch_expression |
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.
Something has gone wrong here, see comment on line 3565 above
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.
This should be resolved if suggestions above are adopted.
|
|
||
| ### §positional-pattern-new-clause Positional pattern | ||
|
|
||
| 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`. |
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.
This feels like it is repeating stuff which is (or should be, e.g. System.ITuple is not in §12.7 at present) in §12.7 Deconstruction and this here should be something like:
A positional_pattern checks that the input value is not
null, performs a deconstruction (§12.7), and performs further pattern matching on the resulting values.
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 that ITuple should be mentioned in 12.7, as I think it's only used in positional patterns, not more general deconstruction. It's possible we should centralise its use within patterns though.
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.
Do we need to say what the compiler invokes on ITuple? (And we need it to be in the relevant annex.) Or just "in order for the pattern to match, the number of subpatterns in the positional pattern must be the same as the number of items in the ITuple, and (something about conversions)"?
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.
(My summary & thoughts post meeting)
The cases this covers:
- if the input value is a tuple type: the number of subpatterns must statically match the tuple arity, subpatterns & tuple elements are matched pairwise, order not specified, match can fail without checking all subpatterns.
- if the input value has a
Deconstructmethod whose number out parameters match the number of subpatterns, and the types of each parameter is compatible with the corresponding subpatterns matched pairwise then the values from invokingDeconstructare matched pairwise, order not specified, match can fail without checking all subpatterns. - if the input value implements
ITuplethen the number of elements in theITuplevalue is checked at runtime to be equal to the number of subpatterns. Then the elements of theITuplevalue are matched pairwise… etc.
I’ve listed these cases in the probable order of priority, i.e. if the input value is a tuple the first case is picked even though tuples implement ITuple (if that is added to the Standard) and Deconstruct (if that is added to the Standard); next if the type of the input value implements a suitable Deconstruct then case 2 is chosen; finally, if applicable, case 3 with dynamic arity check is chosen, and a compile time error occurs if it is not applicable.
Is this ordering correct, note it does not match the current text?
Whatever the ordering it needs to be clearly specified.
standard/patterns.md
Outdated
| ## 11.1 General | ||
|
|
||
| A ***pattern*** is a syntactic form that can be used with the `is` operator ([§12.12.12](expressions.md#121212-the-is-operator)) and in a *switch_statement* ([§13.8.3](statements.md#1383-the-switch-statement)) to express the shape of data against which incoming data is to be compared. A pattern is tested against the *expression* of a switch statement, or against a *relational_expression* that is on the left-hand side of an `is` operator, each of which is referred to as a ***pattern input value***. | ||
| A ***pattern*** is a syntactic form that can be used with the `is` operator ([§12.12.12](expressions.md#121212-the-is-operator)), in a *switch_statement* ([§13.8.3](statements.md#1383-the-switch-statement)), and in a *switch_expression* (§switch-expression-new-clause) to express the shape of data against which incoming data is to be compared. Patterns may be recursive, so that parts of the data may be matched against ***sub-patterns***. A pattern is tested against the *expression* of a switch statement, or against a *relational_expression* that is on the left-hand side of an `is` operator, each of which is referred to as a ***pattern input value***. |
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.
| A ***pattern*** is a syntactic form that can be used with the `is` operator ([§12.12.12](expressions.md#121212-the-is-operator)), in a *switch_statement* ([§13.8.3](statements.md#1383-the-switch-statement)), and in a *switch_expression* (§switch-expression-new-clause) to express the shape of data against which incoming data is to be compared. Patterns may be recursive, so that parts of the data may be matched against ***sub-patterns***. A pattern is tested against the *expression* of a switch statement, or against a *relational_expression* that is on the left-hand side of an `is` operator, each of which is referred to as a ***pattern input value***. | |
| A ***pattern*** is a syntactic form that can be used with the `is` operator ([§12.12.12](expressions.md#121212-the-is-operator)), in a *switch_statement* ([§13.8.3](statements.md#1383-the-switch-statement)), and in a *switch_expression* (§switch-expression-new-clause) to express the shape of data against which incoming data is to be compared. Patterns may be recursive, so that parts of the data may be matched against ***sub-patterns***. | |
| A pattern is tested against a value in a number of contexts: | |
| - In a switch statement, the *pattern* of a case label is tested against the *expression* of the switch statement. | |
| - In an *is-pattern* operator, the *pattern* on the right-hand-side is tested against the expression on the left. | |
| - In a switch expression, the *pattern* of a *switch_expression_arm* is tested against the expression on the switch-expression's left-hand-side. | |
| - In nested contexts, the *sub-pattern* is tested against values retrieved from properties, fields, or indexed from other input values, depending on the pattern form. | |
| The value against which a pattern is tested is called the ***pattern input value*** for the pattern. |
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.
👍’ed the above but a minor grammar question: should the first comma of each bullet be a semi-colon?
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.
In nested contexts, the sub-pattern is tested against values retrieved from properties, fields, or indexed from other input values, depending on the pattern form.
When we get to C# 9 with parenthesized patterns and logical patterns, we might want to remember to come back if we don't generalize this statement now, since and takes two subpatterns that do not retrieve new values to test against.
Co-authored-by: Nigel-Ecma <[email protected]>
Co-authored-by: Nigel-Ecma <[email protected]>
Co-authored-by: Nigel-Ecma <[email protected]>
|
See also #1428 |
gafter
left a comment
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.
Approved, but with additional items to be addressed later.
|
@gafter Is this now ready for me to merge? Or do you want to do more before we accept this? |
We agreed to merge with outstanding issues at our October meeting.
The ECMA committee merged dotnet/csharpstandard#873 Now, remove the feature spec from publication.
* Unpublish C# 8 patterns The ECMA committee merged dotnet/csharpstandard#873 Now, remove the feature spec from publication. * Fix warnings * Remove C# 8 feature spec references It's all in the standard now.
#873 changed `!x` to `!` on the second row of the table in §12.4.2; this PR reverts that change. The `x` is required to indicate that this is the prefix logical negation operator, the first row of the table contains `x!` for the postfix null-forgiving operator
#873 changed `!x` to `!` on the second row of the table in §12.4.2; this PR reverts that change. The `x` is required to indicate that this is the prefix logical negation operator, the first row of the table contains `x!` for the postfix null-forgiving operator
Prior to V8, we have a term “switch expression” defined as the expression inside parens in a
switchstatement.Now, we’re introducing a switch as an expression, and we have a new grammar rule called switch_expression. The difference between “switch expression” (without a *…* fence or separating underscore) and *switch_expression* likely is too subtle. So, how to differentiate them?
Although C calls such a switch expression a “controlling expression” (and uses that term as well for
if,while,for, anddostatements), we already state, “The governing type of aswitchstatement is established by the switch expression.”As such, I have replaced all occurrences of “switch expression” (which exist only in the statements chapter) with “switch’s governing expression.”
Fixes #576.
Fixes #300.