-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Record structs: add properties and primary ctor #51720
Changes from 1 commit
07f6466
d0789ad
dd9069b
9bec338
244a64a
caccbb3
04b39e9
f2b8433
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -140,8 +140,7 @@ internal Binder GetBinder(SyntaxNode node, int position, CSharpSyntaxNode member | |
|
||
internal InMethodBinder GetRecordConstructorInMethodBinder(SynthesizedRecordConstructor constructor) | ||
{ | ||
// PROTOTYPE(record-structs): update for record structs | ||
RecordDeclarationSyntax typeDecl = constructor.GetSyntax(); | ||
TypeDeclarationSyntax typeDecl = constructor.GetSyntax(); | ||
|
||
var extraInfo = NodeUsage.ConstructorBodyOrInitializer; | ||
var key = BinderFactoryVisitor.CreateBinderCacheKey(typeDecl, extraInfo); | ||
|
@@ -158,8 +157,10 @@ internal InMethodBinder GetRecordConstructorInMethodBinder(SynthesizedRecordCons | |
return (InMethodBinder)resultBinder; | ||
} | ||
|
||
internal Binder GetInRecordBodyBinder(RecordDeclarationSyntax typeDecl) | ||
internal Binder GetInRecordBodyBinder(TypeDeclarationSyntax typeDecl) | ||
{ | ||
Debug.Assert(typeDecl.Kind() is SyntaxKind.RecordDeclaration or SyntaxKind.RecordStructDeclaration); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It feels like we should never call this method for a record struct. #Closed |
||
|
||
BinderFactoryVisitor visitor = _binderFactoryVisitorPool.Allocate(); | ||
visitor.Initialize(position: typeDecl.SpanStart, memberDeclarationOpt: null, memberOpt: null); | ||
Binder resultBinder = visitor.VisitTypeDeclarationCore(typeDecl, NodeUsage.NamedTypeBodyOrTypeParameters); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3286,10 +3286,12 @@ public virtual BoundNode BindMethodBody(CSharpSyntaxNode syntax, BindingDiagnost | |
{ | ||
switch (syntax) | ||
{ | ||
// PROTOTYPE(record-structs): update for record structs | ||
case RecordDeclarationSyntax recordDecl: | ||
return BindRecordConstructorBody(recordDecl, diagnostics); | ||
|
||
case RecordStructDeclarationSyntax recordDecl: | ||
return BindRecordStructConstructorBody(recordDecl); | ||
RikkiGibson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
case BaseMethodDeclarationSyntax method: | ||
if (method.Kind() == SyntaxKind.ConstructorDeclaration) | ||
{ | ||
|
@@ -3356,6 +3358,20 @@ private BoundNode BindRecordConstructorBody(RecordDeclarationSyntax recordDecl, | |
expressionBody: null); | ||
} | ||
|
||
private BoundNode BindRecordStructConstructorBody(RecordStructDeclarationSyntax recordStructDecl) | ||
{ | ||
Debug.Assert(recordStructDecl.ParameterList is object); | ||
|
||
Binder bodyBinder = this.GetBinder(recordStructDecl); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It doesn't look like the binder is needed #Closed |
||
Debug.Assert(bodyBinder != null); | ||
|
||
return new BoundConstructorMethodBody(recordStructDecl, | ||
bodyBinder.GetDeclaredLocalsForScope(recordStructDecl), | ||
initializer: null, | ||
blockBody: new BoundBlock(recordStructDecl, ImmutableArray<LocalSymbol>.Empty, ImmutableArray<BoundStatement>.Empty).MakeCompilerGenerated(), | ||
expressionBody: null); | ||
} | ||
|
||
internal virtual BoundExpressionStatement BindConstructorInitializer(PrimaryConstructorBaseTypeSyntax initializer, BindingDiagnosticBag diagnostics) | ||
{ | ||
BoundExpression initializerInvocation = GetBinder(initializer).BindConstructorInitializer(initializer.ArgumentList, (MethodSymbol)this.ContainingMember(), diagnostics); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -103,6 +103,7 @@ internal override BoundNode Bind(Binder binder, CSharpSyntaxNode node, BindingDi | |
case SyntaxKind.RemoveAccessorDeclaration: | ||
case SyntaxKind.CompilationUnit: | ||
case SyntaxKind.RecordDeclaration: | ||
case SyntaxKind.RecordStructDeclaration: | ||
RikkiGibson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return binder.BindMethodBody(node, diagnostics); | ||
} | ||
|
||
|
@@ -270,7 +271,8 @@ internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticMode | |
internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out SemanticModel speculativeModel) | ||
{ | ||
if (MemberSymbol is SynthesizedRecordConstructor primaryCtor && | ||
Root.FindToken(position).Parent?.AncestorsAndSelf().OfType<PrimaryConstructorBaseTypeSyntax>().FirstOrDefault() == primaryCtor.GetSyntax().PrimaryConstructorBaseType) | ||
primaryCtor.GetSyntax() is RecordDeclarationSyntax recordDecl && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it expected that we can't get a speculative model for a record struct here? #Resolved There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The logic here relates to the primary constructor base type, which doesn't exist for record structs. That's why we only need to handle record classes here. In reply to: 589956647 [](ancestors = 589956647) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Alternatively we could check if the containing type is a class. #Closed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the current approach is okay and relatively compact. In reply to: 590762612 [](ancestors = 590762612) |
||
Root.FindToken(position).Parent?.AncestorsAndSelf().OfType<PrimaryConstructorBaseTypeSyntax>().FirstOrDefault() == recordDecl.PrimaryConstructorBaseType) | ||
{ | ||
var binder = this.GetEnclosingBinder(position); | ||
if (binder != null) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1912,8 +1912,8 @@ internal static BoundExpression BindImplicitConstructorInitializer( | |
NamedTypeSymbol baseType = constructor.ContainingType.BaseTypeNoUseSiteDiagnostics; | ||
|
||
SourceMemberMethodSymbol sourceConstructor = constructor as SourceMemberMethodSymbol; | ||
// PROTOTYPE(record-structs): update for record structs | ||
Debug.Assert(sourceConstructor?.SyntaxNode is RecordDeclarationSyntax || ((ConstructorDeclarationSyntax)sourceConstructor?.SyntaxNode)?.Initializer == null); | ||
Debug.Assert(sourceConstructor?.SyntaxNode is RecordDeclarationSyntax or RecordStructDeclarationSyntax | ||
|| ((ConstructorDeclarationSyntax)sourceConstructor?.SyntaxNode)?.Initializer == null); | ||
|
||
// The common case is that the type inherits directly from object. | ||
// Also, we might be trying to generate a constructor for an entirely compiler-generated class such | ||
|
@@ -1963,9 +1963,9 @@ internal static BoundExpression BindImplicitConstructorInitializer( | |
CSharpSyntaxNode containerNode = constructor.GetNonNullSyntaxNode(); | ||
BinderFactory binderFactory = compilation.GetBinderFactory(containerNode.SyntaxTree); | ||
|
||
if (containerNode is RecordDeclarationSyntax recordDecl) | ||
if (containerNode is RecordDeclarationSyntax or RecordStructDeclarationSyntax) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It feels like the change is not necessary, assuming we return null above. #Closed |
||
{ | ||
outerBinder = binderFactory.GetInRecordBodyBinder(recordDecl); | ||
outerBinder = binderFactory.GetInRecordBodyBinder((TypeDeclarationSyntax)containerNode); | ||
} | ||
else | ||
{ | ||
|
@@ -1991,6 +1991,10 @@ internal static BoundExpression BindImplicitConstructorInitializer( | |
outerBinder = binderFactory.GetInRecordBodyBinder(recordDecl); | ||
break; | ||
|
||
case RecordStructDeclarationSyntax recordStructDecl: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It feels like the change is not necessary, assuming we return null above. #Closed |
||
outerBinder = binderFactory.GetInRecordBodyBinder(recordStructDecl); | ||
break; | ||
|
||
default: | ||
throw ExceptionUtilities.Unreachable; | ||
} | ||
|
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.
Consider asserting that this is not a record struct #Closed