From be20c86cd04e74e5361bc5dd911871af2ce42430 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Wed, 13 Jul 2022 09:10:55 -0700 Subject: [PATCH 1/2] Spec forbidding constant numeric patterns on `INumberBase` 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. --- proposals/static-abstracts-in-interfaces.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/proposals/static-abstracts-in-interfaces.md b/proposals/static-abstracts-in-interfaces.md index 2bea70b199..4bc0674c5b 100644 --- a/proposals/static-abstracts-in-interfaces.md +++ b/proposals/static-abstracts-in-interfaces.md @@ -264,6 +264,25 @@ 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) where T : INumberBase +{ + 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`. To do so, we will say that, we will explicitly recognize `INumberBase` 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`, or a user-defined number type that inherits from `INumberBase`). + +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`, and there is no constant conversion from the constant expression to the type of the input value, the pattern-matching operation is an error.** + # Drawbacks [drawbacks]: #drawbacks From 209320bf94b6444d5d60113114700b3cd4668c5a Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Thu, 14 Jul 2022 13:55:42 -0700 Subject: [PATCH 2/2] Added explicit wording for relational patterns as well. --- proposals/static-abstracts-in-interfaces.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/proposals/static-abstracts-in-interfaces.md b/proposals/static-abstracts-in-interfaces.md index 4bc0674c5b..8f7f209efc 100644 --- a/proposals/static-abstracts-in-interfaces.md +++ b/proposals/static-abstracts-in-interfaces.md @@ -283,6 +283,11 @@ Formally, we add an exception to the definition of *pattern-compatible* for cons > 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`, 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` 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