Language/Compiler work: https://github.com/dotnet/csharplang/issues/2850~~ https://github.com/dotnet/csharplang/pull/3361
These are the things we will need to support and/or validate:
is not null. https://github.com/dotnet/roslyn/pull/43322and, or, not patterns when appropriate. https://github.com/dotnet/roslyn/pull/43324not, and, or. Need to make sure we're at soft selecting in places where new comparison patterns are allowed so we don't interfere with typing. #43365, #43574 !(x is null) to x is not null. https://github.com/dotnet/roslyn/pull/43438(>= #43538not null. case string _ =>. Add analzyer that removes unnecessary _ . Add Using, Generate type.cc @mikadumont for info
we would take a refactoring to convert to/from if-chains to and/or patterns
would take a refactoring to convert long chains of comparisons to patterns.
Some other ideas for refactorings:
case p: case q: -> case p or q:case 'a': .. case 'z': -> case >= 'a' and <= 'z':These might be useful to simplify current workarounds:
Some of these might overlap though, and we should decide which one should be an analyzer versus a refactoring.
case string _ =>. Add analzyer that removes unnecessary _ .
I think this should be in the simplifier. There are other cases that need to be covered there.
Update existing pattern analyzers to try to use and, or, not patterns when appropriate
This should include if-to-switch and switch-statement-to-expression in particular, those are specifically limited due to lack of or-patterns.
Worth to consider:
default: when the switch is already exhaustive.=>2 and =<4 or =>3 and =<5great stuff. Thanks @alrz !
CS8780 ERR_DesignatorBeneathPatternCombinatorYou aren't permitted to declare a pattern variable under an or or not
pattern combinator, so we produce this error when you attempt to do so.
if (o is int or long l) // error: A variable may not be declared within a 'not' or 'or' pattern.
if (o is Bar { F: not int i }) // error: A variable may not be declared within a 'not' or 'or' pattern.
CS8781 ERR_UnsupportedTypeForRelationalPatternThe new relational patterns work only for the built-in types that
have comparison operator. If you attempt to use them for other
types it is an error
string s = ...;
if (s < "aardvark") // error: Relational patterns may not be used for a value of type 'string'.
CS8782 ERR_RelationalPatternWithNaNThe new relational patterns do not permit comparing with NaN.
double d = ...;
switch (d)
{
case < double.NaN: // error: Relational patterns may not be used for a floating-point NaN.
CS8793 WRN_GivenExpressionAlwaysMatchesPatternWhen a new pattern form always matches in an is-pattern expression because the input is a constant, we warn.
if (1 is < 10) // warning: The given expression always matches the provided pattern.
CS8794 WRN_IsPatternAlwaysWhen a new pattern form always matches in an is-pattern (whether or not the input is a constant), we warn:
int x = ...;
if (x is <= int.MaxValue) // warning: The input always matches the provided pattern.
Active statement tracking in switch expression arms works well.
Found a couple of related issues:
[Debugger] Disambiguate sequence points with equal text span: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1106749.
[Compilers] Switch expression stepping not working correctly: #43468
[Sam][LowPriority]
case string _ =>. Add analzyer that removes unnecessary _ .
@sharwell I can take this if you're not working on it.
@CyrusNajmabadi
A langversion-dependant reducer works here without a need for an analyzer, right?
(much like CSharpDefaultExpressionReducer)
@alrz Sure go ahead! Also consider the following case, which is not new for C# 9 but would benefit from the same simplification:
if (o is string _)
Closing out. Any remaining work/enhancements can come through directed issues.
@gafter
You aren't permitted to declare a pattern variable under an or or not
pattern combinator
Can you point me to more documentation on this limitation?
I just stumbled upon it on a scenario where it didn't make a lot of sense to me:
if (x is { Code: not 1 code })
{
return new Error(code);
}
The value 1 above is a "success" indicator in my domain, and I want to match "when the code is not 1" then generate an error with the actual code in it.
Can you elaborate why this is an invalid scenario? The restriction you mentioned doesn't seem to make sense when using constant values on the match IMHO.
Seems like the only way out of this is degrading the code into using a when like:
if (x is { Code: var code } when code != 1)
{
return new Error(code);
}
FAKE EDIT:
Found a really weird (undocumented?) way of extracting the value, by repeating the same property twice:
if (x is { Code: not 1, Code: var code })
{
return new Error(code);
}
Can you elaborate why this is an invalid scenario?
Because nothing in the language allows it. Neither hte 'not' nor 'constant' patterns allow you to name the result. We'd need a proposal allowing that for that to work :)
Found a really weird (undocumented?) way of extracting the value, by repeating the same property twice:
Now that is weird. @333fred @jcouv is that supposed to be allowed? Seems really really strange and unintentional.
Huh. I agree it's odd, but I don't see anything in the spec that would disallow this: https://github.com/dotnet/csharplang/blob/master/proposals/csharp-8.0/patterns.md#property-pattern.
@julealgon Try:
if (x is { Code: not 1 and var code })
{
return new Error(code);
}
Now that is weird. ... Seems really really strange and unintentional.
I agree @CyrusNajmabadi . I honestly thought it would give me some sort of error at runtime the first time I tried it, or match the values incorrectly.
@julealgon Try:
if (x is { Code: not 1 and var code }) { return new Error(code); }
It works @alrz ! Interesting... is that how it is supposed to be done at the end of the day? I don't think I've ever seen an example like that.
is that how it is supposed to be done at the end of the day?
Yes. This is definitely a supported and used pattern today. In the future, we might consider a way of making this more terse. But absent that, the above is def a realistic way to go.