-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Avoid several breaking changes in overload resolution from inferred types of lambda expressions and method groups #56341
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
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 |
{ | ||
public readonly ImmutableArray<TypeWithAnnotations> InferredTypeArguments; | ||
public readonly bool InferredFromFunctionType; |
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.
nit: Consider adding a comment here and in MemberResolutionResult
nit: Consider aligning names between those two structures (TypeArgumentsFromFunctionType
here?) #Closed
@@ -276,7 +279,7 @@ private enum Dependency | |||
// Early out: if the method has no formal parameters then we know that inference will fail. | |||
if (formalParameterTypes.Length == 0) | |||
{ | |||
return new MethodTypeInferenceResult(false, default(ImmutableArray<TypeWithAnnotations>)); | |||
return new MethodTypeInferenceResult(false, default, false); |
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.
nit: consider naming arguments #Closed
@@ -2449,6 +2464,16 @@ private BetterResult BetterConversionFromExpression(BoundExpression node, TypeSy | |||
} | |||
} | |||
|
|||
switch ((conv1.Kind, conv2.Kind)) |
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's verify which overload got picked. Ditto in tests below that are no longer breaks #Closed
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
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.
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`. |
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.
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.
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 |
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.
static void Main() | ||
{ | ||
F(() => () => 1, 2); // C#9: F(Func<Func<object>>, int); C#10: ambiguous |
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.
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.
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.
LGTM (commit 23)
- 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