Skip to content
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

Revise compound assignment for nullable #70687

Merged
merged 4 commits into from
Nov 13, 2023

Conversation

RikkiGibson
Copy link
Contributor

@RikkiGibson RikkiGibson commented Nov 2, 2023

Addresses several nullable issues, mainly related to compound assignment. I made an effort to share code for visiting a normal binary operator with the code for visiting a compound assignment.

VisitCompoundAssignmentOperator has been pretty much rewritten only using the original code as a reference. I would recommend that you review the old and new versions of the methods separately as the diff may be a little noisy.

Other minor adjustments in the PR include:

  • simplifies disabling nullable warnings on default arguments. Eliminates a rather crufty condition in ReportNullableAssignmentIfNecessary and instead ensures that we pass along the default arguments BitVector so that we set _disableDiagnostics in the right places.
  • changed the nullable state of an assignment expression to a property with [AllowNull]. Now, any "sanitizing" of the value going into the property will not apply until the property is actually read again. This more precisely reflects the semantics of this scenario.

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Nov 2, 2023
@RikkiGibson RikkiGibson force-pushed the nullable-compound-assignment branch from 65f4906 to 8391b57 Compare November 7, 2023 00:39
@RikkiGibson RikkiGibson force-pushed the nullable-compound-assignment branch from 8391b57 to ded5ba6 Compare November 7, 2023 00:54
@RikkiGibson RikkiGibson marked this pull request as ready for review November 7, 2023 01:35
@RikkiGibson RikkiGibson requested a review from a team as a code owner November 7, 2023 01:35
node.Operator.Kind,
node.Operator.Method,
node.Operator.ReturnType ?? node.Type,
node.LeftConversion as BoundConversion ?? node.Left,
Copy link
Member

Choose a reason for hiding this comment

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

as BoundConversion

Is as BoundConversion necessary? What else might this be other than a BoundConversion or null?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

<!-- Could be a BoundConversion or, in some cases of an identity conversion, the LeftPlaceholder, or null for no conversion case -->
<Field Name="LeftConversion" Type="BoundExpression?" SkipInVisitor="true" Null="allow"/>

The other possibility is that it is a BoundPlaceholder, which to me didn't make sense to visit as if the operand is really being operated on by that placeholder. However, I don't think I tested to see what happens when we remove the as BoundConversion.

Copy link
Member

Choose a reason for hiding this comment

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

nit: No test is affected by the removal of as BoundConversion. It'd be good to hunt one down.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Opened #70751 to try and find a scenario which could be used as a starting point. I probably will not block the PR on it, though.

AdjustSetValue(left, ref resultType);
TrackNullableStateForAssignment(node, leftLValueType, MakeSlot(node.Left), resultType);
AdjustSetValue(node.Left, ref resultTypeWithState);
Debug.Assert(MakeSlot(node) == -1);
Copy link
Member

Choose a reason for hiding this comment

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

Debug.Assert(MakeSlot(node) == -1);

Just curious: Why assert this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wanted to indicate that the value stored in the LHS of the compound-assignment effectively drops any "sub-slot" information in either operand of the compound-assignment, i.e. the nullable state of fields of the operands. Showing that the entire compound-assignment never has a slot felt useful. See test CompoundAssignment_SubSlots.

Copy link
Member

@cston cston Nov 7, 2023

Choose a reason for hiding this comment

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

In that case, shouldn't the assert use node.Left rather than node? (I don't think we ever create slots for binary operators.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

A regular assignment can have a slot.

It's possible a compound assignment should have a slot for the same reason but I feel comfortable punting on it.

https://sharplab.io/#v2:CYLg1APgAgTAjAWAFBQMwAJboMLoN7LpGYZQAs6AsgBRRwAMA/OgB4A0mDzAnh3U+gBeASnyFiEgJYAzdNWot0AXnTdRAQhUA7AK4AbPaJYA6ACoB7AMoAXAE6StAc2rCA3OIlETFm/acv3JAkAX2RgoA===

comp.VerifyEmitDiagnostics();
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65546")]
Copy link
Member

Choose a reason for hiding this comment

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

#65546

70646?

// (19,9): warning CS8602: Dereference of a possibly null reference.
// c1.f3.ToString(); // 3
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c1.f3").WithLocation(19, 9));
}
Copy link
Member

Choose a reason for hiding this comment

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

}

Should we test the following as well?

class C
{
    public string f1, f2, f3;
}
C c1 = new() { f1 = null, f2 = null }; // 1, 2
C c2 = new() { f1 = null, f3 = null }; // 3, 4
c1 += c2;
c1.f1.ToString();
c1.f2.ToString();
c1.f3.ToString();

@jcouv jcouv self-assigned this Nov 8, 2023
@RikkiGibson RikkiGibson requested a review from jcouv November 8, 2023 19:31
Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

LGTM Thanks (iteration 3)

@RikkiGibson RikkiGibson merged commit fb1b83f into dotnet:main Nov 13, 2023
@ghost ghost added this to the Next milestone Nov 13, 2023
@RikkiGibson RikkiGibson deleted the nullable-compound-assignment branch November 13, 2023 20:25
@RikkiGibson RikkiGibson modified the milestones: Next, 17.9 P2 Nov 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
3 participants