Skip to content

Commit c225440

Browse files
committed
fixed-typed-throws-after-arrow-fixit
- `Parser.parseMisplacedEffectSpecifiers` will detect whether there is any misplaced typed throws. If yes, it will try to parse the thrown type and mark all tokens of the thrown type as missing. - `ParseDiagnosticsGenerator.handleMisplacedEffectSpecifiersAfterArrow` will recognize the entire throws clause as correct instead of the throws specifier only. - `ParseDiagnosticsGenerator.exchangeNodes` to replace `ParseDiagnosticsGenerator.exchangeTokens`, relaxing the input type from token to any syntax node. - refactored `TokenMissingMaker` in Declaration.swift, moved to Parser.swift, creating `Parser.withAllTokensMarkedMissing` for more generalized use.
1 parent 70e3741 commit c225440

File tree

5 files changed

+215
-86
lines changed

5 files changed

+215
-86
lines changed

Sources/SwiftParser/Declarations.swift

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,17 +1281,7 @@ extension Parser {
12811281
arena: self.arena
12821282
)
12831283

1284-
/// Create a version of the same attribute with all tokens missing.
1285-
class TokenMissingMaker: SyntaxRewriter {
1286-
override func visit(_ token: TokenSyntax) -> TokenSyntax {
1287-
return .init(token.tokenKind, presence: .missing)
1288-
}
1289-
}
1290-
let tokenMissingMaker = TokenMissingMaker(arena: self.arena)
1291-
let missingAttributes = tokenMissingMaker.rewrite(
1292-
Syntax(raw: RawSyntax(recoveredAttributes), rawNodeArena: arena)
1293-
).raw
1294-
attrs.attributes = missingAttributes.cast(RawAttributeListSyntax.self)
1284+
attrs.attributes = withAllTokensMarkedMissing(syntax: recoveredAttributes)
12951285
}
12961286

12971287
var (pattern, typeAnnotation) = self.parseTypedPattern()

Sources/SwiftParser/Parser.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,24 @@ extension Parser {
826826
}
827827
}
828828

