-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add proposal for type inference from method group #10239
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,32 @@ | ||||||
| # Type inference using method group natural type | ||||||
|
|
||||||
| Champion issue: https://github.com/dotnet/csharplang/issues/9007 | ||||||
|
|
||||||
| ## Summary | ||||||
| [summary]: #summary | ||||||
|
|
||||||
| It allows the natural type of a method group to contribute to method type inference | ||||||
|
|
||||||
| The current [type inference rules](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/expressions.md#1263-type-inference) allow | ||||||
| - method groups to contribute to output type inference | ||||||
| - infering bounds for the `Ui` type parameters in `C<U1 ... Uk>` when given a `C<V1...Vk>` and `C` is a class, struct, interface or delegate type. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| But they don't allow method groups to contribute to bounds. | ||||||
|
|
||||||
| ``` | ||||||
| Test(IsEven); // Error CS0411 The type arguments for method 'Program.Test<T>(Func<T, bool>)' cannot be inferred from the usage. Try specifying the type arguments explicitly. | ||||||
|
|
||||||
| partial class Program | ||||||
| { | ||||||
| public static bool IsEven(int x) => x % 2 == 0; | ||||||
| public static void Test<T>(Func<T, bool> predicate) { } | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| ## Design | ||||||
|
|
||||||
| We modify the [explicit parameter type inference rules](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/expressions.md#12638-explicit-parameter-type-inferences) to not just apply to explicitly-typed lambdas, but also to method groups: | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps expand on potential breaking changes that will come from this? IIRC that was a major reason we didn't do this in the first place.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. E.g. the exact inference causes: static bool P(object o) => true;
static void M<T>(Func<T, bool> f, T value) => Console.WriteLine(typeof(T));
M(P, "hello"); // Today, prints System.String; after proposal, prints System.Object
M(bool (object o) => true, "hello"); // Prints System.Object
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly, this would stop compiling: static bool P(object o) => true;
static void M<T>(Func<T, bool> f, Func<T, bool> g) { }
M((string s) => true, P); // Compiles now, would behave like the next line after the proposal
M((string s) => true, bool (object o) => true); // Fails to compile
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those are good to include, but neither would have worked before the original lambda changes. The breaks I'm referring to are when an inner scope method suddenly becomes applicable where it wasn't before, such as an instance generic now working instead of going to an extension method, or a derived overload now working where previously it went to a base type. |
||||||
|
|
||||||
| An *explicit parameter type inference* is made *from* an expression `E` *to* a type `T` in the following way: | ||||||
|
|
||||||
| - If `E` is an explicitly typed anonymous function \***or method group with a unique signature** with parameter types `U₁...Uᵥ` and `T` is a delegate type or expression tree type with parameter types `V₁...Vᵥ` then for each `Uᵢ` an *exact inference* is made *from* `Uᵢ` *to* the corresponding `Vᵢ`. | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because as written I think the spec would still work even if method groups had no natural type.