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
Add the subsumption and exhaustiveness rules for the new patterns in V9.
The subsumption/exhaustiveness rules in the Roslyn compiler use a BDD (binary decision diagram)-based algorithm that is more powerful than can be expressed with simple prose rules. These rules attempt to capture the *observable behavior* (what the compiler accepts/rejects) rather than the implementation algorithm. Where the compiler's algorithm is too complex to fully express (e.g., relational range analysis), the spec describes the intent and give examples.
Copy file name to clipboardExpand all lines: standard/patterns.md
+32-4Lines changed: 32 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -548,6 +548,10 @@ negated_pattern
548
548
549
549
A *negated_pattern* matches if the pattern being negated does not match, and vice versa. A *conjunctive_pattern* requires both patterns to match. A *disjunctive_pattern* requires either pattern to match. Unlike their language operator counterparts, `&&` and `||`, `and` and `or` are *not* short-circuiting operators.
550
550
551
+
It is a compile-time error for a pattern variable to be declared beneath a `not` or `or` pattern operator.
552
+
553
+
> *Note*: Because neither `not` nor `or` can produce a definite assignment for a pattern variable, it is an error to declare one in those positions. *end note*
554
+
551
555
In a *conjunctive_pattern*, the *input type* of the second pattern is narrowed by the *type narrowing* requirements of first pattern of the `and`. The *narrowed type* of a pattern `P` is defined as follows:
552
556
553
557
- If `P` is a type pattern, the *narrowed type* is the type of the type pattern's type.
@@ -669,13 +673,29 @@ In a switch statement ([§13.8.3](statements.md#1383-the-switch-statement)), it
669
673
> *Note*: This means that any input value would have been matched by one of the previous cases or arms. *end note*
670
674
The following rules define when a set of patterns subsumes a given pattern:
671
675
672
-
A pattern `P` *would match* a constant `K` if the specification for that pattern’s runtime behavior is that `P` matches `K`.
676
+
A pattern `P` *would match* a constant `K` if any of the following conditions hold:
677
+
678
+
- the specification for that pattern's runtime behavior is that `P` matches `K`.
679
+
- `P` is a *type_pattern* for type `T` and `K` is not `null` and the runtime type of `K` is `T` or a type derived from `T` or a type that implements `T`.
680
+
- `P` is a *relational_pattern* with operator «op» and constant `v`, and the expression `K` «op» `v` would evaluate to `true`.
681
+
- `P` is a *negated_pattern* `not P₁` and `P₁` would not match `K`.
682
+
- `P` is a *conjunctive_pattern* `P₁ and P₂` and both `P₁` would match `K` and `P₂` would match `K`.
683
+
- `P` is a *disjunctive_pattern* `P₁ or P₂` and either `P₁` would match `K` or `P₂` would match `K`.
684
+
- `P` is a *discard_pattern*.
673
685
674
686
A set of patterns `Q` *subsumes* a pattern `P` if any of the following conditions hold:
675
687
676
-
- `P` is a constant pattern and any of the patterns in the set `Q` would match `P`’s *converted value*
688
+
- `P` is a constant pattern and any of the patterns in the set `Q` would match `P`'s *converted value*
677
689
- `P` is a var pattern and the set of patterns `Q` is *exhaustive* ([§11.4](patterns.md#114-pattern-exhaustiveness)) for the type of the pattern input value ([§11.1](patterns.md#111-general)), and either the pattern input value is not of a nullable type or some pattern in `Q` would match `null`.
678
690
- `P` is a declaration pattern with type `T` and the set of patterns `Q` is *exhaustive* for the type `T` ([§11.4](patterns.md#114-pattern-exhaustiveness)).
691
+
- `P` is a *type_pattern* for type `T` and the set of patterns `Q` is *exhaustive* for the type `T`.
692
+
- `P` is a *relational_pattern* with operator «op» and constant value `v`, and for every value of the input type satisfying the relation «op» `v`, some pattern in the set `Q` would match that value.
693
+
- `P` is a *disjunctive_pattern* `P₁ or P₂` and the set of patterns `Q` subsumes `P₁` and `Q` subsumes `P₂`.
694
+
- `P` is a *conjunctive_pattern* `P₁ and P₂` and at least one of the following holds: `Q` subsumes `P₁`, or `Q` subsumes `P₂`.
695
+
- `P` is a *negated_pattern* `not P₁` and `Q` is *exhaustive* for the input type considering only the values not matched by `P₁`.
696
+
- `P` is a *discard_pattern* and the set of patterns `Q` is *exhaustive* for the type of the pattern input value, and either the pattern input value is not of a nullable type or some pattern in `Q` would match `null`.
697
+
- Some pattern in `Q` is a *disjunctive_pattern* `Q₁ or Q₂` and replacing that pattern with `Q₁` in `Q` would yield a set that subsumes `P`, or replacing it with `Q₂` would yield a set that subsumes `P`.
698
+
- Some pattern in `Q` is a *negated_pattern* `not Q₁` and `P` would not match any value that `Q₁` would match.
679
699
680
700
> *Example*: In the following switch expression, no arm is subsumed even though arms 1, 2, and 3 share the same pattern:
681
701
>
@@ -702,8 +722,16 @@ The following rules define when a set of patterns is *exhaustive* for a type:
702
722
Asetofpatterns `Q` is *exhaustive* foratype `T` ifanyofthefollowingconditionshold:
703
723
704
724
1. `T` isanintegralorenumtype, oranullableversionofoneofthose, andforeverypossiblevalueof `T`’snon-nullableunderlyingtype, somepatternin `Q` wouldmatchthatvalue; or
705
-
2. Somepatternin `Q` isa *varpattern*; or
706
-
3. Somepatternin `Q` isa *declarationpattern* fortype `D`, andthereisanidentityconversion, animplicitreferenceconversion, oraboxingconversionfrom `T` to `D`.
725
+
1. Somepatternin `Q` isa *varpattern*; or
726
+
1. Somepatternin `Q` isa *declarationpattern* fortype `D`, andthereisanidentityconversion, animplicitreferenceconversion, oraboxingconversionfrom `T` to `D`; or
727
+
1. Somepatternin `Q` isa *type_pattern* fortype `D`, andthereisanidentityconversion, animplicitreferenceconversion, oraboxingconversionfrom `T` to `D`; or
728
+
1. Somepatternin `Q` isa *discard_pattern*; or
729
+
1. Thepatternsin `Q` includeacombinationof*relational_pattern*sand*constant_pattern*swhoserangescollectivelycovereverypossiblevalueof `T`'s non-nullable underlying type. For `float` and `double` types, this includes `System.Double.NaN` or `System.Single.NaN` respectively, since `NaN` is not matched by any relational pattern; or
730
+
1. Somepatternin `Q` isa *disjunctive_pattern* `P₁ orP₂`, andreplacingthatpatternwithboth `P₁` and `P₂` in `Q` yieldsasetthatis*exhaustive* for `T`; or
731
+
1. Somepatternin `Q` isa *negated_pattern* `notP₁`, andthepatternsin `Q` togetherwiththevaluesnotmatchedby `P₁` covereverypossiblevalueof `T`. A*negated_pattern* `notP₁` isexhaustivebyitself when `P₁` matches no possible value of `T`; or
732
+
1. Somepatternin `Q` isa *conjunctive_pattern* `P₁ andP₂`, andthesetcontainingonly `P₁` is*exhaustive* for `T` andthesetcontainingonly `P₂` is *exhaustive* for `T`.
733
+
734
+
> *Note*:Forfloating-pointtypes, thecombinationofpatterns `<0` and `>=0` is*not*exhaustivebecauseneitherrelationalpatternmatches `NaN`. Acorrectexhaustivesetwouldbe `< 0`, `>=0`, and `double.NaN` (or `float.NaN`). *endnote*
0 commit comments