From 13f99d27061f414a428a79bc1a285b37c8357479 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 9 Mar 2022 13:33:00 -0500 Subject: [PATCH 01/10] Incorporate Better Betterness This commit adds the notes from https://github.com/dotnet/roslyn/blob/main/docs/specs/CSharp%206/Better%20Betterness.md --- standard/expressions.md | 64 +++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index e5c079097..5a37d4993 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -945,34 +945,42 @@ In case the parameter type sequences `{P₁, P₂, ..., Pᵥ}` and `{Q₁, Q₂ #### 11.6.4.4 Better conversion from expression -Given an implicit conversion `C₁` that converts from an expression `E` to a type `T₁`, and an implicit conversion `C₂` that converts from an expression `E` to a type `T₂`, `C₁` is a ***better conversion*** than `C₂` if at least one of the following holds: - -- `E` has a type `S` and an identity conversion exists from `S` to `T₁` but not from `S` to `T₂` -- `E` is not an anonymous function and `T₁` is a better conversion target than `T₂` ([§11.6.4.6](expressions.md#11646-better-conversion-target)) -- `E` is an anonymous function, `T₁` is either a delegate type `D₁` or an expression tree type `Expression`, `T₂` is either a delegate type `D₂` or an expression tree type `Expression` and one of the following holds: - - `D₁` is a better conversion target than `D₂` - - `D₁` and `D₂` have identical parameter lists, and one of the following holds: - - `D₁` has a return type `Y₁`, and `D₂` has a return type `Y₂`, an inferred return type `X` exists for `E` in the context of that parameter list ([§11.6.3.13](expressions.md#116313-inferred-return-type)), and the conversion from `X` to `Y₁` is better than the conversion from `X` to `Y₂` - - `E` is async, `D₁` has a return type `Task`, and `D₂` has a return type `Task`, an inferred return type `Task` exists for `E` in the context of that parameter list ([§11.6.3.13](expressions.md#116313-inferred-return-type)), and the conversion from `X` to `Y₁` is better than the conversion from `X` to `Y₂` - - `D₁` has a return type `Y`, and `D₂` is void returning - -#### 11.6.4.5 Better conversion from type - -Given a conversion `C₁` that converts from a type `S` to a type `T₁`, and a conversion `C₂` that converts from a type `S` to a type `T₂`, `C₁` is a *better conversion* than `C₂` if at least one of the following holds: - -- An identity conversion exists from `S` to `T₁` but not from `S` to `T₂` -- `T₁` is a better conversion target than `T₂` ([§11.6.4.6](expressions.md#11646-better-conversion-target)) - -#### 11.6.4.6 Better conversion target - -Given two different types `T₁` and `T₂`, `T₁` is a better conversion target than `T₂` if at least one of the following holds: - -- An implicit conversion from `T₁` to `T₂` exists, and no implicit conversion from `T₂` to `T₁` exists -- `T₁` is a signed integral type and `T₂` is an unsigned integral type. Specifically: - - `T₁` is `sbyte` and `T₂` is `byte`, `ushort`, `uint`, or `ulong` - - `T₁` is `short` and `T₂` is `ushort`, `uint`, or `ulong` - - `T₁` is `int` and `T₂` is `uint`, or `ulong` - - `T₁` is `long` and `T₂` is `ulong` + + +Given an implicit conversion `C₁` that converts from an expression `E` to a type `T₁`, and an implicit conversion `C₂` that converts from an expression `E` to a type `T₂`, `C₁` is a ***better conversion*** than `C₂` if `E` does not exactly match `T₂` and one of the following holds: + +- `E` exactly matches `T₁` (§11.6.4.5) +- `T₁` is a better conversion target than `T₂` (§11.6.4.6) + +### 11.6.4.5 Exactly matching Expression + +Given an expression `E` and a type `T`, `E` ***exactly matches*** `T` is one of the following holds: + +- `E` has a type `S`, and an identity conversion exists from `S` to `T` +- `E` is an anonymous function, `T` is either a delegate type `D` or an expression tree type `Expression` and one of the following holds: + - An inferred return type `X` exists for `E` in the context of the parameter list of `D` (§11.6.3.12), and an identity conversion exists from `X` to the return type of `D` + - Either `E` is non-async and `D` has a return type `Y` or `E` is async and `D` has a return type `Task`, and one of the following holds: +- The body of `E` is an expression that exactly matches `Y` +- The body of `E` is a statement block where every return statement returns an expression that exactly matches `Y` + +### 11.6.4.6 Better conversion target + +Given two different types `T₁` and `T₂`, `T₁` is a ***better conversion target*** than `T₂` if: + +- An implicit conversion from `T₁` to `T₂` exists +- `T₁` is either a delegate type `D₁` or an expression tree type `Expression`, `T₂` is either a delegate type `D₂` or an expression tree type `Expression`, `D₁` has a return type `S₁` and one of the following holds: + - `D₂` is void returning + - `D₂` has a return type `S₂`, and `S₁` is a better conversion target than `S₂` +- `T₁` is `Task`, `T₂` is `Task`, and `S₁` is a better conversion target than `S₂` +- `T₁` is `S₁` or `S₁`? where `S₁` is a signed integral type, and `T₂` is `S₂` or `S₂`? where `S₂` is an unsigned integral type. Specifically: + - `S₁` is `sbyte` and `S₂` is `byte`, `ushort`, `uint`, or `ulong` + - `S₁` is `short` and `S₂` is `ushort`, `uint`, or `ulong` + - `S₁` is `int` and `S₂` is `uint`, or `ulong` + - `S₁` is `long` and `S₂` is `ulong` #### 11.6.4.7 Overloading in generic classes From c53e09122981a874d88c609aaea5b7e4c03e4e6d Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 9 Mar 2022 13:44:35 -0500 Subject: [PATCH 02/10] Incorporate changes from #283 Issue #283 contains notes for how the implementation differed from the proposed better betterness text. --- standard/expressions.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index 5a37d4993..c88e36be7 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -951,10 +951,9 @@ In case the parameter type sequences `{P₁, P₂, ..., Pᵥ}` and `{Q₁, Q₂ > Section 7.5.3.5 is now 11.6.4.6 --> -Given an implicit conversion `C₁` that converts from an expression `E` to a type `T₁`, and an implicit conversion `C₂` that converts from an expression `E` to a type `T₂`, `C₁` is a ***better conversion*** than `C₂` if `E` does not exactly match `T₂` and one of the following holds: - -- `E` exactly matches `T₁` (§11.6.4.5) -- `T₁` is a better conversion target than `T₂` (§11.6.4.6) +Given an implicit conversion `C₁` that converts from an expression `E` to a type `T₁`, and an implicit conversion `C₂` that converts from an expression `E` to a type `T₂`, `C₁` is a better conversion than `C₂` if one of the following holds: +- `E` exactly matches `T₁` and `E` does not exactly match `T₂` (§11.6.4.5) +- `E` exactly matches both or neither of `T₁` and `T2`, and `T₁` is a better conversion target than `T2` (§11.6.4.6) ### 11.6.4.5 Exactly matching Expression From 6fc72f884d257f75194c508627d8c45645f6500a Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 9 Mar 2022 17:15:09 -0500 Subject: [PATCH 03/10] compat for delegate conversion This commit brings in the method group conversion fix that caused dotnet/roslyn#6750 It needs wordsmithing for a number of reasons: - "corresponding argument" isn't defined. - the section references itself. - I think there may have been requirements from the prior commit regarding delegates and expressions that are still needed. --- standard/delegates.md | 1 - standard/expressions.md | 14 +++----------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/standard/delegates.md b/standard/delegates.md index 2d07ecfa5..87cab7065 100644 --- a/standard/delegates.md +++ b/standard/delegates.md @@ -79,7 +79,6 @@ A method or delegate type `M` is ***compatible*** with a delegate type `D` if al - `D` and `M` have the same number of parameters, and each parameter in `D` has the same `ref` or `out` modifiers as the corresponding parameter in `M`. - For each value parameter (a parameter with no `ref` or `out` modifier), an identity conversion ([§10.2.2](conversions.md#1022-identity-conversion)) or implicit reference conversion ([§10.2.8](conversions.md#1028-implicit-reference-conversions)) exists from the parameter type in `D` to the corresponding parameter type in `M`. - - For each `ref` or `out` parameter, the parameter type in `D` is the same as the parameter type in `M`. - An identity or implicit reference conversion exists from the return type of `M` to the return type of `D`. diff --git a/standard/expressions.md b/standard/expressions.md index c88e36be7..f7fe6a533 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -945,12 +945,6 @@ In case the parameter type sequences `{P₁, P₂, ..., Pᵥ}` and `{Q₁, Q₂ #### 11.6.4.4 Better conversion from expression - - Given an implicit conversion `C₁` that converts from an expression `E` to a type `T₁`, and an implicit conversion `C₂` that converts from an expression `E` to a type `T₂`, `C₁` is a better conversion than `C₂` if one of the following holds: - `E` exactly matches `T₁` and `E` does not exactly match `T₂` (§11.6.4.5) - `E` exactly matches both or neither of `T₁` and `T2`, and `T₁` is a better conversion target than `T2` (§11.6.4.6) @@ -963,17 +957,15 @@ Given an expression `E` and a type `T`, `E` ***exactly matches*** `T` is one of - `E` is an anonymous function, `T` is either a delegate type `D` or an expression tree type `Expression` and one of the following holds: - An inferred return type `X` exists for `E` in the context of the parameter list of `D` (§11.6.3.12), and an identity conversion exists from `X` to the return type of `D` - Either `E` is non-async and `D` has a return type `Y` or `E` is async and `D` has a return type `Task`, and one of the following holds: -- The body of `E` is an expression that exactly matches `Y` -- The body of `E` is a statement block where every return statement returns an expression that exactly matches `Y` + - The body of `E` is an expression that exactly matches `Y` + - The body of `E` is a statement block where every return statement returns an expression that exactly matches `Y` ### 11.6.4.6 Better conversion target Given two different types `T₁` and `T₂`, `T₁` is a ***better conversion target*** than `T₂` if: - An implicit conversion from `T₁` to `T₂` exists -- `T₁` is either a delegate type `D₁` or an expression tree type `Expression`, `T₂` is either a delegate type `D₂` or an expression tree type `Expression`, `D₁` has a return type `S₁` and one of the following holds: - - `D₂` is void returning - - `D₂` has a return type `S₂`, and `S₁` is a better conversion target than `S₂` +- In case of a method group conversion (§10.6) for the corresponding argument, if a better conversion target (§7.5.3.5), is a delegate type that is not compatible (§19.4) with the single best method from the method group (§10.6), then neither delegate type is better. - `T₁` is `Task`, `T₂` is `Task`, and `S₁` is a better conversion target than `S₂` - `T₁` is `S₁` or `S₁`? where `S₁` is a signed integral type, and `T₂` is `S₂` or `S₂`? where `S₂` is an unsigned integral type. Specifically: - `S₁` is `sbyte` and `S₂` is `byte`, `ushort`, `uint`, or `ulong` From ebc3858778fc9d5352019dbd26588008b9b8f4ed Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 10 Mar 2022 12:18:46 -0500 Subject: [PATCH 04/10] initial feedback. --- standard/expressions.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index f7fe6a533..ca1bd1d92 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -947,11 +947,11 @@ In case the parameter type sequences `{P₁, P₂, ..., Pᵥ}` and `{Q₁, Q₂ Given an implicit conversion `C₁` that converts from an expression `E` to a type `T₁`, and an implicit conversion `C₂` that converts from an expression `E` to a type `T₂`, `C₁` is a better conversion than `C₂` if one of the following holds: - `E` exactly matches `T₁` and `E` does not exactly match `T₂` (§11.6.4.5) -- `E` exactly matches both or neither of `T₁` and `T2`, and `T₁` is a better conversion target than `T2` (§11.6.4.6) +- `E` exactly matches both or neither of `T₁` and `T₂`, and `T₁` is a better conversion target than `T2` (§11.6.4.6) -### 11.6.4.5 Exactly matching Expression +#### 11.6.4.5 Exactly matching expression -Given an expression `E` and a type `T`, `E` ***exactly matches*** `T` is one of the following holds: +Given an expression `E` and a type `T`, `E` ***exactly matches*** `T` if one of the following holds: - `E` has a type `S`, and an identity conversion exists from `S` to `T` - `E` is an anonymous function, `T` is either a delegate type `D` or an expression tree type `Expression` and one of the following holds: @@ -960,14 +960,14 @@ Given an expression `E` and a type `T`, `E` ***exactly matches*** `T` is one of - The body of `E` is an expression that exactly matches `Y` - The body of `E` is a statement block where every return statement returns an expression that exactly matches `Y` -### 11.6.4.6 Better conversion target +#### 11.6.4.6 Better conversion target -Given two different types `T₁` and `T₂`, `T₁` is a ***better conversion target*** than `T₂` if: +Given two different types `T₁` and `T₂`, `T₁` is a ***better conversion target*** than `T₂` if one of the following holds: - An implicit conversion from `T₁` to `T₂` exists - In case of a method group conversion (§10.6) for the corresponding argument, if a better conversion target (§7.5.3.5), is a delegate type that is not compatible (§19.4) with the single best method from the method group (§10.6), then neither delegate type is better. - `T₁` is `Task`, `T₂` is `Task`, and `S₁` is a better conversion target than `S₂` -- `T₁` is `S₁` or `S₁`? where `S₁` is a signed integral type, and `T₂` is `S₂` or `S₂`? where `S₂` is an unsigned integral type. Specifically: +- `T₁` is `S₁` or `S₁?` where `S₁` is a signed integral type, and `T₂` is `S₂` or `S₂?` where `S₂` is an unsigned integral type. Specifically: - `S₁` is `sbyte` and `S₂` is `byte`, `ushort`, `uint`, or `ulong` - `S₁` is `short` and `S₂` is `ushort`, `uint`, or `ulong` - `S₁` is `int` and `S₂` is `uint`, or `ulong` From 2a257046c373e2a3ab5a66a574d20db492470be7 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 10 Mar 2022 12:21:53 -0500 Subject: [PATCH 05/10] section reference --- standard/expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/expressions.md b/standard/expressions.md index ca1bd1d92..61d0c30a8 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -965,7 +965,7 @@ Given an expression `E` and a type `T`, `E` ***exactly matches*** `T` if one of Given two different types `T₁` and `T₂`, `T₁` is a ***better conversion target*** than `T₂` if one of the following holds: - An implicit conversion from `T₁` to `T₂` exists -- In case of a method group conversion (§10.6) for the corresponding argument, if a better conversion target (§7.5.3.5), is a delegate type that is not compatible (§19.4) with the single best method from the method group (§10.6), then neither delegate type is better. +- In case of a method group conversion (§10.6) for the corresponding argument, if a better conversion target (§11.6.4.6), is a delegate type that is not compatible (§19.4) with the single best method from the method group (§10.6), then neither delegate type is better. - `T₁` is `Task`, `T₂` is `Task`, and `S₁` is a better conversion target than `S₂` - `T₁` is `S₁` or `S₁?` where `S₁` is a signed integral type, and `T₂` is `S₂` or `S₂?` where `S₂` is an unsigned integral type. Specifically: - `S₁` is `sbyte` and `S₂` is `byte`, `ushort`, `uint`, or `ulong` From 7cf27529117c5245349bb42003d5c336bd691a94 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 16 Mar 2022 09:22:08 -0400 Subject: [PATCH 06/10] a bit of editing --- standard/expressions.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index 61d0c30a8..c622a5cb6 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -946,8 +946,9 @@ In case the parameter type sequences `{P₁, P₂, ..., Pᵥ}` and `{Q₁, Q₂ #### 11.6.4.4 Better conversion from expression Given an implicit conversion `C₁` that converts from an expression `E` to a type `T₁`, and an implicit conversion `C₂` that converts from an expression `E` to a type `T₂`, `C₁` is a better conversion than `C₂` if one of the following holds: + - `E` exactly matches `T₁` and `E` does not exactly match `T₂` (§11.6.4.5) -- `E` exactly matches both or neither of `T₁` and `T₂`, and `T₁` is a better conversion target than `T2` (§11.6.4.6) +- `E` exactly matches both or neither of `T₁` and `T₂`, and `T₁` is a better conversion target than `T₂` (§11.6.4.6) #### 11.6.4.5 Exactly matching expression @@ -962,16 +963,20 @@ Given an expression `E` and a type `T`, `E` ***exactly matches*** `T` if one of #### 11.6.4.6 Better conversion target -Given two different types `T₁` and `T₂`, `T₁` is a ***better conversion target*** than `T₂` if one of the following holds: +Given an expression `E` and two types `T₁` and `T₂`, `T₁` is a ***better conversion target*** than `T₂` for `E` if one of the following holds: - An implicit conversion from `T₁` to `T₂` exists -- In case of a method group conversion (§10.6) for the corresponding argument, if a better conversion target (§11.6.4.6), is a delegate type that is not compatible (§19.4) with the single best method from the method group (§10.6), then neither delegate type is better. - `T₁` is `Task`, `T₂` is `Task`, and `S₁` is a better conversion target than `S₂` - `T₁` is `S₁` or `S₁?` where `S₁` is a signed integral type, and `T₂` is `S₂` or `S₂?` where `S₂` is an unsigned integral type. Specifically: - `S₁` is `sbyte` and `S₂` is `byte`, `ushort`, `uint`, or `ulong` - `S₁` is `short` and `S₂` is `ushort`, `uint`, or `ulong` - `S₁` is `int` and `S₂` is `uint`, or `ulong` - `S₁` is `long` and `S₂` is `ulong` +- In case of a method group conversion (§10.6) for the corresponding argument, if a better conversion target (§11.6.4.6), is a delegate type that is not compatible (§19.4) with the single best method from the method group (§10.6), then neither delegate type is better. +- `E` is the result of a method group conversion is a delegate creation expression (§11.7.15.6) whose argument is a method group and `T₁` is compatible (§19.4) with the single best method from the method group (§10.8) +- `T₁` is either a delegate type `D₁` or an expression tree type `Expression`, `T₂` is either a delegate type `D₂` or an expression tree type `Expression`, `D₁` has a return type `S₁` and one of the following holds: + - `D₂` is void returning + - `D₂` has a return type `S₂`, and `S₁` is a better conversion target than `S₂` #### 11.6.4.7 Overloading in generic classes From c7c4362156a41a5f7e7138bbd0d85b0c84764143 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 16 Mar 2022 11:07:06 -0400 Subject: [PATCH 07/10] I think this gets close This gets close to what's implemented in C# 6.0. I think this fails as a description in the case of #499 For 7.3, it would be better to describe that change in the section on Method Group conversion. --- standard/expressions.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index c622a5cb6..93b27654e 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -972,11 +972,7 @@ Given an expression `E` and two types `T₁` and `T₂`, `T₁` is a ***better c - `S₁` is `short` and `S₂` is `ushort`, `uint`, or `ulong` - `S₁` is `int` and `S₂` is `uint`, or `ulong` - `S₁` is `long` and `S₂` is `ulong` -- In case of a method group conversion (§10.6) for the corresponding argument, if a better conversion target (§11.6.4.6), is a delegate type that is not compatible (§19.4) with the single best method from the method group (§10.6), then neither delegate type is better. - `E` is the result of a method group conversion is a delegate creation expression (§11.7.15.6) whose argument is a method group and `T₁` is compatible (§19.4) with the single best method from the method group (§10.8) -- `T₁` is either a delegate type `D₁` or an expression tree type `Expression`, `T₂` is either a delegate type `D₂` or an expression tree type `Expression`, `D₁` has a return type `S₁` and one of the following holds: - - `D₂` is void returning - - `D₂` has a return type `S₂`, and `S₁` is a better conversion target than `S₂` #### 11.6.4.7 Overloading in generic classes From 8fae9765f4a4b30630c0c7740af50dc51828193a Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 16 Mar 2022 17:27:38 -0400 Subject: [PATCH 08/10] review from the meeting. --- standard/expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/expressions.md b/standard/expressions.md index 93b27654e..5700576c2 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -972,7 +972,7 @@ Given an expression `E` and two types `T₁` and `T₂`, `T₁` is a ***better c - `S₁` is `short` and `S₂` is `ushort`, `uint`, or `ulong` - `S₁` is `int` and `S₂` is `uint`, or `ulong` - `S₁` is `long` and `S₂` is `ulong` -- `E` is the result of a method group conversion is a delegate creation expression (§11.7.15.6) whose argument is a method group and `T₁` is compatible (§19.4) with the single best method from the method group (§10.8) +- `E` is a delegate creation expression (§11.7.15.6) resulting from the result of a method group conversion and `T₁` is compatible (§19.4) with the single best method from the method group (§10.8) #### 11.6.4.7 Overloading in generic classes From e4a6f8d56aa4f2693d82d7a8dba116ec3819806b Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 17 Mar 2022 11:17:53 -0400 Subject: [PATCH 09/10] fix awkward grammar --- standard/expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/expressions.md b/standard/expressions.md index 5700576c2..a1c3b798a 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -972,7 +972,7 @@ Given an expression `E` and two types `T₁` and `T₂`, `T₁` is a ***better c - `S₁` is `short` and `S₂` is `ushort`, `uint`, or `ulong` - `S₁` is `int` and `S₂` is `uint`, or `ulong` - `S₁` is `long` and `S₂` is `ulong` -- `E` is a delegate creation expression (§11.7.15.6) resulting from the result of a method group conversion and `T₁` is compatible (§19.4) with the single best method from the method group (§10.8) +- `E` is a delegate creation expression (§11.7.15.6) resulting from a method group conversion and `T₁` is compatible (§19.4) with the single best method from the method group (§10.8) #### 11.6.4.7 Overloading in generic classes From 88547ce645171894d2cf0474a03447fe16936e03 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 24 Mar 2022 08:41:17 -0400 Subject: [PATCH 10/10] limit bullet to method group conversion. --- standard/expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/expressions.md b/standard/expressions.md index a1c3b798a..55a5be441 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -972,7 +972,7 @@ Given an expression `E` and two types `T₁` and `T₂`, `T₁` is a ***better c - `S₁` is `short` and `S₂` is `ushort`, `uint`, or `ulong` - `S₁` is `int` and `S₂` is `uint`, or `ulong` - `S₁` is `long` and `S₂` is `ulong` -- `E` is a delegate creation expression (§11.7.15.6) resulting from a method group conversion and `T₁` is compatible (§19.4) with the single best method from the method group (§10.8) +- `E` is a method group conversion (§10.8() and `T₁` is compatible (§19.4) with the single best method from the method group #### 11.6.4.7 Overloading in generic classes