Skip to content

Commit

Permalink
Spec forbidding constant numeric patterns on INumberBase<T> (#6273)
Browse files Browse the repository at this point in the history
* Spec forbidding constant numeric patterns on `INumberBase<T>`

We want to block this for C# 11, so that a future version of C# can call the appropriate APIs on `INumberBase` and make this scenario work as expected.
  • Loading branch information
333fred committed Jul 18, 2022
1 parent 19d5cbe commit e6d8c4b
Showing 1 changed file with 24 additions and 0 deletions.
24 changes: 24 additions & 0 deletions proposals/static-abstracts-in-interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,30 @@ We discussed a simpler version which maintains the limitations of the current pr

At https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-24.md#default-implementations-of-abstract-statics we decided to support Default Implementations of static members following/expanding the rules established in https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/default-interface-methods.md accordingly.

## Pattern matching

Given the following code, a user might reasonably expect it to print True (as it would if the constant pattern was written inline):

```cs
M(1.0);

static void M<T>(T t) where T : INumberBase<T>
{
Console.WriteLine(t is 1);
}
```

However, because the input type of the pattern is not `double`, the constant `1` pattern will first type check the incoming `T` against `int`. This is unintuitive, so we will block it until a future C# version adds better handling for numeric matching against types derived from `INumberBase<T>`. To do so, we will say that, we will explicitly recognize `INumberBase<T>` as the type that all "numbers" will derive from, and block the pattern if we're trying to match a numeric constant pattern against a number type that we can't represent the pattern in (ie, a type parameter constrained to `INumberBase<T>`, or a user-defined number type that inherits from `INumberBase<T>`).

Formally, we add an exception to the definition of *pattern-compatible* for constant patterns:

> A constant pattern tests the value of an expression against a constant value. The constant may be any constant expression, such as a literal, the name of a declared `const` variable, or an enumeration constant. When the input value is not an open type, the constant expression is implicitly converted to the type of the matched expression; if the type of the input value is not *pattern-compatible* with the type of the constant expression, the pattern-matching operation is an error. **If the constant expression being matched against is a numeric value, the input value is a type that inherits from `System.Numerics.INumberBase<T>`, and there is no constant conversion from the constant expression to the type of the input value, the pattern-matching operation is an error.**
We also add a similar exception for relational patterns:

> When the input is a type for which a suitable built-in binary relational operator is defined that is applicable with the input as its left operand and the given constant as its right operand, the evaluation of that operator is taken as the meaning of the relational pattern. Otherwise we convert the input to the type of the expression using an explicit nullable or unboxing conversion. It is a compile-time error if no such conversion exists. **It is a compile-time error if the input type is a type parameter constrained to or a type inheriting from `System.Numerics.INumberBase<T>` and the input type has no suitable built-in binary relational operator defined.** The pattern is considered not to match if the conversion fails. If the conversion succeeds then the result of the pattern-matching operation is the result of evaluating the expression e OP v where e is the converted input, OP is the relational operator, and v is the constant expression.

# Drawbacks
[drawbacks]: #drawbacks

Expand Down

0 comments on commit e6d8c4b

Please sign in to comment.