@@ -412,6 +412,21 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
412412 return . visitChildren
413413 }
414414
415+ override func visit( _ node: AccessorEffectSpecifiersSyntax ) -> SyntaxVisitorContinueKind {
416+ arrangeEffectSpecifiers ( node)
417+ return . visitChildren
418+ }
419+
420+ override func visit( _ node: FunctionEffectSpecifiersSyntax ) -> SyntaxVisitorContinueKind {
421+ arrangeEffectSpecifiers ( node)
422+ return . visitChildren
423+ }
424+
425+ override func visit( _ node: TypeEffectSpecifiersSyntax ) -> SyntaxVisitorContinueKind {
426+ arrangeEffectSpecifiers ( node)
427+ return . visitChildren
428+ }
429+
415430 /// Applies formatting tokens to the tokens in the given function or function-like declaration
416431 /// node (e.g., initializers, deinitiailizers, and subscripts).
417432 private func arrangeFunctionLikeDecl< Node: BracedSyntax , BodyContents: SyntaxCollection > (
@@ -434,6 +449,17 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
434449 after ( node. lastToken ( viewMode: . sourceAccurate) , tokens: . close)
435450 }
436451
452+ /// Arranges the `async` and `throws` effect specifiers of a function or accessor declaration.
453+ private func arrangeEffectSpecifiers< Node: EffectSpecifiersSyntax > ( _ node: Node ) {
454+ before ( node. asyncSpecifier, tokens: . break)
455+ before ( node. throwsSpecifier, tokens: . break)
456+ // Keep them together if both `async` and `throws` are present.
457+ if let asyncSpecifier = node. asyncSpecifier, let throwsSpecifier = node. throwsSpecifier {
458+ before ( asyncSpecifier, tokens: . open)
459+ after ( throwsSpecifier, tokens: . close)
460+ }
461+ }
462+
437463 // MARK: - Property and subscript accessor block nodes
438464
439465 override func visit( _ node: AccessorListSyntax ) -> SyntaxVisitorContinueKind {
@@ -449,22 +475,6 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
449475
450476 override func visit( _ node: AccessorDeclSyntax ) -> SyntaxVisitorContinueKind {
451477 arrangeAttributeList ( node. attributes)
452-
453- if let asyncKeyword = node. effectSpecifiers? . asyncSpecifier {
454- if node. effectSpecifiers? . throwsSpecifier != nil {
455- before ( asyncKeyword, tokens: . break, . open)
456- } else {
457- before ( asyncKeyword, tokens: . break)
458- }
459- }
460-
461- if let throwsKeyword = node. effectSpecifiers? . throwsSpecifier {
462- before ( node. effectSpecifiers? . throwsSpecifier, tokens: . break)
463- if node. effectSpecifiers? . asyncSpecifier != nil {
464- after ( throwsKeyword, tokens: . close)
465- }
466- }
467-
468478 arrangeBracesAndContents ( of: node. body, contentsKeyPath: \. statements)
469479 return . visitChildren
470480 }
@@ -1160,13 +1170,6 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
11601170 }
11611171 }
11621172
1163- before ( node. effectSpecifiers? . asyncSpecifier, tokens: . break)
1164- before ( node. effectSpecifiers? . throwsSpecifier, tokens: . break)
1165- if let asyncKeyword = node. effectSpecifiers? . asyncSpecifier, let throwsTok = node. effectSpecifiers? . throwsSpecifier {
1166- before ( asyncKeyword, tokens: . open)
1167- after ( throwsTok, tokens: . close)
1168- }
1169-
11701173 before ( node. output? . arrow, tokens: . break)
11711174 after ( node. lastToken ( viewMode: . sourceAccurate) , tokens: . close)
11721175 before ( node. inTok, tokens: . break( . same) )
@@ -1607,8 +1610,6 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
16071610 override func visit( _ node: FunctionTypeSyntax ) -> SyntaxVisitorContinueKind {
16081611 after ( node. leftParen, tokens: . break( . open, size: 0 ) , . open)
16091612 before ( node. rightParen, tokens: . break( . close, size: 0 ) , . close)
1610- before ( node. effectSpecifiers? . asyncSpecifier, tokens: . break)
1611- before ( node. effectSpecifiers? . throwsSpecifier, tokens: . break)
16121613 return . visitChildren
16131614 }
16141615
@@ -1833,14 +1834,6 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
18331834 }
18341835
18351836 override func visit( _ node: FunctionSignatureSyntax ) -> SyntaxVisitorContinueKind {
1836- before ( node. effectSpecifiers? . asyncSpecifier, tokens: . break)
1837- before ( node. effectSpecifiers? . throwsSpecifier, tokens: . break)
1838- if let asyncOrReasyncKeyword = node. effectSpecifiers? . asyncSpecifier,
1839- let throwsOrRethrowsKeyword = node. effectSpecifiers? . throwsSpecifier
1840- {
1841- before ( asyncOrReasyncKeyword, tokens: . open)
1842- after ( throwsOrRethrowsKeyword, tokens: . close)
1843- }
18441837 before ( node. output? . firstToken ( viewMode: . sourceAccurate) , tokens: . break)
18451838 return . visitChildren
18461839 }
@@ -1873,6 +1866,14 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
18731866 }
18741867
18751868 let binOp = node. operatorOperand
1869+ if binOp. is ( ArrowExprSyntax . self) {
1870+ // `ArrowExprSyntax` nodes occur when a function type is written in an expression context;
1871+ // for example, `let x = [(Int) throws -> Void]()`. We want to treat those consistently like
1872+ // we do other function return clauses and not treat them as regular binary operators, so
1873+ // handle that behavior there instead.
1874+ return . visitChildren
1875+ }
1876+
18761877 let rhs = node. rightOperand
18771878 maybeGroupAroundSubexpression ( rhs, combiningOperator: binOp)
18781879
@@ -1986,9 +1987,8 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
19861987 }
19871988
19881989 override func visit( _ node: ArrowExprSyntax ) -> SyntaxVisitorContinueKind {
1989- // The break before the `throws` keyword is inserted at the `InfixOperatorExpr` level so that it
1990- // is placed in the correct relative position to the group surrounding the "operator".
1991- after ( node. effectSpecifiers? . throwsSpecifier, tokens: . break)
1990+ before ( node. arrowToken, tokens: . break)
1991+ after ( node. arrowToken, tokens: . space)
19921992 return . visitChildren
19931993 }
19941994
0 commit comments