-
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
Parse lambda attributes #52038
Parse lambda attributes #52038
Conversation
src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs
Outdated
Show resolved
Hide resolved
I didn't think so. This method is only called after scanning In reply to: 804442264 [](ancestors = 804442264) Refers to: src/Compilers/CSharp/Portable/Parser/LanguageParser.cs:11311 in 6d72d30. [](commit_id = 6d72d30, deletion_comment = False) |
Currently true. Which is why In reply to: 804445349 [](ancestors = 804445349,804442264) Refers to: src/Compilers/CSharp/Portable/Parser/LanguageParser.cs:11311 in 6d72d30. [](commit_id = 6d72d30, deletion_comment = False) |
src/Compilers/CSharp/Test/Syntax/Parsing/SuppressNullableWarningExpressionParsingTests.cs
Outdated
Show resolved
Hide resolved
Done review pass (commit 2) #Closed |
src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs
Outdated
Show resolved
Hide resolved
src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs
Outdated
Show resolved
Hide resolved
Done review pass (commit 5) #Closed |
Of the proposed changes in lambda-improvements.md, does this only cover item 1? If so, is item 3 next? Between 2 and 3, 3 is a lot more important for the usability of an API taking an arbitrary |
This is just the parsing changes for 1. 3 requires no parsing changes and will come later. |
This PR covers a part of 1: parsing the attribute syntax. Changes will be needed to bind and emit attributes as well. After that, I'll focus on 3. |
Done review pass (commit 6) |
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.
LGTM (commit 8)
@dotnet/roslyn-compiler, please review, thanks. |
Looking now. |
@@ -216,6 +216,7 @@ internal enum MessageID | |||
IDS_FeatureVarianceSafetyForStaticInterfaceMembers = MessageBase + 12791, | |||
IDS_FeatureConstantInterpolatedStrings = MessageBase + 12792, | |||
IDS_FeatureMixedDeclarationsAndExpressionsInDeconstruction = MessageBase + 12793, | |||
IDS_FeatureLambdaAttributes = MessageBase + 12798, |
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.
curious why the +5 here. #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.
curious why the +5 here.
To reduce the chance of conflict with other features.
In reply to: 604497031 [](ancestors = 604497031)
@@ -11056,6 +11072,8 @@ private bool ScanExplicitlyTypedLambda(Precedence precedence) | |||
// Advance past the open paren or comma. | |||
this.EatToken(); | |||
|
|||
_ = ParseAttributeDeclarations(); |
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 is definitely so weird. i don't expect you to change this in this pr, but at this point, i think we need to rethink the whole 'scan then parse' approach we take. Now that scanning is effectively just running the parser to make its determination, we should think about just swithcing to a "just parse" approach. We'd still have rewind points, we just wouldn't be trying to duplicate the logic between these guys.
default: | ||
result = false; | ||
break; | ||
} |
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.
could just be a switch expression. #Resolved
result = IsPossibleLambdaExpressionCore(precedence); | ||
break; | ||
case SyntaxKind.OpenParenToken: | ||
result = ScanParenthesizedImplicitlyTypedLambda(precedence) || ScanExplicitlyTypedLambda(precedence); |
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.
should this go into a single ScanParenthesizedLambda helper? #Resolved
} | ||
|
||
this.Reset(ref resetPoint); | ||
this.Release(ref resetPoint); |
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.
we generally put these in finallys. is it ok that these aren't? #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.
also, if you do a try/finally, the body of this helper becomes much simpler,a nd less likely to have a problem later on (for example, if someone errantly returns). #Resolved
{ | ||
case SyntaxKind.StaticKeyword: | ||
case SyntaxKind.IdentifierToken: | ||
result = IsPossibleLambdaExpressionCore(precedence); |
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.
i don't love the assymetry here with the check above (though i grant it is correct). i would prefer another case of "== Static || IsTrueIdentifier" to make it clear tehse chunks are in sync, and aren't dependent on an internal detail of IsTrueIdentifier implying that this case is sufficient.
@@ -12233,6 +12291,7 @@ private SyntaxList<SyntaxToken> ParseAnonymousFunctionModifiers() | |||
|
|||
private LambdaExpressionSyntax ParseLambdaExpression() | |||
{ | |||
var attributes = ParseAttributeDeclarations(checkLambdaAttributesFeature: true); |
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.
so this is technically a bit unclean, but hopefully not a problem. THe main issue is that this makes attribute parsing context sensitive. We generally like avoiding that as it makes incremental difficult. Specifically, it means we couldn't jsut say "ah, we can reuse the attributes from a previous parse that are available in this location".
In your case, i think you're ok. that's bacause you'll have one of the two cases:
- the attribute decl is on a lambda before. so it will have the feature diagnostic on it, so it will crumble if we try to reparse it.
- the attribute decl is not on a lambda. it is reused in ParseAttributeDecl, but we still add the diagnostic on afterwards.
This is subtle though and easy to get wrong. in general, it can be preferable to just do the parse normally and have the caller (i.e. this method) do the check.
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 makes attribute parsing context sensitive. We generally like avoiding that as it makes incremental difficult.
I'm interested to understand how to handle the feature check in this method. Specifically, what would the resulting error be attached to that would simplify incremental parsing? (Perhaps I can address this in a subsequent PR.)
In reply to: 604500799 [](ancestors = 604500799)
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.
Parsing looks correct. I couldn't think of any cases that would be a problem. I do have some suggestions on potential simplification/safety. But as they are not necessary, it's up to you if you want to do any of them.
Parse attributes on lambda expressions and lambda parameters.
Proposal: lambda-improvements.md
Test plan: #52192