Avoid several breaking changes in overload resolution from inferred types of lambda expressions and method groups#56341
Conversation
…not a function conversion
…nce did not infer type arguments from inferred type of lambdas or method groups
…s or argument conversion
|
Regarding the proposed spec change:
Can this be simplified to "a function type conversion"? Similarly, we can use the "function type" label as a shorthand in the third group. In reply to: 918633815 In reply to: 918633815 In reply to: 918633815 |
| internal readonly struct MethodTypeInferenceResult | ||
| { | ||
| public readonly ImmutableArray<TypeWithAnnotations> InferredTypeArguments; | ||
| public readonly bool InferredFromFunctionType; |
There was a problem hiding this comment.
nit: Consider adding a comment here and in MemberResolutionResult
nit: Consider aligning names between those two structures (TypeArgumentsFromFunctionType here?) #Closed
| if (formalParameterTypes.Length == 0) | ||
| { | ||
| return new MethodTypeInferenceResult(false, default(ImmutableArray<TypeWithAnnotations>)); | ||
| return new MethodTypeInferenceResult(false, default, false); |
There was a problem hiding this comment.
nit: consider naming arguments #Closed
| } | ||
| } | ||
|
|
||
| switch ((conv1.Kind, conv2.Kind)) |
There was a problem hiding this comment.
The proposed spec changes covers "better function member" and is implemented by BetterFunctionMember above. But I don't a spec change for better conversion from expression. I think this change is sensible, but let's spec it too. #Resolved
|
|
||
| [WorkItem(4674, "https://github.com/dotnet/csharplang/issues/4674")] | ||
| [Fact] | ||
| public void OverloadResolution_01A() |
There was a problem hiding this comment.
consider adding one more variation on this: void M<T>(T, Func<object>) vs. void M<T>(Func<object>, T) (remains error) #Closed
|
|
||
| [WorkItem(4674, "https://github.com/dotnet/csharplang/issues/4674")] | ||
| [Fact] | ||
| public void OverloadResolution_01D() |
There was a problem hiding this comment.
Could we add a variant of this scenario with M<T, U>(Func<T>, U) versus M<T, U>(T, U)? I think it will be ambiguous, but may be worth discussing (should we keep a per-argument rule like before rather than adding an aggregate rule where any function type conversion means "worse"?) #Closed
| comp = CreateCompilation(source); | ||
| comp.VerifyDiagnostics(expectedDiagnostics10AndLater); | ||
| CompileAndVerify(source, parseOptions: TestOptions.Regular10); | ||
| CompileAndVerify(source); |
There was a problem hiding this comment.
Let's verify which overload got picked. Ditto in tests below that are no longer breaks #Closed
jcouv
left a comment
There was a problem hiding this comment.
Done with review pass (iteration 9)
|
This PR fixes a few recently opened issues. I think #56167 is one of them |
| { | ||
| // (10,11): error CS0428: Cannot convert method group 'F' to non-delegate type 'Expression'. Did you intend to invoke the method? | ||
| // M(F); | ||
| Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "F").WithArguments("F", "System.Linq.Expressions.Expression").WithLocation(10, 11) |
There was a problem hiding this comment.
Ideally, overload resolution should choose M(object) rather than M(Expression).
| operator+(A a, Func<int> f) | ||
| "); | ||
|
|
||
| // Breaking change from C#9. |
There was a problem hiding this comment.
Let's update the breaking change doc along with this and review that we've documented other breaks we've accepted. Could be done in a separate PR, but feels like it would fit well along with this. #Closed
jcouv
left a comment
There was a problem hiding this comment.
Done with review pass (iteration 12)
- This tests a build of dotnet/roslyn#56341
| ``` | ||
|
|
||
| 2. In C# 10, lambda expressions and method groups with inferred type are implicitly convertible to `System.MulticastDelegate`, and bases classes and interfaces of `System.MulticastDelegate` including `object`, | ||
| and lambda expressions are implicitly convertible to `System.Linq.Expressions.Expression` and `System.Linq.Expressions.LambdaExpression`. |
jcouv
left a comment
There was a problem hiding this comment.
LGTM Thanks (iteration 21) with a suggestion to consolidate breaking change bullet 3 into breaking change bullet 2.
|
|
||
| static void Main() | ||
| { | ||
| F(() => () => 1, 2); // C#9: ok; C#10: ambiguous |
|
|
||
| static void Main() | ||
| { | ||
| F(() => () => 1, 2); // C#9: F(Func<Func<object>>, int); C#10: ambiguous |
- This tests a build of dotnet/roslyn#56341
|
So many people have noticed the breaks in RC1 that I wonder if this change is worth a mention in dotnet/core#6570. |
Thanks @jnm2, I've added an entry there. |
- This tests a build of dotnet/roslyn#56341
Update "better function member" to prefer members where none of the conversions and none of the type arguments involved inferred types from lambda expressions or method groups.
Update "better conversion from expression" to prefer conversions that did not involve inferred types from lambda expressions or method groups.
The changes resolve several breaking changes between C#9 and C#10.
Fixes #55691
Fixes #56167
Fixes #56319
Relates to test plan #52192