829+
// MARK: Marking Tokens As Missing
830+
extension Parser {
831+
private class TokenMissingMaker: SyntaxRewriter {
832+
override func visit(_ token: TokenSyntax) -> TokenSyntax {
833+
TokenSyntax(token.tokenKind, presence: .missing)
834+
}
835+
}
836+
837+
/// Creates a replicate of `syntax` with all tokens marked as missing.
838+
func withAllTokensMarkedMissing<T: RawSyntaxNodeProtocol>(syntax: T) -> T {
839+
let tokenMissingMaker = TokenMissingMaker(arena: self.arena)
840+
let allMissing = tokenMissingMaker.rewrite(
841+
Syntax(raw: RawSyntax(syntax), rawNodeArena: self.arena)
842+
).raw
843+
return allMissing.cast(T.self)
844+
}
845+
}
846+
829847
extension SyntaxText {
830848
func withBuffer<Result>(_ body: (UnsafeBufferPointer<UInt8>) throws -> Result) rethrows -> Result {
831849
try body(UnsafeBufferPointer<UInt8>(start: self.baseAddress, count: self.count))

Sources/SwiftParser/Specifiers.swift

Lines changed: 74 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -772,16 +772,17 @@ extension Parser {
772772
_ effectSpecifiers: inout S?
773773
) -> RawUnexpectedNodesSyntax? {
774774
var synthesizedAsync: RawTokenSyntax? = nil
775-
var synthesizedThrows: RawTokenSyntax? = nil
776-
var unexpected: [RawTokenSyntax] = []
775+
var synthesizedThrowsClause: RawThrowsClauseSyntax? = nil
776+
var unexpected: [RawSyntax] = []
777777
var loopProgress = LoopProgressCondition()
778+
778779
while self.hasProgressed(&loopProgress) {
779780
if let (spec, handle, matchedSubset) = self.at(
780781
anyIn: S.MisspelledAsyncTokenKinds.self,
781782
or: S.CorrectAsyncTokenKinds.self
782783
) {
783784
let misspelledAsync = self.eat(handle)
784-
unexpected.append(misspelledAsync)
785+
unexpected.append(RawSyntax(misspelledAsync))
785786
if effectSpecifiers?.asyncSpecifier == nil {
786787
if matchedSubset == S.CorrectAsyncTokenKinds.self {
787788
synthesizedAsync = missingToken(spec)
@@ -794,23 +795,82 @@ extension Parser {
794795
or: S.CorrectThrowsTokenKinds.self
795796
) {
796797
let misspelledThrows = self.eat(handle)
797-
unexpected.append(misspelledThrows)
798-
if effectSpecifiers?.throwsClause == nil {
799-
if matchedSubset == S.CorrectThrowsTokenKinds.self {
800-
synthesizedThrows = missingToken(spec)
801-
} else {
802-
synthesizedThrows = missingToken(.throws)
798+
unexpected.append(RawSyntax(misspelledThrows))
799+
guard effectSpecifiers?.throwsClause == nil else {
800+
continue
801+
}
802+
if matchedSubset == S.CorrectThrowsTokenKinds.self {
803+
let synthesizedThrows = missingToken(spec)
804+
805+
// avoid generating diagnotics that suggest moving `throws` and the following type if there is any trivia
806+
// between `throws` and the following left parenthesis, because the following type is likely to be the
807+
// return type.
808+
// e.g. -> throws (Int, Int)
809+
//
810+
// prefer pessimistic diagnostics even if they might be suboptimal.
811+
// e.g. -> throws (any Error) Int
812+
guard misspelledThrows.trailingTriviaByteLength == 0 && self.currentToken.leadingTriviaByteLength == 0 else {
813+
synthesizedThrowsClause = RawThrowsClauseSyntax(
814+
throwsSpecifier: synthesizedThrows,
815+
leftParen: nil,
816+
type: nil,
817+
rightParen: nil,
818+
arena: self.arena
819+
)
820+
continue
821+
}
822+
823+
guard
824+
withLookahead({ lookahead in
825+
lookahead.consume(if: .leftParen) != nil && lookahead.canParseType()
826+
})
827+
else {
828+
synthesizedThrowsClause = RawThrowsClauseSyntax(
829+
throwsSpecifier: synthesizedThrows,
830+
leftParen: nil,
831+
type: nil,
832+
rightParen: nil,
833+
arena: self.arena
834+
)
835+
continue
803836
}
837+
838+
let (unexpectedBeforeLeftParen, leftParen) = self.expect(.leftParen)
839+
if let unexpectedBeforeLeftParen {
840+
unexpected += unexpectedBeforeLeftParen.elements
841+
}
842+
unexpected.append(RawSyntax(leftParen))
843+
let type = self.parseType()
844+
unexpected.append(RawSyntax(type))
845+
let (unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen)
846+
if let unexpectedBeforeRightParen {
847+
unexpected += unexpectedBeforeRightParen.elements
848+
}
849+
if !rightParen.isMissing {
850+
unexpected.append(RawSyntax(rightParen))
851+
}
852+
853+
synthesizedThrowsClause = RawThrowsClauseSyntax(
854+
throwsSpecifier: synthesizedThrows,
855+
leftParen: missingToken(.leftParen),
856+
type: self.withAllTokensMarkedMissing(syntax: type),
857+
rightParen: rightParen.isMissing ? nil : missingToken(.rightParen),
858+
arena: self.arena
859+
)
860+
} else {
861+
synthesizedThrowsClause = RawThrowsClauseSyntax(
862+
throwsSpecifier: missingToken(.throws),
863+
leftParen: nil,
864+
type: nil,
865+
rightParen: nil,
866+
arena: self.arena
867+
)
804868
}
805869
} else {
806870
break
807871
}
808872
}
809-
if synthesizedAsync != nil || synthesizedThrows != nil {
810-
let synthesizedThrowsClause = synthesizedThrows.map {
811-
RawThrowsClauseSyntax(throwsSpecifier: $0, leftParen: nil, type: nil, rightParen: nil, arena: self.arena)
812-
}
813-
873+
if synthesizedAsync != nil || synthesizedThrowsClause != nil {
814874
if let specifiers = effectSpecifiers {
815875
effectSpecifiers = specifiers.withMisplaced(
816876
async: synthesizedAsync,

0 commit comments

Comments
 (0)