From ee800880500053df79dbf533ca88ebdbd835c53b Mon Sep 17 00:00:00 2001 From: Neal Gafter Date: Sun, 20 Mar 2016 19:50:42 -0700 Subject: [PATCH] Update pattern-matching specification and work list. Closes #7703 --- docs/features/patterns.md | 19 +++++--------- docs/features/patterns.work.md | 46 ++++++++++++++++++---------------- 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/docs/features/patterns.md b/docs/features/patterns.md index 1ba64dde4cd64..1c5e3b6239a5c 100644 --- a/docs/features/patterns.md +++ b/docs/features/patterns.md @@ -233,6 +233,7 @@ The `switch` statement is extended to select for execution the first block havin ```antlr switch-label : 'case' complex-pattern case-guard? ':' + | 'case' constant-expression case-guard? ':' | 'default' ':' ; @@ -242,6 +243,7 @@ case-guard ``` [TODO: we need to explain the interaction with definite assignment here.] +[TODO: we need to describe the scope of pattern variables appearing in the switch-label.] The order in which patterns are matched is not defined. A compiler is permitted to match patterns out of order, and to reuse the results of already matched patterns to compute the result of matching of other patterns. @@ -259,11 +261,7 @@ The C# language syntax is augmented with the following syntactic productions: relational-expression : match-expression ; -``` - -We add the *match-expression* as a new kind of *relational-expression*. -```antlr match-expression : relational-expression 'switch' match-block ; @@ -276,11 +274,7 @@ match-sections : match-section | match-sections ',' match-section ; -``` - -At least one *match-section* is required. -```antlr match-section : 'case' pattern case-guard? ':' expression ; @@ -373,8 +367,8 @@ is shorthand for (i.e. a *var-pattern*) and is a convenient way for declaring a read-only local variable. Semantically, it is an error unless precisely one of the following is true -1. the compiler can prove that the expression always matches the pattern; or -2. an `else` clause is present. +- the compiler can prove that the expression always matches the pattern; or +- an `else` clause is present. Any pattern variables in the *pattern* are in scope throughout the enclosing block. They are not definitely assigned before the `else` clause. They are definitely assigned after the *let-statement* if there is no `else` clause or they are definitely assigned at the end of the `else` clause (which could only occur because the end point of the `else` clause is unreachable). It is an error to use these variables before their point of definition. @@ -382,7 +376,7 @@ A *let-statement* is a *block-statement* and not an *embedded-statement* because If a `when` clause is present, the expression following it must be of type `bool`. -Ar runtime the expression to the right of `=` is evaluated and matched against the *pattern*. If the match fails control transfers to the `else` clause. If the match succeeds and there is a `when` clause, the expression following `when` is evaluated, and if its value is `false` control transfers to the `else` clause. +At runtime the expression to the right of `=` is evaluated and matched against the *pattern*. If the match fails control transfers to the `else` clause. If the match succeeds and there is a `when` clause, the expression following `when` is evaluated, and if its value is `false` control transfers to the `else` clause. ## Some Possible Optimizations @@ -537,5 +531,4 @@ Much of the Roslyn compiler code base, and client code written to use Roslyn for * Pattern matching with List, Dictionary * How should the type `dynamic` interact with pattern matching? * In what situations should the compiler be required by specification to warn about a match that must fail. E.g. switch on a `byte` but case label is out of range? -* Should it be possible to combine a recursive pattern and a property pattern into a single pattern, like `Point(int x, int y) { Length is 5 }` ? -* Should it be possible to name the whole matched thing in a property and/or recursive pattern, like `case Point(2, int x) p:` ? +* Should it be possible to name the whole matched thing in a property and/or recursive pattern, like `case Point p (2, int x):` ? diff --git a/docs/features/patterns.work.md b/docs/features/patterns.work.md index c9d6172fb892b..54642154affc4 100644 --- a/docs/features/patterns.work.md +++ b/docs/features/patterns.work.md @@ -1,27 +1,40 @@ This is a checklist (moved from #9375) of implementation of pattern matching as specified in [patterns.md](./patterns.md). For reference a previous prototype was at https://github.com/semihokur/pattern-matching-csharp Open design issues (needing LDM decisions) -- [ ] Do we want pattern-matching in the switch statement? If so, what does “goto case” mean? Or do we want a separate statement-based construct instead? (#8821) -- [ ] What syntax do we want for the match expression? (#8818) -- [ ] Do they have to be complete? If not, what happens? Warning and exception? -- [ ] Under what condition do we give diagnostics for pattern-matching based on subsumption or completion? See http://www.cs.tufts.edu/~nr/cs257/archive/norman-ramsey/match.pdf for a discussion of implementation approaches. +- [ ] Do we want pattern-matching in the `switch` statement? Or do we want a separate statement-based construct instead? (#8821) + - [ ] What does `goto case` mean? + - [ ] Do we limit `goto case` to constants? + - [ ] Or do we allow a non-constant expression in a `goto case` statement? + - [ ] If limited to constants, must its value match an existing constant label? + - [ ] Can a constant `case` label with a `when` clause be the target of `goto case`? + - [ ] How do we write the rules for the switch-expression (conversion) and matching labels (i.e. constant patterns) so that it approximates the current behavior? + - [ ] Do we allow multiple cases in the same `switch` block if one of them defines a pattern variable? +- [ ] What syntax do we want for the `match` expression? (#8818) + - [ ] Does a `match` expression have to be complete? If not, what happens? Warning? Exception? Both? + - [ ] What about the `case` expression? +- [ ] Under what condition do we give diagnostics for pattern-matching based on subsumption or completion? See http://www.cs.tufts.edu/~nr/cs257/archive/norman-ramsey/match.pdf for a discussion of implementation approaches. We probably need to select (and specify?) an approach. - [ ] Should we combine the property pattern with the type pattern so as to allow giving the object a name? If so, what syntax? - [ ] What do we think about the let statement? + - [ ] Do we require the match be irrefutable? If not, do we give a warning? Or let definite-assignment issues alert the user to any problems? + - [ ] Do we support an else? - [ ] There are some scoping questions for pattern variables. #9452 - [ ] Need to get LDM approval for design change around scope of pattern variables declared within a constructor initializer #9452 - [ ] Also questions about multiple field initializers, local initializers, ctor-initializers (how far does the scope extend?) - [ ] Need detailed spec for name lookup of property in a property pattern #9255 - [ ] [Pattern Matching] Should a property-pattern be capable of referencing an event? #9515 -- [ ] Two small clarifications need to be integrated into the spec (#7703) -- [ ] We need to specify and implement the user-defined pattern forms: user-defined `operator is` +- [X] Two small clarifications need to be integrated into the spec (#7703) +- [ ] We need to specify and implement the user-defined pattern forms: user-defined `operator is`? - [ ] static void with self-receiver - [ ] static bool for active patterns - [ ] instance bool for captured data (regex) - [ ] Do we want to support "breakpoints inside" patterns (#9095) - [ ] What is the correct precedence of *throw-expression*? Should *assignment* be allowed as its subexpression? +- [ ] @jaredpar suggested that, by analogy with the integral types, we should match floating-point literal patterns across floating-point types. -Progress checklist: -- [ ] Add a decision tree to enable +Implementation progress checklist: +- [ ] **Match constant patterns with appropriate integral conversions** (#8819) +- [ ] **Allow declaration of `operator is`** and use it for recursive patterns. +- [ ] **Add a decision tree** to enable - [ ] completeness checking: a mutli-armed pattern-matching expression is required to be complete - [ ] subsumption checking: a branch of a switch statement or match expression may not be subsumed by the totality of previous branches (#8823) - [ ] Generate efficient code like `switch` does in corresponding situations. (#8820) @@ -32,35 +45,25 @@ Progress checklist: - [x] Add tests for the parser, including precedence tests for the edge cases. - [ ] Augment `TestResource.AllInOneCSharpCode` to handle all pattern forms. - [x] Check for feature availability in the parser (error if feature not supported). + - [ ] Do not generate any new syntax nodes in C# 6 mode. - [X] Error pattern matching to a nullable value type - [x] Implement pattern matching to a type that is an unconstrained type variable (requires a double type test) -- [ ] Implement and test scoping in remaining "odd" contexts (where the scope is not the enclosing statement) - - [x] pattern matching in ctor-initializers - - [x] pattern matching in catch filters - - [x] pattern matching in field initializers - - [x] pattern matching in expression-bodied methods and properties - - [x] pattern matching in an expression-bodied lambda - - [x] pattern matching in an expression-bodied local function - - [x] pattern matching in attributes and parameter defaults (lookup and error recovery) - - [x] test these "odd" contexts in `SemanticModel`. - [ ] Semantics and code-gen for all pattern forms - [X] Type ID - [x] * - [x] 3 - [X] matching with exact type for integral constants (as a short-term hack) - - [ ] matching with appropriate integral conversions (#8819) - [x] `var` ID - [x] Type { ID is Pattern ... } - ~~Type ( Pattern ... )~~ This will be done when Records are integrated. - [ ] Extend the switch statement to handle patterns - [x] Parser - - [ ] Syntax Tests + - [x] Syntax Tests - [x] Binding - [ ] Binding (failure cases) tests - [x] Flow analysis - [x] Lowering - [x] Code-gen tests -- [ ] Allow declaration of `operator is` - [x] An expression form for mutli-armed pattern-matching (`match`?) - [ ] Extend the scope of a pattern variable declared in a catch filter to the catch block. (#8814) - [ ] Implement and test pattern variable scoping for all statements (#8817) @@ -81,7 +84,8 @@ Progress checklist: - [ ] Is a method - [ ] Is an indexed property - [ ] Is a nested type - - [X] In inaccessible + - [X] Is inaccessible + - [ ] Is ambiguous - [ ] Does not exist - [ ] `IOperation` support for pattern-matching (#8699) - [ ] Some unit tests that were disabled during development need to be re-enabled (#8778)