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
Prev Previous commit
Next Next commit
Update pattern-const-expressions.md
  • Loading branch information
Rekkonnect committed Oct 14, 2023
commit d66f305414c7a9c6560828fbe08a5cbbfcaa4772
49 changes: 37 additions & 12 deletions proposals/pattern-const-expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,36 @@ Consider `is` pattern expressions as constant if the LHS is constant.
## Motivation
[motivation]: #motivation

Certain pattern expressions that can be converted into simpler boolean expressions using equality and comparison operators are never considered constant expressions, even when all parts of the expression are considered constant and can be evaluated during compilation. However, the lowered versions of those expressions (that only involve equality and comparison operators) are always considered constant. This prohibits the ability to utilize `is` expressions for operations like comparing against a range (e.g. `x is >= 'a' and 'z'`), or checking against distinct values (e.g. `x is Values.A or Values.B or Values.C`).
Certain pattern expressions that can be converted into simpler boolean expressions using equality and comparison operators are never considered constant expressions, even when all parts of the expression are considered constant and can be evaluated during compilation. However, the lowered versions of those expressions (that only involve equality and comparison operators) are constant.

The above restriction prevents the ability to utilize `is` expressions for operations like comparing against a range (e.g. `x is >= 'a' and 'z'`), or checking against distinct values (e.g. `x is Values.A or Values.B or Values.C`), and instead relying on using traditional comparison operators like so for the last example: `x == Values.A || x == Values.B || x == Values.C`.

## Detailed design
[design]: #detailed-design

A pattern expression is constant if all its contained subpatterns are all also constant. The following subpatterns are constant:
- Boolean literal (`true` or `false`)
- Numeric literal (e.g. `0`, `1f`, `3m`, etc.)
- Character literal (e.g. `'c'`, `'\0'`, etc.)
- String literal (e.g. `"Hello world."`, `""`, etc.)
- Relative numeric literal (e.g. `> 3`, `< 0.3m`, etc.)
- Relative character literal (e.g. `> 'a'`, `<= 'z'`, etc.)
- Null literal (`null`)
- Default literal (`default(T)`), but not `default` without a type
- And, or and not patterns (e.g. the *and* in `>= 'a' and <= 'z'`)
- Parenthesized patterns (e.g. the parentheses in `is (not (X or Y))`)
- Constant field (including enum fields) or local, e.g.
- `x is y` when y is a const field or local, or
- `x is SomeEnum.None` when `None` is an enum field

The allowed subpatterns as shown in the list above are called "constant subpatterns", as they will be eligible for compile-time evaluation.

If the `is` expression consists of a constant expression on the LHS, and is compared against a constant pattern on the right, the entire `is` expression is a constant expression.

### Spec
[spec]: #spec

The [section](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/expressions.md#1223-constant-expressions) in the spec needs to be updated accordingly, in the following segments:
The [§12.23 section](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/expressions.md#1223-constant-expressions) in the spec needs to be updated accordingly, in the following segments:

> Only the following constructs are permitted in constant expressions:
> - Literals (including the null literal).
Expand All @@ -35,7 +56,9 @@ The [section](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/ex
> - The predefined +, –, !, and ~ unary operators.
> - The predefined +, –, *, /, %, <<, >>, &, |, ^, &&, ||, ==, !=, <, >, <=, and >= binary operators.
> - The ?: conditional operator.
> - **Pattern expressions with only the following subpatterns:**
> - 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.**
Expand All @@ -44,22 +67,21 @@ The [section](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/ex
> - **Relative character literal patterns.**
> - **Null literal patterns.**
> - **Default literal patterns.**
> - 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.

The allowed subpatterns as shown in the list above are called "constant subpatterns", as they will be eligible for compile-time evaluation.
> - **And, or and not patterns.**
> - **Parenthesized patterns.**
> - **References to constant fields or locals inside constant patterns.**

### Grammar
[grammar]: #grammar
The grammar remains untouched, as nothing changes syntactically for this change.
The grammar remains untouched, as nothing changes syntactically for this feature.

### Semantics
[semantics]: #semantics
A pattern expression only consisting of the above subpatterns with a constant LHS may be evaluated at compile time currently, but it cannot be assigned to a constant symbol. With this change, constant fields and locals of type `bool` may be assigned pattern expressions, as already evaluated during compilation.
A pattern expression only consisting of constant subpatterns with a constant LHS may be evaluated at compile time currently, but it is not considered as constant. With this change, the following adjustments enable constant pattern expressions to be used in constant contexts, like assigning a constant field or local, a default parameter, the condition in a constant conditional expression, etc.

### Examples
[examples]: #examples
The below example shows pattern expressions being assigned to a constant field.
The below example shows pattern expressions being assigned to constant fields:
```csharp
public const int A = 4;
public const bool B = A is 4;
Expand All @@ -72,7 +94,9 @@ public const bool D = Environment
or DeploymentEnvironment.Test;
```

Since `A` is constant, and all the operands on the right are constant, the entire expression only consists of constants, thus the expression is evaluated during compilation. This result will then be assigned to the constant field. Likewise, `Environment` is also constant as an enum value, and so are the other subpatterns of the expression.
In the expression assigned to `C`, since `A` is constant, and all the subpatterns on the pattern are constant, the entire expression only consists of constants. This result will be evaluated during compile-time and then be assigned to the constant field.

Likewise, `Environment` is constant as an enum value, and so are the other subpatterns of the expression assigned to `D`.

Another example, using `null` and default value checks:
```csharp
Expand Down Expand Up @@ -113,8 +137,9 @@ Currently, equality and comparison operators can be used to compare against othe
[unresolved]: #unresolved-questions

- [ ] Requires LDM review
- [ ] Should this be extended to `switch` expressions too? (Discussion [#7489](https://github.com/dotnet/csharplang/discussions/7489))
333fred marked this conversation as resolved.
Show resolved Hide resolved

## Design meetings
[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)
- 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)