Skip to content

Zero fields before running field initializers in struct constructor with default : this() initializer#60471

Merged
RikkiGibson merged 7 commits intodotnet:release/dev17.2from
cston:58790
Mar 31, 2022
Merged

Zero fields before running field initializers in struct constructor with default : this() initializer#60471
RikkiGibson merged 7 commits intodotnet:release/dev17.2from
cston:58790

Conversation

@cston
Copy link
Copy Markdown
Contributor

@cston cston commented Mar 30, 2022

From the dotnet/csharplang proposal:

When a struct instance constructor has a this() constructor initializer that represents the default parameterless constructor, the declared constructor implicitly clears all instance fields and performs the initializations specified by the variable_initializers of the instance fields declared in its struct. Immediately upon entry to the constructor, all value type fields are set to their default value and all reference type fields are set to null. Immediately after that, a sequence of assignments corresponding to the variable_initializers are executed.

Fixes #58790

@cston cston marked this pull request as ready for review March 30, 2022 06:03
@cston cston requested a review from a team as a code owner March 30, 2022 06:03
@RikkiGibson RikkiGibson self-assigned this Mar 30, 2022
@cston cston requested review from AlekseyTs and RikkiGibson March 30, 2022 18:06
Copy link
Copy Markdown
Member

@RikkiGibson RikkiGibson left a comment

Choose a reason for hiding this comment

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

LGTM, however we did discuss offline whether it's possible to make the change simpler by keeping the existing constructor initializer code path the same and adjusting the path that adds field initializers to the body to do a special check for the default parameterless constructor. Would like to see whether any changes are made as a result of that exploration before signing off.

comp.VerifyDiagnostics(
// (10,12): error CS0171: Field 'S1.y' must be fully assigned before control is returned to the caller
// public S1() { }
Diagnostic(ErrorCode.ERR_UnassignedThis, "S1").WithArguments("S1.y").WithLocation(10, 12),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's make sure we keep an eye out after this is merged to update the test baselines when this flows forward to 17.3/main-vs-deps.

Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "y1").WithArguments("S1.y1").WithLocation(3, 14),
// (3,14): error CS0170: Use of possibly unassigned field 'y1'
// int x1 = y1 + 1;
Diagnostic(ErrorCode.ERR_UseDefViolationField, "y1").WithArguments("y1").WithLocation(3, 14),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Many of the new [Theory] tests will have divergent diagnostics when this flows to main-vs-deps. The tests can still be written this way, just wanted to call it out.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It looks like there are 5 or so tests that will be affected. But it might simpler if I leave these combined for now, then split them when merging into main.

bodyBinder.GetDeclaredLocalsForScope(constructor),
skipInitializer ? new BoundNoOpStatement(constructor, NoOpStatementFlavor.Default)
: initializer == null ? null : bodyBinder.BindConstructorInitializer(initializer, diagnostics),
initializer == null ? null : bodyBinder.BindConstructorInitializer(initializer, diagnostics),
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Mar 30, 2022

Choose a reason for hiding this comment

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

initializer == null ? null : bodyBinder.BindConstructorInitializer(initializer, diagnostics),

Is this change observable in IOperation tree? Consider adding a test. #Closed

@cston
Copy link
Copy Markdown
Contributor Author

cston commented Mar 30, 2022

make the change simpler by keeping the existing constructor initializer code path the same and adjusting the path that adds field initializers to the body

The current approach combines the constructor initializer and body (into a BoundConstructorMethodBody) in Binder.BindConstructorBody and then inserts the field initializers between the two sets of statements a couple of callers higher in MethodCompiler.CompileMethod. But in between, MethodCompiler.BindMethodBody also generates the methodBodyForSemanticModel from the BoundConstructorMethodBody so it feels like that method body should include the constructor initializer as it would for any other constructor initializer case.


In reply to: 925601353

@AlekseyTs
Copy link
Copy Markdown
Contributor

I also like the clean-up in the Binder and prefer if we go with that.


In reply to: 1083707550

{
int x = 1;
int y;
public S(int y) : this()
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Mar 30, 2022

Choose a reason for hiding this comment

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

public S(int y) : this()

Is this a scenario that used to be an error? #Closed

Copy link
Copy Markdown
Contributor Author

@cston cston Mar 30, 2022

Choose a reason for hiding this comment

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

Yes, previously:

(6,12): error CS0171: Field 'S.y' must be fully assigned before control is returned to the caller
     public S(int y) : this()
(15,12): error CS0171: Field 'R.y' must be fully assigned before control is returned to the caller
     public R(int y) : this()

Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs 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 6)

@cston
Copy link
Copy Markdown
Contributor Author

cston commented Mar 31, 2022

The failure in Test_Windows_Desktop_Spanish_Release_64 appears to be a known infrastructure issue.

@RikkiGibson RikkiGibson merged commit afe5eef into dotnet:release/dev17.2 Mar 31, 2022
@cston cston deleted the 58790 branch March 31, 2022 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants