-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Short term field keyword nullable analysis #75246
Conversation
Test failure appears to be just the following
I will try to address tomorrow. |
// Share a slot between backing field and associated property/event in the context of a constructor which owns initialization of that backing field. | ||
if (this._symbol is MethodSymbol constructor | ||
&& constructor.IsConstructor() | ||
&& constructor.IsStatic == symbol.IsStatic) |
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.
This check is only really going to be relevant in a scenario like the following:
- static property is used in instance constructor, and
- somehow, backing field of the same static property is also used in instance constructor. I think this is not possible.
I am adding some tests to poke at that area, but, even if the tests don't show the necessity of the check, I think I will feel more comfortable having it there.
|
||
var comp = CreateCompilation(source); | ||
comp.VerifyEmitDiagnostics( | ||
// (6,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. |
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.
Hmm. Existing problem, but you can't exactly mark Prop
as required...
} | ||
|
||
[Fact] | ||
public void Nullability_07() |
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.
The goal of this separation was to test the constructor exit checks separately from testing field flow state being reflected when reading the property.
[MaybeNull, AllowNull] | ||
public string Prop | ||
{ | ||
get => field.ToString(); // 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.
} | ||
|
||
[Fact] | ||
public void Nullability_20_ManualGetter_AutoSetter_NullTest() |
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.
The goal is to demonstrate that a null-test+throw on the property puts a non-nullable field into the correct state. Adding a version without initializer to demonstrate that more clearly.
Part of #75244
I found that the dotnet/csharplang#8425 did not really include enough details to attack the attribute problem.
Basically, we have a precedent with auto properties using nullable attributes, that the field is subject to those same attributes in the same way. For example,
[AllowNull] string Prop { get; set; } = null;
is valid, even though the= null
is assigning to the backing field rather than the auto-prop which claims to accept null.However, our goal with the field keyword nullability proposal was to allow customizing the field's nullability independently of the property. Therefore, I have arrived at the following principle:
field
keyword,field:
targeted nullability attributes are ignored, and the attributes from the property are used for the field instead. Essentially, the field is not a distinct thing from the property for the purposes of nullable analysis.field
keyword, the field is a distinct thing.field:
targeted nullability attributes are used on the field, and nullability attributes on the property are not applied to the field.[AllowNull] string Prop { get => field; set => field = value } = null;
results in a warning--since the initializer is assigning to the field, and the AllowNull doesn't apply to the field.if (Prop is null) throw ...;
is used, to ensure that the property is in the correct state before exiting the constructor.The short term solution reflects the need for user to specify whether the field is nullable or not independently of the property. When we introduce a solution which infers the field's nullability across members, we expect the need for the user to specify will disappear in most cases.