From 656e9766c4fd96302549efd18c770f6396b305fe Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Fri, 30 Jul 2021 11:49:02 +0430 Subject: [PATCH 01/11] Update list-patterns.md --- proposals/list-patterns.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/proposals/list-patterns.md b/proposals/list-patterns.md index ef12dc2644..8b6c79bf66 100644 --- a/proposals/list-patterns.md +++ b/proposals/list-patterns.md @@ -59,7 +59,12 @@ case [.., 1, _]: // expr.Length is >= 2 && expr[^2] is 1 ``` The order in which subpatterns are matched at runtime is unspecified, and a failed match may not attempt to match all subpatterns. - + +Given a specific length, it's possible that two subpatterns refer to the same element, in which case a test for this value is inserted into the decision DAG. + +For instance, `[_, >0, ..] or [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length == 3 || [^1] <= 0)` +Conversely, `[_, >0, ..] and [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length != 3 && [^1] <= 0)` + #### Lowering A pattern of the form `expr is [1, 2, 3]` is equivalent to the following code (if compatible via implicit `Index` support): From a1af1ccb547b28fd9a893c0603455de2cb5b7bcd Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Fri, 30 Jul 2021 11:52:31 +0430 Subject: [PATCH 02/11] Update list-patterns.md --- proposals/list-patterns.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/proposals/list-patterns.md b/proposals/list-patterns.md index 8b6c79bf66..9b90336896 100644 --- a/proposals/list-patterns.md +++ b/proposals/list-patterns.md @@ -34,12 +34,18 @@ There are two new patterns: #### Pattern compatibility -A *list_pattern* is compatible with any type that is *countable* as well as *indexable* — it has an accessible indexer that takes an `Index` as an argument or otherwise an accessible indexer with a single `int` parameter. If both indexers are present, the former is preferred. +A *list_pattern* is compatible with any type that is *countable* and *indexable*. -A *slice_pattern* with a subpattern is compatible with any type that is *countable* as well as *sliceable* — it has an accessible indexer that takes a `Range` as an argument or otherwise an accessible `Slice` method with two `int` parameters. If both are present, the former is preferred. +A *slice_pattern* with a subpattern is compatible with any type that is *countable* and *sliceable*. A *slice_pattern* without a subpattern is compatible with any type that is compatible with a *list_pattern*. +A type is *countable* if it has an accessible property getter that returns an `int` and has the name `Length` or `Count`. If both properties are present, the former is preferred. + +A type is *indexable* if it has an accessible indexer that takes an `Index` as an argument or otherwise an accessible indexer with a single `int` parameter. If both indexers are present, the former is preferred. + +A type is *sliceable* it has an accessible indexer that takes a `Range` as an argument or otherwise an accessible `Slice` method with two `int` parameters. If both are present, the former is preferred. + This set of rules is derived from the [***range indexer pattern***](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-8.0/ranges.md#implicit-index-support). #### Subsumption checking @@ -62,8 +68,8 @@ The order in which subpatterns are matched at runtime is unspecified, and a fail Given a specific length, it's possible that two subpatterns refer to the same element, in which case a test for this value is inserted into the decision DAG. -For instance, `[_, >0, ..] or [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length == 3 || [^1] <= 0)` -Conversely, `[_, >0, ..] and [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length != 3 && [^1] <= 0)` +For instance, `[_, >0, ..] or [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length == 3 || [^1] <= 0)` where the length value of 3 implies the other test. +Conversely, `[_, >0, ..] and [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length != 3 && [^1] <= 0)` where the length value of 3 disallows the other test. #### Lowering From b02f701bf8e646cf781907d06feff88e0c7d8e1e Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Fri, 30 Jul 2021 11:55:06 +0430 Subject: [PATCH 03/11] Update list-patterns.md --- proposals/list-patterns.md | 1 + 1 file changed, 1 insertion(+) diff --git a/proposals/list-patterns.md b/proposals/list-patterns.md index 9b90336896..ec70e21913 100644 --- a/proposals/list-patterns.md +++ b/proposals/list-patterns.md @@ -69,6 +69,7 @@ The order in which subpatterns are matched at runtime is unspecified, and a fail Given a specific length, it's possible that two subpatterns refer to the same element, in which case a test for this value is inserted into the decision DAG. For instance, `[_, >0, ..] or [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length == 3 || [^1] <= 0)` where the length value of 3 implies the other test. + Conversely, `[_, >0, ..] and [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length != 3 && [^1] <= 0)` where the length value of 3 disallows the other test. #### Lowering From 65f973d48adff07bd4e3f97b6717c7a2e84c2aa5 Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Fri, 30 Jul 2021 12:08:13 +0430 Subject: [PATCH 04/11] Update list-patterns.md --- proposals/list-patterns.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/proposals/list-patterns.md b/proposals/list-patterns.md index ec70e21913..32da3d7985 100644 --- a/proposals/list-patterns.md +++ b/proposals/list-patterns.md @@ -72,6 +72,14 @@ For instance, `[_, >0, ..] or [.., <=0, _]` becomes `length >= 2 && [1] > 0 && ( Conversely, `[_, >0, ..] and [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length != 3 && [^1] <= 0)` where the length value of 3 disallows the other test. +If a slice subpattern matches a list or a length value, subpatterns are analysed as if they were a direct subpattern of the containing list. + +For instance, `[..[1, 2, 3]]` subsumes a pattern of the form `[1, 2, 3]`. + +`Length` or `Count` properties are assumed to always return non-negative values, if only if the type is *indexable*. + +For instance, the pattern `array is { Length: -1 }` can never match. + #### Lowering A pattern of the form `expr is [1, 2, 3]` is equivalent to the following code (if compatible via implicit `Index` support): From 05dbfd93279e1b142d89045115c4da2282074a5d Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Fri, 30 Jul 2021 12:12:29 +0430 Subject: [PATCH 05/11] Update list-patterns.md --- proposals/list-patterns.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/list-patterns.md b/proposals/list-patterns.md index 32da3d7985..970afd6549 100644 --- a/proposals/list-patterns.md +++ b/proposals/list-patterns.md @@ -76,9 +76,9 @@ If a slice subpattern matches a list or a length value, subpatterns are analysed For instance, `[..[1, 2, 3]]` subsumes a pattern of the form `[1, 2, 3]`. -`Length` or `Count` properties are assumed to always return non-negative values, if only if the type is *indexable*. +`Length` or `Count` properties are assumed to always return a non-negative value, if and only if the type is *indexable*. -For instance, the pattern `array is { Length: -1 }` can never match. +For instance, the pattern `{ Length: -1 }` can never match an array. #### Lowering From 5180cb332b1d2e2f8c2216fc69d83fe52650d334 Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Sat, 31 Jul 2021 13:43:55 +0430 Subject: [PATCH 06/11] Update list-patterns.md --- proposals/list-patterns.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/list-patterns.md b/proposals/list-patterns.md index 970afd6549..ae88b7544c 100644 --- a/proposals/list-patterns.md +++ b/proposals/list-patterns.md @@ -68,9 +68,9 @@ The order in which subpatterns are matched at runtime is unspecified, and a fail Given a specific length, it's possible that two subpatterns refer to the same element, in which case a test for this value is inserted into the decision DAG. -For instance, `[_, >0, ..] or [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length == 3 || [^1] <= 0)` where the length value of 3 implies the other test. +For instance, `[_, >0, ..] or [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length == 3 || [^2] <= 0)` where the length value of 3 implies the other test. -Conversely, `[_, >0, ..] and [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length != 3 && [^1] <= 0)` where the length value of 3 disallows the other test. +Conversely, `[_, >0, ..] and [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length != 3 && [^2] <= 0)` where the length value of 3 disallows the other test. If a slice subpattern matches a list or a length value, subpatterns are analysed as if they were a direct subpattern of the containing list. From 2f46077f1922e2af1d5032baa67a3a2d3fcf47bb Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Sat, 31 Jul 2021 16:33:02 +0430 Subject: [PATCH 07/11] Update list-patterns.md --- proposals/list-patterns.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/proposals/list-patterns.md b/proposals/list-patterns.md index ae88b7544c..329bdc32c2 100644 --- a/proposals/list-patterns.md +++ b/proposals/list-patterns.md @@ -68,17 +68,14 @@ The order in which subpatterns are matched at runtime is unspecified, and a fail Given a specific length, it's possible that two subpatterns refer to the same element, in which case a test for this value is inserted into the decision DAG. -For instance, `[_, >0, ..] or [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length == 3 || [^2] <= 0)` where the length value of 3 implies the other test. +- For instance, `[_, >0, ..] or [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length == 3 || [^2] <= 0)` where the length value of 3 implies the other test. +- Conversely, `[_, >0, ..] and [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length != 3 && [^2] <= 0)` where the length value of 3 disallows the other test. -Conversely, `[_, >0, ..] and [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length != 3 && [^2] <= 0)` where the length value of 3 disallows the other test. +As a result, an error is produced for something like `case [.., p]: case [p]` because at runtime, we're matching the same element in each case. -If a slice subpattern matches a list or a length value, subpatterns are analysed as if they were a direct subpattern of the containing list. +If a slice subpattern matches a list or a length value, subpatterns are treated as if they were a direct subpattern of the containing list. For instance, `[..[1, 2, 3]]` subsumes a pattern of the form `[1, 2, 3]`. -For instance, `[..[1, 2, 3]]` subsumes a pattern of the form `[1, 2, 3]`. - -`Length` or `Count` properties are assumed to always return a non-negative value, if and only if the type is *indexable*. - -For instance, the pattern `{ Length: -1 }` can never match an array. +`Length` or `Count` properties are assumed to always return a non-negative value, if and only if the type is *indexable*. For instance, the pattern `{ Length: -1 }` can never match an array. The behavior of a pattern-matching operation is undefined if this assumption doesn't hold. #### Lowering From 4cb116ec137690275cc1426789c8e5e8520967e8 Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Sun, 1 Aug 2021 21:29:00 +0430 Subject: [PATCH 08/11] Update list-patterns.md --- proposals/list-patterns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/list-patterns.md b/proposals/list-patterns.md index 329bdc32c2..280f7911bd 100644 --- a/proposals/list-patterns.md +++ b/proposals/list-patterns.md @@ -71,7 +71,7 @@ Given a specific length, it's possible that two subpatterns refer to the same el - For instance, `[_, >0, ..] or [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length == 3 || [^2] <= 0)` where the length value of 3 implies the other test. - Conversely, `[_, >0, ..] and [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length != 3 && [^2] <= 0)` where the length value of 3 disallows the other test. -As a result, an error is produced for something like `case [.., p]: case [p]` because at runtime, we're matching the same element in each case. +As a result, an error is produced for something like `case [.., p]: case [p]` because at runtime, we're matching the same element in the second case. If a slice subpattern matches a list or a length value, subpatterns are treated as if they were a direct subpattern of the containing list. For instance, `[..[1, 2, 3]]` subsumes a pattern of the form `[1, 2, 3]`. From 02fd39631bda49e2522e2f0fb02160a65d2cbea8 Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Sun, 1 Aug 2021 21:50:34 +0430 Subject: [PATCH 09/11] Update list-patterns.md --- proposals/list-patterns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/list-patterns.md b/proposals/list-patterns.md index 280f7911bd..cbd67f8a96 100644 --- a/proposals/list-patterns.md +++ b/proposals/list-patterns.md @@ -71,7 +71,7 @@ Given a specific length, it's possible that two subpatterns refer to the same el - For instance, `[_, >0, ..] or [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length == 3 || [^2] <= 0)` where the length value of 3 implies the other test. - Conversely, `[_, >0, ..] and [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length != 3 && [^2] <= 0)` where the length value of 3 disallows the other test. -As a result, an error is produced for something like `case [.., p]: case [p]` because at runtime, we're matching the same element in the second case. +As a result, an error is produced for something like `case [.., p]: case [p]:` because at runtime, we're matching the same element in the second case. If a slice subpattern matches a list or a length value, subpatterns are treated as if they were a direct subpattern of the containing list. For instance, `[..[1, 2, 3]]` subsumes a pattern of the form `[1, 2, 3]`. From 7bf631e9933eca8ef9e10a9f26508baacc954a09 Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Mon, 2 Aug 2021 20:34:06 +0430 Subject: [PATCH 10/11] Update list-patterns.md --- proposals/list-patterns.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/list-patterns.md b/proposals/list-patterns.md index cbd67f8a96..f5376428f7 100644 --- a/proposals/list-patterns.md +++ b/proposals/list-patterns.md @@ -68,8 +68,8 @@ The order in which subpatterns are matched at runtime is unspecified, and a fail Given a specific length, it's possible that two subpatterns refer to the same element, in which case a test for this value is inserted into the decision DAG. -- For instance, `[_, >0, ..] or [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length == 3 || [^2] <= 0)` where the length value of 3 implies the other test. -- Conversely, `[_, >0, ..] and [.., <=0, _]` becomes `length >= 2 && [1] > 0 && (length != 3 && [^2] <= 0)` where the length value of 3 disallows the other test. +- For instance, `[_, >0, ..] or [.., <=0, _]` becomes `length >= 2 && ([1] > 0 || length == 3 || [^2] <= 0)` where the length value of 3 implies the other test. +- Conversely, `[_, >0, ..] and [.., <=0, _]` becomes `length >= 2 && [1] > 0 && length != 3 && [^2] <= 0` where the length value of 3 disallows the other test. As a result, an error is produced for something like `case [.., p]: case [p]:` because at runtime, we're matching the same element in the second case. From e70376676d8b0c8dc45a6119bae4564f1f13268a Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Tue, 3 Aug 2021 06:07:23 +0430 Subject: [PATCH 11/11] Revert --- proposals/list-patterns.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/proposals/list-patterns.md b/proposals/list-patterns.md index f5376428f7..155e2439cc 100644 --- a/proposals/list-patterns.md +++ b/proposals/list-patterns.md @@ -34,18 +34,12 @@ There are two new patterns: #### Pattern compatibility -A *list_pattern* is compatible with any type that is *countable* and *indexable*. +A *list_pattern* is compatible with any type that is *countable* as well as *indexable* — it has an accessible indexer that takes an `Index` as an argument or otherwise an accessible indexer with a single `int` parameter. If both indexers are present, the former is preferred. -A *slice_pattern* with a subpattern is compatible with any type that is *countable* and *sliceable*. +A *slice_pattern* with a subpattern is compatible with any type that is *countable* as well as *sliceable* — it has an accessible indexer that takes a `Range` as an argument or otherwise an accessible `Slice` method with two `int` parameters. If both are present, the former is preferred. A *slice_pattern* without a subpattern is compatible with any type that is compatible with a *list_pattern*. -A type is *countable* if it has an accessible property getter that returns an `int` and has the name `Length` or `Count`. If both properties are present, the former is preferred. - -A type is *indexable* if it has an accessible indexer that takes an `Index` as an argument or otherwise an accessible indexer with a single `int` parameter. If both indexers are present, the former is preferred. - -A type is *sliceable* it has an accessible indexer that takes a `Range` as an argument or otherwise an accessible `Slice` method with two `int` parameters. If both are present, the former is preferred. - This set of rules is derived from the [***range indexer pattern***](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-8.0/ranges.md#implicit-index-support). #### Subsumption checking