From ae73a341d788410e5f817cb22e7334b03db4abc8 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sat, 24 Jan 2026 11:38:54 -0500 Subject: [PATCH 1/2] support extended property patterns --- standard/patterns.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/standard/patterns.md b/standard/patterns.md index 0226f208b..d9f2c63d4 100644 --- a/standard/patterns.md +++ b/standard/patterns.md @@ -236,7 +236,11 @@ subpatterns ; subpattern : pattern - | identifier ':' pattern + | subpattern_name ':' pattern + ; +subpattern_name + : identifier + | subpattern_name '.' identifier ; ``` @@ -349,6 +353,12 @@ At runtime, the expression is tested against *T*. If this fails then the propert The *property_pattern* may be used to pattern-match with anonymous types. +A *property_subpattern* may reference a nested member. In such a case, the receiver for each name lookup is the type of the previous member *T₀*, starting from the *input type* of the *property_pattern*. If *T* is a nullable type, *T₀* is its underlying type, otherwise *T₀* is equal to *T*. For example, a pattern of the form `{ Prop1.Prop2: pattern }` is exactly equivalent to `{ Prop1: { Prop2: pattern } }`. + +> *Note*: This will include the null check when *T* is a nullable value type or a reference type. This null check means that the nested properties available will be the properties of *T₀*, not of *T*. As repeated member paths are allowed, the compilation of pattern matching can take advantage of common parts of patterns. *end note* + + + > *Example*: > > From 422843f2fae37b7cc2b1a8792afdc79e270ae166 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 24 Mar 2026 15:42:18 -0400 Subject: [PATCH 2/2] Grammar production name changes Some grammar productions have changed names since this was originally created. --- standard/patterns.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/standard/patterns.md b/standard/patterns.md index d9f2c63d4..9e7be2057 100644 --- a/standard/patterns.md +++ b/standard/patterns.md @@ -328,7 +328,7 @@ property_subpattern ; ``` -It is an error if any *subpattern* of a *property_pattern* does not contain an *identifier*. +It is an error if any *subpattern* of a *property_pattern* does not contain a *subpattern_name*. 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)). @@ -347,13 +347,13 @@ It is a compile-time error if the *type* is a nullable value type ([§8.3.12](ty > The example declaring `x2` is similar to `if (s is var x2)` in terms of inferring the variable type, but the property pattern guarantees that `x2` is non-null. > *end note* -Given a match of an expression *e* to the pattern *type* `{` *subpatterns* `}`, it is a compile-time error if the expression *e* is not pattern compatible ([§11.2.2](patterns.md#1122-declaration-pattern)) with the type *T* designated by *type*. If the type is absent, the type is assumed to be the static type of *e*. Each of the identifiers appearing on the left-hand-side of its *subpatterns* shall designate an accessible readable property or field of *T*. If the *simple_designation* of the *property_pattern* is present, it declares a pattern variable of type *T*. +Given a match of an expression *e* to the pattern *type* `{` *subpatterns* `}`, it is a compile-time error if the expression *e* is not pattern compatible with the type *T* designated by *type*. If the type is absent, the type is assumed to be the static type of *e*. Each of the identifiers appearing on the left-hand-side of its *subpatterns* shall designate an accessible readable property or field of *T*. If the *simple_designation* of the *property_pattern* is present, it declares a pattern variable of type *T*. At runtime, the expression is tested against *T*. If this fails then the property pattern match fails, and the result is `false`. If it succeeds, then each *property_subpattern* field or property is read, and its value matched against its corresponding pattern. The result of the whole match is `false` only if the result of any of these is `false`. The order in which subpatterns are matched is not specified, and a failed match may not test all subpatterns at runtime. If the match succeeds and the *simple_designation* of the *property_pattern* is a *single_variable_designation*, the declared variable is assigned the matched value. The *property_pattern* may be used to pattern-match with anonymous types. -A *property_subpattern* may reference a nested member. In such a case, the receiver for each name lookup is the type of the previous member *T₀*, starting from the *input type* of the *property_pattern*. If *T* is a nullable type, *T₀* is its underlying type, otherwise *T₀* is equal to *T*. For example, a pattern of the form `{ Prop1.Prop2: pattern }` is exactly equivalent to `{ Prop1: { Prop2: pattern } }`. +A *subpattern_name* may reference a nested member. In such a case, the receiver for each name lookup is the type of the previous member *T₀*, starting from the *input type* of the *property_pattern*. If *T* is a nullable type, *T₀* is its underlying type, otherwise *T₀* is equal to *T*. For example, a pattern of the form `{ Prop1.Prop2: pattern }` is exactly equivalent to `{ Prop1: { Prop2: pattern } }`. > *Note*: This will include the null check when *T* is a nullable value type or a reference type. This null check means that the nested properties available will be the properties of *T₀*, not of *T*. As repeated member paths are allowed, the compilation of pattern matching can take advantage of common parts of patterns. *end note*