-
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
Support struct records #43133
Support struct records #43133
Conversation
I believe this should work according to the spec and am just cleaning up some implementation gaps.
I see there were some recent changes to the spec which have issues (i.e. don't make sense). I cannot figure out how to add comments on those changes as there was never a PR that I could view. I don't think it is implementable as written (e.g. there is no way to "suppress" the struct default constructor on the CLR). So consider this a comment that the implementation here doesn't do that as specified. #Resolved |
@gafter I don't follow. There's no way to suppress struct default construction but we can certainly prevent surfacing a default constructor. The spec change is that the struct parameterless constructor for a record is no longer visible. #Resolved |
The C# compiler currently never produces a default constructor for a struct, so I don't know what there is to suppress (or make not visible). #Resolved |
Ah, I see, on metadata import there's no way to tell that the struct is a record, and therefore no way to avoid creating the symbol. Good point. I'll add a test for this and adjust the spec. #Resolved |
As far as I know we don't create a symbol for a struct's default constructor, but yes, you have the idea. But the problem occurs purely in source too. A |
I think we do:
|
I've adjusted the spec and implementation to preserve default struct parameterless constructors #Resolved |
@@ -1153,7 +1153,8 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum | |||
// don't emit if the resulting method would contain initializers with errors | |||
if (!hasErrors && (hasBody || includeInitializersInBody)) | |||
{ | |||
Debug.Assert(!methodSymbol.IsImplicitInstanceConstructor || !methodSymbol.ContainingType.IsStructType()); | |||
Debug.Assert(!(methodSymbol.IsImplicitInstanceConstructor && methodSymbol.ParameterCount == 0) || |
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.
IsImplicitInstanceConstructor [](start = 52, length = 29)
I think the condition IsImplicitInstanceConstructor
generally implies methodSymbol.ParameterCount == 0
, so you've weakened the assertion in case there is a mismatch there. #Resolved
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.
Not as far as I can tell: http://sourceroslyn.io/#Microsoft.CodeAnalysis.CSharp/Symbols/MethodSymbol.cs,fb6aebe573e152e2,references
That is satisfied for every record constructor as well, so all record constructors are now implicit instance constructors #Resolved
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.
Are there any other implicit instance constructors though? AFAIK, there's only the default parameterless one.
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.
Record constructors!
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.
Fair enough.
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.
Thankfully there's only one use of this property (in this assert), so we don't have to worry about that contract being violated elsewhere.
@@ -143,6 +143,9 @@ public bool SetNullableContext(byte? value) | |||
} | |||
} | |||
|
|||
private static readonly ObjectPool<PooledDictionary<Symbol, Symbol>> s_duplicateMemberSignatureDictionary = |
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.
s_duplicateMemberSignatureDictionary [](start = 77, length = 36)
Why do you need a custom pool instead of using PooledDictionary<Symbol, Symbol>.GetInstance()
? #Resolved
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.
Need a custom comparer #Resolved
public void StructRecord1() | ||
{ | ||
var src = @" | ||
data struct Point(int X, int Y);"; |
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.
data struct [](start = 0, length = 11)
I took a "data structures" class once. 😉
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.
{ | ||
// For structs: | ||
// | ||
// return param is ContainingType i ? this.Equals(in i) : false; |
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.
param is ContainingType i && this.Equals(in i)
?
src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs
Show resolved
Hide resolved
src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordConstructor.cs
Show resolved
Hide resolved
src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordObjEquals.cs
Show resolved
Hide resolved
Done review pass (commit 3). Just a couple of small points. |
I believe this should work according to the spec and am just cleaning
up some implementation gaps.
Relates to #40726 (test plan for records)