-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Ignore function types in return type inference #57713
Conversation
var comp = CreateCompilation(source); | ||
comp.VerifyDiagnostics( | ||
|
||
var expectedDiagnostics = new[] |
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.
@dotnet/roslyn-compiler, please review this fix for 17.0, thanks. |
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Test4").WithArguments("Test4").WithLocation(7, 6), | ||
// (11,1): error CS0411: The type arguments for method 'Test3<T>(Func<Func<T>>)' cannot be inferred from the usage. Try specifying the type arguments explicitly. | ||
// Test3(() => () => 3); | ||
Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Test3").WithArguments("Test3<T>(System.Func<System.Func<T>>)").WithLocation(11, 1), |
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.
I'm not familiar at all with the rules/specifications around this so feel free to ignore, but is it expected that this case shouldn't support inference? In my bug report (57517) I mentioned that Func<Func<T>>
supported inference of T
and it seems this change is going in the opposite direction and undoing something that was working? When I made the bug report I was thinking that the outcome would be that inference of T
on Func<Expression<Func<T>>>
would start working.
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.
Thanks @CameronAavik for catching this and for logging #57517.
With C#10 currently, there is a potential breaking change from C#9 in type inference when inferring from the return type of a lambda expression when the return value is another lambda expression or a method group
(see examples in #57517 (comment) and #57630).
We've decided to fix the breaking change for now by not inferring from the return type of a lambda if the return value is another lambda or method group. This effectively reverts the type inference behavior for those cases to the C#9 behavior.
(I've added this to the PR description above.)
In your examples above, as you noted, this means that inference fails for the calls to Test3()
and Test4()
, as in C#9.
Separately, we will investigate whether we can improve type inference (in a subsequent release) for these cases by inferring from the function type of the returned lambda or method group. If so, that should allow inference for Test3()
and Test4()
.
I will log a separate issue for that investigation.
@dotnet/roslyn-compiler, please review, thanks. |
@@ -85,18 +88,18 @@ public BoundLambda(SyntaxNode syntax, UnboundLambda unboundLambda, BoundBlock bo | |||
); | |||
} | |||
|
|||
public TypeWithAnnotations GetInferredReturnType(ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo) | |||
public TypeWithAnnotations GetInferredReturnType(ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo, bool allowInferredFromFunctionType) |
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.
|
||
TypeWithAnnotations inferredType; | ||
if (bestType is { }) | ||
{ | ||
// Note: so long as we have a best type, we can proceed. | ||
var bestTypeWithObliviousAnnotation = TypeWithAnnotations.Create(bestType); | ||
var unwrappedType = bestType is FunctionTypeSymbol functionType ? |
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.
Based on your suggestion offline, I've changed the various methods to return a TypeSymbol
and a bool
rather than requiring callers to pass in the correct value.
It looks like we can end up with Refers to: src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs:3569 in 692a53b. [](commit_id = 692a53b, deletion_comment = False) |
|
||
if (!allowInferredFromFunctionType && inferredReturnType.InferredFromFunctionType) | ||
{ | ||
return default; |
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 (commit 2) |
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 4)
bestResultType = default; | ||
break; | ||
case 1: | ||
if (conversions.IncludeNullability) | ||
{ | ||
inferredFromFunctionType = 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.
I didn't follow, why is inferredFromFunctionType
always false here?
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.
It's assumed that the caller has populated the returns
array with the actual types of the corresponding BoundExpression
(although if the caller is NullableWalker
, the types may differ by inferred nullability). That assumption is unchanged with this PR since callers did not expect this method to return a function type previously.
Do we have a follow-up issue to either make further adjustments for 17.1, or to reify the current behavior into the spec (if we choose to stick with this behavior)? |
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 4)
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 4)
Logged #57779 to investigate inferring from the function type instead. |
With C#10 currently, there is a potential breaking change from C#9 in type inference when inferring from the return type of a lambda expression when the return value is another lambda expression or a method group.
See examples in #57517 (comment) and #57630.
To avoid the breaking change, type inference is updated to not infer from the return type of a lambda if the return value is another lambda or method group. This effectively reverts the type inference behavior for those cases to the C#9 behavior.
Fixes #57630.
See also https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1437668.