Skip to content
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

Create spec for const expressions for is patterns #7589

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
66 changes: 56 additions & 10 deletions proposals/pattern-const-expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ The [§12.23 section](https://github.com/dotnet/csharpstandard/blob/standard-v7/
> - sizeof expressions, provided the unmanaged-type is one of the types specified in §23.6.9 for which sizeof returns a constant value.
> - Default value expressions, provided the type is one of the types listed above.
> - **`is` expressions with only the following subpatterns:**
> - **Boolean literal patterns.**
> - **Numeric literal patterns.**
> - **Character literal patterns.**
> - **String literal patterns.**
> - **Relative numeric literal patterns.**
> - **Relative character literal patterns.**
> - **Null literal patterns.**
> - **Default literal patterns.**
> - **Boolean patterns.**
> - **Numeric patterns.**
> - **Character patterns.**
> - **String patterns.**
> - **Relative numeric patterns.**
> - **Relative character patterns.**
> - **Null patterns.**
> - **Default patterns.**
> - **And, or and not patterns.**
> - **Parenthesized patterns.**
> - **References to constant fields or locals inside constant patterns.**
Expand Down Expand Up @@ -111,9 +111,54 @@ const bool z = d is not null; // always true
const bool p = b is null; // always false
```

All the above are currently valid pattern matching expressions, that also emit warnings about their constant evaluation results, about them being always true or false.
### Diagnostics

When assigning those expressions to a constant symbol, these warnings about the constant result of the expression will **not** be reported, as the user intends to capture the constant value of the expression.
All the above are currently valid pattern matching expressions, that also emit warnings about their constant evaluation results, being always true or false.

When assigning those expressions in a constant context, these warnings about the constant result of the expression will **not** be reported, as the user intends to capture the constant value of the expression. Constant context involves:
- initializers for const symbols (fields or locals)
- attribute arguments
- parameter default value
- switch statement case labels
- switch expression arms
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to see the actual spec changes here. How do we have to redefine the sections that specify these constructs to introduce a constant context? What is the definition of a constant context itself?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated ptal


Examples for the above:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add some more examples. All of the examples here are always true, we want some always false as well. Let's also throw in some switch expression examples with proposed behavior; I don't want to go through the whole specification of switch expressions yet, but we can at least include some examples to demonstrate warning behavior for unreachable arms/locations where the arms don't cover the whole input range (ie, when you cover case 1 and 2, but not 3-uint.MaxValue).

```csharp
const int a = 4;
const bool b = false;
const long c = 4;
const string d = "hello";
const Sign e = Sign.Negative;

// local or field
const bool x = a is default(int); // always false, no warning/error

// attribute argument
[assembly: Something(a is 4)] // always true, no warning/error

// parameter default value
// always true, no warning/error
int Negate(int value, bool negate = e is Sign.Negative) { }

// switch statement case label
switch (b)
{
// always true, no warning/error
case a is c:
break;
}

// switch expression arm
var p = b switch
{
// always true, no warning/error
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 problems with this:

  1. This is actually missing a case. b is false, and a is c is true.
  2. The overall switch expression should not change behavior, which is to say it should still warn about missing cases.

a is c => 1,
};
```

**NOTE**: we do not introduce any breaking changes in the reported diagnostics. Currently, all the above cases are illegal reporting "CS0150: A constant value is expected". A warning about the values always evaluating to either true or false is also reported alongside the error. We remove the warnings from those places where `is` expressions are currently not permitted to be used due to the error.

### Other patterns

Pattern expressions containing non-constant subpatterns, like accessing properties, list patterns and var patterns, are **not** constant. In the below examples, all expressions will report compiler errors:

Expand Down Expand Up @@ -143,3 +188,4 @@ Currently, equality and comparison operators can be used to compare against othe
[meetings]: #design-meetings

- Approval for Any Time milestone: [Here](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-10-09.md#is-expression-evaluating-const-expression-should-be-considered-constant)
- November 27th, 2023 [Discussion](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-11-27.md#making-patterns-constant-expressions)