-
Notifications
You must be signed in to change notification settings - Fork 441
Add diagnostic for misplaced specifiers #947
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
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 |
---|---|---|
|
@@ -32,8 +32,8 @@ extension Parser { | |
/// type → self-type | ||
/// type → '(' type ')' | ||
@_spi(RawSyntax) | ||
public mutating func parseType() -> RawTypeSyntax { | ||
let type = self.parseTypeScalar() | ||
public mutating func parseType(misplacedSpecifiers: [RawTokenSyntax] = []) -> RawTypeSyntax { | ||
let type = self.parseTypeScalar(misplacedSpecifiers: misplacedSpecifiers) | ||
|
||
// Parse pack expansion 'T...'. | ||
if self.currentToken.isEllipsis { | ||
|
@@ -47,8 +47,8 @@ extension Parser { | |
return type | ||
} | ||
|
||
mutating func parseTypeScalar() -> RawTypeSyntax { | ||
let (specifier, attrList) = self.parseTypeAttributeList() | ||
mutating func parseTypeScalar(misplacedSpecifiers: [RawTokenSyntax] = []) -> RawTypeSyntax { | ||
let (specifier, attrList) = self.parseTypeAttributeList(misplacedSpecifiers: misplacedSpecifiers) | ||
var base = RawTypeSyntax(self.parseSimpleOrCompositionType()) | ||
if self.lookahead().isAtFunctionTypeArrow() { | ||
let firstEffect = self.parseEffectsSpecifier() | ||
|
@@ -402,7 +402,11 @@ extension Parser { | |
let second: RawTokenSyntax? | ||
let unexpectedBeforeColon: RawUnexpectedNodesSyntax? | ||
let colon: RawTokenSyntax? | ||
if self.lookahead().startsParameterName(false) { | ||
var misplacedSpecifiers: [RawTokenSyntax] = [] | ||
if self.withLookahead({ $0.startsParameterName(isClosure: false, allowMisplacedSpecifierRecovery: true) }) { | ||
while let specifier = self.consume(ifAnyIn: TypeSpecifier.self) { | ||
misplacedSpecifiers.append(specifier) | ||
} | ||
first = self.parseArgumentLabel() | ||
if let parsedColon = self.consume(if: .colon) { | ||
second = nil | ||
|
@@ -423,12 +427,13 @@ extension Parser { | |
colon = nil | ||
} | ||
// Parse the type annotation. | ||
let type = self.parseType() | ||
let type = self.parseType(misplacedSpecifiers: misplacedSpecifiers) | ||
let ellipsis = self.currentToken.isEllipsis ? self.consumeAnyToken() : nil | ||
let trailingComma = self.consume(if: .comma) | ||
keepGoing = trailingComma != nil | ||
elements.append(RawTupleTypeElementSyntax( | ||
inOut: nil, | ||
RawUnexpectedNodesSyntax(misplacedSpecifiers, arena: self.arena), | ||
name: first, | ||
secondName: second, | ||
unexpectedBeforeColon, | ||
|
@@ -593,7 +598,7 @@ extension Parser.Lookahead { | |
|
||
// If the tuple element starts with "ident :", then it is followed | ||
// by a type annotation. | ||
if self.startsParameterName(/*isClosure=*/false) { | ||
if self.startsParameterName(isClosure: false, allowMisplacedSpecifierRecovery: false) { | ||
self.consumeAnyToken() | ||
if self.currentToken.canBeArgumentLabel { | ||
self.consumeAnyToken() | ||
|
@@ -783,8 +788,12 @@ extension Parser.Lookahead { | |
|
||
extension Parser { | ||
@_spi(RawSyntax) | ||
public mutating func parseTypeAttributeList() -> (RawTokenSyntax?, RawAttributeListSyntax?) { | ||
let specifier = self.consume(ifAny: [.inoutKeyword], contextualKeywords: ["__shared", "__owned"]) | ||
public mutating func parseTypeAttributeList(misplacedSpecifiers: [RawTokenSyntax] = []) -> (RawTokenSyntax?, RawAttributeListSyntax?) { | ||
var specifier: RawTokenSyntax? = self.consume(ifAnyIn: TypeSpecifier.self) | ||
// We can only stick one specifier on this type. Let's pick the first one | ||
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 feel the same way about this PR as I do about mine. I'm not sure it's worth keeping around all the state in order to allow adding the "missing" specifier here. Also note that specifiers are parsed into Whatever we end up doing here, it would be nice to be consistent across All the Things (where "things" here are attributes/modifiers/specifiers). Ie. should we ever expect a single, or should we always allow a list? Do we diagnose moving them to their correct position, or just add them (parsed correctly) as unexpected nodes? There are current clients (eg. SwiftLint) that check eg. the async keyword in a function declaration to determine if a function is async. Should that check pass if the async is in any position, or just the correct? |
||
if specifier == nil, let misplacedSpecifier = misplacedSpecifiers.first { | ||
specifier = missingToken(misplacedSpecifier.tokenKind, text: misplacedSpecifier.tokenText) | ||
} | ||
|
||
if self.at(any: [.atSign, .inoutKeyword]) { | ||
return (specifier, self.parseTypeAttributeListPresent()) | ||
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 can't add a comment where I want it - but |
||
|
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 name is somewhat confusing since function types can also have specifiers, but this is for the type specifiers specifically.