Enforce nullability contract in lambda body#56590
Enforce nullability contract in lambda body#56590jcouv merged 11 commits intodotnet:release/dev17.0from
Conversation
40a2b89 to
2c450c7
Compare
| } | ||
| } | ||
|
|
||
| void enforceNotNullWhenForPendingReturn(PendingBranch pendingReturn, BoundReturnStatement returnStatement) |
There was a problem hiding this comment.
📝 The local functions were extracted mostly without modification (except for naming changes and tweak to location reported for WRN_ParameterDisallowsNull)
7c3908a to
7bec213
Compare
7bec213 to
c082359
Compare
| Debug.Assert(!useDelegateInvokeReturnType || delegateInvokeMethod is object); | ||
|
|
||
| var oldSymbol = this.CurrentSymbol; | ||
| var oldSymbol = this._symbol; |
There was a problem hiding this comment.
📝 _symbol drives various APIs, such as MethodParameters #Resolved
There was a problem hiding this comment.
Did you consider modifying the relevant APIs to instead check CurrentSymbol?
There was a problem hiding this comment.
Took another look, but the comment on _symbol says its primary purpose is to provide method parameters and return type. So I think this is correct.
c082359 to
4220574
Compare
56a06e4 to
d5b9c77
Compare
d5b9c77 to
0f4fdb7
Compare
| } | ||
|
|
||
| [Fact, WorkItem(52827, "https://github.com/dotnet/roslyn/issues/52827")] | ||
| public void FunctionTypeConversion_NullableAttributes() |
| /// 'MethodParameters', 'MethodThisParameter' and 'AnalyzeOutParameters(...)' should be used | ||
| /// instead. _symbol is null during speculative binding. | ||
| /// </summary> | ||
| protected readonly Symbol _symbol; |
There was a problem hiding this comment.
Yes, I think so, as it drives separate APIs, like MethodParameters which are used by existing helpers for nullability checks.
| } | ||
|
|
||
| void reportParameterIfBadConditionalState(SyntaxNode syntax, ParameterSymbol parameter, bool sense, LocalState stateWhen) | ||
| void EnforceParameterNotNullOnExit(SyntaxNode? syntaxOpt, LocalState state) |
| } | ||
| } | ||
|
|
||
| void EnforceNotNullWhenForPendingReturn(PendingBranch pendingReturn, BoundReturnStatement returnStatement) |
| { | ||
| if (!unboundLambda.HasExplicitlyTypedParameterList) | ||
| MethodSymbol targetInvokeMethod = delegateType.DelegateInvokeMethod; | ||
| MethodSymbol sourceInvokeMethod = (MethodSymbol)lambda.ExpressionSymbol; |
| compilation, | ||
| sourceInvokeMethod, | ||
| targetInvokeMethod, | ||
| new BindingDiagnosticBag(Diagnostics), |
| Func<object?> f9 = [return: NotNull] () => null; // 5 | ||
| D1 f10 = [return: NotNull] () => null; | ||
| D2 f11 = [return: NotNull] () => null; // 6 | ||
| D3 f12 = [return: NotNull] () => null; |
There was a problem hiding this comment.
Are these cases distinct from f6, f7, f8? #Closed
| _ = new Func<object?>([return: NotNull] () => null); // 5 | ||
| _ = new D1([return: NotNull] () => null); | ||
| _ = new D2([return: NotNull] () => null); // 6 | ||
| _ = new D3([return: NotNull] () => null); |
There was a problem hiding this comment.
Are these cases distinct from the three above? #Closed
| Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOfTargetDelegate, "([NotNullWhen(true)] out object? obj) =>").WithArguments("obj", "lambda expression", "D").WithLocation(10, 15), | ||
| // (13,17): warning CS8762: Parameter 'obj' must have a non-null value when exiting with 'true'. | ||
| // return true; | ||
| Diagnostic(ErrorCode.WRN_ParameterConditionallyDisallowsNull, "return true;").WithArguments("obj", "true").WithLocation(13, 17) |
There was a problem hiding this comment.
One lambda returns true with obj=null and the other returns false. So only one of them reports this warning.
|
@RikkiGibson Gentle ping to take a look. Thanks |
| } | ||
| }"; | ||
| // Wrong lambda conversion warnings tracked by https://github.com/dotnet/roslyn/issues/56668 | ||
| // We're expecting WRN_NullabilityMismatchInReturnTypeOfTargetDelegate for each commented line |
There was a problem hiding this comment.
I'm not 100% sure I understood. Does this mean that this baseline is missing a single diagnostic for each // n comment above? And the commented lines are not meant to indicate the entire set of expected diagnostics? #Resolved
There was a problem hiding this comment.
That's correct. We should have one WRN_NullabilityMismatchInReturnTypeOfTargetDelegate for each commented line (and only those lines). Other lines have different warnings which are not the focus on this test.
There was a problem hiding this comment.
Or is it more that the "check nullable attributes in lambda conversion" was implemented, the commented lines were added, then the conversion check was punted out, and the commented lines were intentionally not updated?
There was a problem hiding this comment.
Your description is also correct (another way to say the same thing).
| // (9,28): warning CS8621: Nullability of reference types in return type of 'lambda expression' doesn't match the target delegate 'Func<string?>' (possibly because of nullability attributes). | ||
| // Func<string?> f3 = string () => default!; | ||
| Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOfTargetDelegate, "string () => default!").WithArguments("lambda expression", "System.Func<string?>").WithLocation(9, 28)); | ||
| Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOfTargetDelegate, "string () =>").WithArguments("lambda expression", "System.Func<string?>").WithLocation(9, 28)); |
There was a problem hiding this comment.
Removing the lambda body from the diagnostic span seems like a good change. #Resolved
| assert(o2 is not null); | ||
| o2.ToString(); | ||
|
|
||
| // Note: no enforcement on method body for DoesNotReturnIf |
There was a problem hiding this comment.
Was this limitation intentional? Or the functionality was punted out? #Resolved
There was a problem hiding this comment.
I think we failed to find a design for that enforcement (if I recall correctly it's not possible for a reasonable cost).
| } | ||
| } | ||
| "; | ||
| var comp = CreateCompilation(new[] { source, AllowNullAttributeDefinition }); |
There was a problem hiding this comment.
Should we also have a comment here that the missing warning will be handled in a follow-up? #Resolved
| var comp = CreateCompilation(source); | ||
| comp.VerifyDiagnostics( | ||
| // (11,14): warning CS8622: Nullability of reference types in type of parameter 'o' of 'lambda expression' doesn't match the target delegate 'Action<object>' (possibly because of nullability attributes). | ||
| // a1 = (object? o) => { }; // warning |
There was a problem hiding this comment.
nit: it looks like // warning comments are present in this test baseline but not in the source code. #Resolved
RikkiGibson
left a comment
There was a problem hiding this comment.
LGTM. Would be nice if we could address CurrentSymbol vs _symbol in this PR but can be punted if necessary.
|
Re-targeted to |
Fixes #52827 (Enforce nullability attributes in lambda body)
Fixes #47896 (Enforce nullability attributes in local function body)
Fixes #45814 (Enforce DoesNotReturn in local function body)
Fixes #52598 (Enforce DoesNotReturn in local function body)
Fixes #55649 (Roslyn fails to verify nullable attributes on lambda expressions in delegate conversions)
Per discussion with Jared and Chuck, I'm pulling out the part of the change that relates to conversions. Opened #56668 to track this change in 17.1.
Relates to test plan #52192