-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Improve error recovery for incomplete attribute in a type-parameter. #81231
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
Changes from all commits
3a09a5d
c780868
a95e595
51cfa91
bd67526
8fc6527
0a0d8ce
78d6908
13d6ec2
286d305
01e2862
92b1b54
acd2b5b
8a38ae5
fd5d3d1
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 |
|---|---|---|
|
|
@@ -6028,36 +6028,34 @@ private bool IsStartOfTypeParameter() | |
| if (this.IsCurrentTokenWhereOfConstraintClause()) | ||
| return false; | ||
|
|
||
| // possible attributes | ||
| if (this.CurrentToken.Kind == SyntaxKind.OpenBracketToken && this.PeekToken(1).Kind != SyntaxKind.CloseBracketToken) | ||
| return true; | ||
|
|
||
| // possible attributes. | ||
| // Variance. | ||
| if (this.CurrentToken.Kind is SyntaxKind.InKeyword or SyntaxKind.OutKeyword) | ||
| if (this.CurrentToken.Kind is SyntaxKind.OpenBracketToken or SyntaxKind.InKeyword or SyntaxKind.OutKeyword) | ||
| return true; | ||
|
|
||
| return IsTrueIdentifier(); | ||
| } | ||
|
|
||
| private TypeParameterSyntax ParseTypeParameter() | ||
| { | ||
| if (this.IsCurrentTokenWhereOfConstraintClause()) | ||
| { | ||
| return _syntaxFactory.TypeParameter( | ||
| default(SyntaxList<AttributeListSyntax>), | ||
| varianceKeyword: null, | ||
| this.AddError(CreateMissingIdentifierToken(), ErrorCode.ERR_IdentifierExpected)); | ||
| } | ||
|
|
||
| var attrs = default(SyntaxList<AttributeListSyntax>); | ||
| if (this.CurrentToken.Kind == SyntaxKind.OpenBracketToken && this.PeekToken(1).Kind != SyntaxKind.CloseBracketToken) | ||
| if (this.CurrentToken.Kind == SyntaxKind.OpenBracketToken) | ||
| { | ||
| var saveTerm = _termState; | ||
| _termState = TerminatorState.IsEndOfTypeArgumentList; | ||
| attrs = this.ParseAttributeDeclarations(inExpressionContext: false); | ||
| _termState = saveTerm; | ||
| } | ||
|
|
||
| if (this.IsCurrentTokenWhereOfConstraintClause() || | ||
| this.IsCurrentTokenPartialKeywordOfPartialMemberOrType()) | ||
|
Member
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's not obvious why "partial" is getting special treatment. Should we similarly care about other modifier keywords?
Member
Author
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. partial/where refer to the special identifiers that IsTrueIdentifier returns false for if it sees that these should not actually be treated as identifiers but as contextual keywords. They're treated specially here as they are very reasonable contextual keywords that would follow a type param being written. |
||
| { | ||
| return _syntaxFactory.TypeParameter( | ||
| attrs, | ||
| varianceKeyword: null, | ||
| this.AddError(CreateMissingIdentifierToken(), ErrorCode.ERR_IdentifierExpected)); | ||
| } | ||
|
|
||
| return _syntaxFactory.TypeParameter( | ||
| attrs, | ||
| this.CurrentToken.Kind is SyntaxKind.InKeyword or SyntaxKind.OutKeyword ? EatToken() : null, | ||
|
|
||
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 blocks good error recovery in the
Foo<[]T>case. There isn't a good reason for this, as[]isn't a suitable start of some other construct. In all other attribute cases, running into[]is supported, just not for type params.This simply removes that restriction, and gives consistent support for attributes here like everywhere else.