-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Update list-patterns.md #4790
Update list-patterns.md #4790
Conversation
@@ -153,7 +148,7 @@ 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. | |||
|
|||
> **Open question**: The pattern `{..}` tests for `expr.Length >= 0`. Should we omit such test (assuming `Length` is always non-negative)? | |||
> **Open question**: By this definition, the pattern `{..}` tests for `expr.Length >= 0`. Should we omit such test, assuming `Length` is always non-negative? (answer [LDM 2021-05-26]: `{ .. }` will not emit a Length check) |
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.
📝 Notes were clear that this is about semantics and not an optimization.
proposals/list-patterns.md
Outdated
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` 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*. |
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.
📝 We shouldn't require Slice method if there is no subpattern. This'd be consistent with the decision about {..}
.
: '..' negated_pattern? | ||
: '..' 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.
Wasn't mentioned in LDM. But I think "all patterns" includes combinators. #Resolved
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.
It does. I'm not familiar enough with the various levels of the pattern grammar, does negated_pattern
not include combinators?
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.
No it doesn't. I've started this as an unary operator, hence the precedence.
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.
nit: Consider adding links to previous patterns specs:
https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.0/pattern-matching.md
https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/patterns.md
https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/patterns3.md
A *slice_pattern* is compatible with any type that is *countable* as well as *sliceable* — it has an accessible indexer that takes a `Range` argument or otherwise an accessible `Slice` method that takes two `int` arguments. If both are present, the former is preferred. | ||
A *slice_pattern* without a subpattern is also compatible with any type that is *enumerable*. | ||
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*. |
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.
Might need to mention discard subpattern?
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.
With this change, we have:
{..}
works even withoutthis[Range]
or a properSlice
method.{.._}
requiresthis[Range]
/Slice
. The codegen, however, is permitted to omit the invocation (which we do). That is not limited to discards or the slice pattern, we skip an evaluation when the output is unused.e.g. with an unused variable etc.
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.
Sounds like we currently don't include unused variables here, but it's something that could be done as an optimization.
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.
Here's an example to demonstrate it's not limited to discard: if (this is {IntProp: {}}){}
IntProp is not called here.
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.
The codegen, however, is permitted to omit the invocation (which we do).
This is a good distinction, but I do think it is good to make this not an optimization: it gets back to making sure that behavior of something like default(ImmutableArray<int>) is { .._ }
is well-defined.
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.
At the moment the behavior of default(ImmutableArray<int>) is { .._ }
is an error. "unsupported type for slice pattern"
ImmutableArray doesn't expose a Slice method or range indexer.
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.
Yeah, but additions are tracked by dotnet/runtime#22928.
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 main concern is that when a type is not sliceable, we should be able to do {1, ..}
etc. Not every list should be required to be sliceable only to be able to skip elements in the list 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.
I'm fine with the behavior as spec'ed in this PR. I'd let .._
and ..var unused
require a sliceable type. It's conceptually simpler.
For { ..var unused }
: during binding we don't know that var unused
is unused.
For { .._ }
: @333fred , I can add a note to test plan to rediscuss if you think this should not require a sliceable type.
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.
For
{ .._ }
Just like we still need an indexable type for {_}
that we're not going to use, {.._}
should require a sliceable type that we may not use. I think the part that we decide to not evaluate the method, is orthogonal to binding rules.
To be clear, I don't think we should do anything specific for To that end, I've proposed to use a hypothetical |
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.
LGTM Thanks (iteration 2)
Agreed. |
@333fred I started thread with LDM mentioning the |
Merged/squashed. Thanks @alrz |
Record recent LDM decisions and sync with the current impl.
Linking to test plan: dotnet/roslyn#51289