Skip to content

Update null state for add/remove on field-like events#46477

Merged
RikkiGibson merged 5 commits intodotnet:masterfrom
RikkiGibson:nullable-event-assignment
Aug 7, 2020
Merged

Update null state for add/remove on field-like events#46477
RikkiGibson merged 5 commits intodotnet:masterfrom
RikkiGibson:nullable-event-assignment

Conversation

@RikkiGibson
Copy link
Member

@RikkiGibson RikkiGibson commented Jul 31, 2020

Fixes #42557

This work supports the new nullable constructor analysis, since we need to be able to tell that an event no longer contains 'null' after a non-null delegate is added to it.

🦔

@RikkiGibson RikkiGibson marked this pull request as ready for review July 31, 2020 18:37
@RikkiGibson RikkiGibson requested a review from a team as a code owner July 31, 2020 18:37
@RikkiGibson
Copy link
Member Author

Please take a look @dotnet/roslyn-compiler

1 similar comment
@RikkiGibson
Copy link
Member Author

Please take a look @dotnet/roslyn-compiler

@RikkiGibson
Copy link
Member Author

Please review @dotnet/roslyn-compiler

{
if (ResultType.IsNotNull)
{
LearnFromNonNullTest(MakeMemberSlot(receiverOpt, @event), ref State);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MakeMemberSlot(receiverOpt, @event) [](start = 45, length = 35)

Does LearnFromNonNullTest() handle an invalid slot? For instance, F().E += () => { };

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like no, not really, and we don't have any debug asserts preventing e.g. this.State[-1] = .... When we write it through to the BitVector, it ends up getting bit-shifted into something arbitrary and undesirable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logged #46621 to fix BitVector.this[int].

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have made the change to only try and update state if we have a valid member slot.

}
else
{
this.State[memberSlot] = NullableFlowState.MaybeNull;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to change these to more direct state modifications because event assignment is more limited in what it can operate on. For example the LHS of an event assignment must be an lvalue, so it can't be a conditional-access expression like x?.y += SomeDelegate.

If this feels wrong from a coding patterns POV we can change this to use the LearnFromNullTest/LearnFromNonNullTest or some other more appropriate helpers that I may have overlooked in NullableWalker.

{
if (node.IsAddition)
{
this.State[memberSlot] = this.State[memberSlot].Meet(ResultType.State);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we should using SetResult to set these, rather than updating the state directly like this. Please add some tests that observe the change in field-like event's nullability from the public API.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed offline, and the difficulty is that it's not clear what bound node would be passed to SetResult. Will add the test.

VisitRvalue(node.Argument);
// https://github.com/dotnet/roslyn/issues/31018: Check for delegate mismatch.
if (node.Argument.ConstantValue?.IsNull != true
&& MakeMemberSlot(receiverOpt, @event) is not -1 and var memberSlot)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is not -1 [](start = 55, length = 9)

Consider using is > 0 for consistency with other checks.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

else
{
this.State[memberSlot] = NullableFlowState.MaybeNull;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps use conditional: this.State[memberSlot] = node.IsAddition ? ... : ...;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


var lhs = root.DescendantNodes().OfType<AssignmentExpressionSyntax>().Single().Left;
typeInfo = model.GetTypeInfo(lhs);
Assert.Equal(PublicNullableAnnotation.None, typeInfo.Type.NullableAnnotation);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a bug, can you file to follow up?

Copy link
Member

@333fred 333fred left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (commit 5)

@RikkiGibson
Copy link
Member Author

I have the required sign offs and the CI failure is due to a known flaky test, so I will just merge the PR.

@RikkiGibson RikkiGibson merged commit a433234 into dotnet:master Aug 7, 2020
@ghost ghost added this to the Next milestone Aug 7, 2020
@RikkiGibson RikkiGibson deleted the nullable-event-assignment branch August 7, 2020 23:18
333fred added a commit that referenced this pull request Aug 10, 2020
…features/function-pointers

* upstream/master: (465 commits)
  Stop specifying Rich Nav's version of dotnet
  Fix nullable reference warning
  Fix up some calls to SymbolKey.Resolve now that it's annotated
  Remove try/catch of ArgumentException
  Null annotate SymbolKey
  Annotate Location.IsInSource as ensuring SourceTree is non-null
  Fix nullable annotation of Compilation.CreateErrorTypeSymbol
  Update null state for add/remove on field-like events (#46477)
  Throw IndexOutOfRangeException from BitVector.this[int] if index < 0 (#46627)
  Delete some dead support for changing legacy options
  Delete our use of Microsoft.VisualStudio.CodingConventions
  Fix crash in the preview of a code action that modified an .editorconfig
  Move null check above where the variable is used (#46558)
  Add integration test to configure diagnostic severity via editorconfig
  Disable a few Mac tests
  Consider nullability in conversion to constraint type (#46405)
  Added interpolated strings and tests
  Introduce request context (#46557)
  Simplify NativeIntegerAttribute encoding (#46522)
  Update extension getenumerator status. (#46607)
  ...
@RikkiGibson RikkiGibson modified the milestones: Next, 16.8.P2 Aug 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Roslyn doesn't correctly update nullability on += operators for events

3 participants