@@ -519,7 +519,24 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
519
519
520
520
override func visit( _ node: ForInStmtSyntax ) -> SyntaxVisitorContinueKind {
521
521
after ( node. labelColon, tokens: . space)
522
- after ( node. forKeyword, tokens: . space)
522
+
523
+ // If we have a `(try) await` clause, allow breaking after the `for` so that the `(try) await`
524
+ // can fall onto the next line if needed, and if both `try await` are present, keep them
525
+ // together. Otherwise, keep `for` glued to the token after it so that we break somewhere later
526
+ // on the line.
527
+ if let awaitKeyword = node. awaitKeyword {
528
+ after ( node. forKeyword, tokens: . break)
529
+ if let tryKeyword = node. tryKeyword {
530
+ before ( tryKeyword, tokens: . open)
531
+ after ( tryKeyword, tokens: . break)
532
+ after ( awaitKeyword, tokens: . close, . break)
533
+ } else {
534
+ after ( awaitKeyword, tokens: . break)
535
+ }
536
+ } else {
537
+ after ( node. forKeyword, tokens: . space)
538
+ }
539
+
523
540
after ( node. caseKeyword, tokens: . space)
524
541
before ( node. inKeyword, tokens: . break)
525
542
after ( node. inKeyword, tokens: . space)
@@ -897,10 +914,11 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
897
914
898
915
if let calledMemberAccessExpr = node. calledExpression. as ( MemberAccessExprSyntax . self) {
899
916
if let base = calledMemberAccessExpr. base, base. is ( IdentifierExprSyntax . self) {
900
- // When this function call is wrapped by a try-expr, the group applied when visiting the
901
- // try-expr is sufficient. Adding another gruop here in that case can result in
902
- // unnecessarily breaking after the try keyword.
903
- if !( base. firstToken? . previousToken? . parent? . is ( TryExprSyntax . self) ?? false ) {
917
+ // When this function call is wrapped by a try-expr or await-expr, the group applied when
918
+ // visiting that wrapping expression is sufficient. Adding another group here in that case
919
+ // can result in unnecessarily breaking after the try/await keyword.
920
+ if !( base. firstToken? . previousToken? . parent? . is ( TryExprSyntax . self) ?? false
921
+ || base. firstToken? . previousToken? . parent? . is ( AwaitExprSyntax . self) ?? false ) {
904
922
before ( base. firstToken, tokens: . open)
905
923
after ( calledMemberAccessExpr. name. lastToken, tokens: . close)
906
924
}
@@ -1050,6 +1068,8 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
1050
1068
override func visit( _ node: ClosureSignatureSyntax ) -> SyntaxVisitorContinueKind {
1051
1069
before ( node. firstToken, tokens: . open)
1052
1070
1071
+ arrangeAttributeList ( node. attributes, suppressFinalBreak: node. input == nil )
1072
+
1053
1073
if let input = node. input {
1054
1074
// We unconditionally put a break before the `in` keyword below, so we should only put a break
1055
1075
// after the capture list's right bracket if there are arguments following it or we'll end up
@@ -1087,7 +1107,13 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
1087
1107
}
1088
1108
}
1089
1109
1110
+ before ( node. asyncKeyword, tokens: . break)
1090
1111
before ( node. throwsTok, tokens: . break)
1112
+ if let asyncKeyword = node. asyncKeyword, let throwsTok = node. throwsTok {
1113
+ before ( asyncKeyword, tokens: . open)
1114
+ after ( throwsTok, tokens: . close)
1115
+ }
1116
+
1091
1117
before ( node. output? . arrow, tokens: . break)
1092
1118
after ( node. lastToken, tokens: . close)
1093
1119
before ( node. inTok, tokens: . break( . same) )
@@ -1461,32 +1487,52 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
1461
1487
tokens: . break( . continue, newlines: . elective( ignoresDiscretionary: true ) ) )
1462
1488
1463
1489
// Check for an anchor token inside of the expression to group with the try keyword.
1464
- if let anchorToken = findTryExprConnectingToken ( inExpr: node. expression) {
1490
+ if let anchorToken = findTryAwaitExprConnectingToken ( inExpr: node. expression) {
1465
1491
before ( node. tryKeyword, tokens: . open)
1466
1492
after ( anchorToken, tokens: . close)
1467
1493
}
1468
1494
1469
1495
return . visitChildren
1470
1496
}
1471
1497
1498
+ override func visit( _ node: AwaitExprSyntax ) -> SyntaxVisitorContinueKind {
1499
+ before (
1500
+ node. expression. firstToken,
1501
+ tokens: . break( . continue, newlines: . elective( ignoresDiscretionary: true ) ) )
1502
+
1503
+ // Check for an anchor token inside of the expression to group with the await keyword.
1504
+ if !( node. parent? . is ( TryExprSyntax . self) ?? false ) ,
1505
+ let anchorToken = findTryAwaitExprConnectingToken ( inExpr: node. expression)
1506
+ {
1507
+ before ( node. awaitKeyword, tokens: . open)
1508
+ after ( anchorToken, tokens: . close)
1509
+ }
1510
+
1511
+ return . visitChildren
1512
+ }
1513
+
1472
1514
/// Searches the AST from `expr` to find a token that should be grouped with an enclosing
1473
- /// try-expr. Returns that token, or nil when no such token is found.
1515
+ /// try-expr or await-expr . Returns that token, or nil when no such token is found.
1474
1516
///
1475
- /// - Parameter expr: An expression that is wrapped by a try-expr.
1476
- /// - Returns: A token that should be grouped with the try-expr, or nil.
1477
- func findTryExprConnectingToken( inExpr expr: ExprSyntax ) -> TokenSyntax ? {
1517
+ /// - Parameter expr: An expression that is wrapped by a try-expr or await-expr.
1518
+ /// - Returns: A token that should be grouped with the try-expr or await-expr, or nil.
1519
+ func findTryAwaitExprConnectingToken( inExpr expr: ExprSyntax ) -> TokenSyntax ? {
1520
+ if let awaitExpr = expr. as ( AwaitExprSyntax . self) {
1521
+ // If we were called from the `try` of a `try await <expr>`, drill into the child expression.
1522
+ return findTryAwaitExprConnectingToken ( inExpr: awaitExpr. expression)
1523
+ }
1478
1524
if let callingExpr = expr. asProtocol ( CallingExprSyntaxProtocol . self) {
1479
- return findTryExprConnectingToken ( inExpr: callingExpr. calledExpression)
1525
+ return findTryAwaitExprConnectingToken ( inExpr: callingExpr. calledExpression)
1480
1526
}
1481
1527
if let memberAccessExpr = expr. as ( MemberAccessExprSyntax . self) , let base = memberAccessExpr. base
1482
1528
{
1483
- // When there's a simple base (i.e. identifier), group the entire `try <base>.<name>`
1529
+ // When there's a simple base (i.e. identifier), group the entire `try/await <base>.<name>`
1484
1530
// sequence. This check has to happen here so that the `MemberAccessExprSyntax.name` is
1485
1531
// available.
1486
1532
if base. is ( IdentifierExprSyntax . self) {
1487
1533
return memberAccessExpr. name. lastToken
1488
1534
}
1489
- return findTryExprConnectingToken ( inExpr: base)
1535
+ return findTryAwaitExprConnectingToken ( inExpr: base)
1490
1536
}
1491
1537
if expr. is ( IdentifierExprSyntax . self) {
1492
1538
return expr. lastToken
@@ -1634,13 +1680,28 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
1634
1680
}
1635
1681
1636
1682
override func visit( _ node: DeclModifierSyntax ) -> SyntaxVisitorContinueKind {
1637
- after ( node. lastToken, tokens: . break)
1683
+ // Due to the way we currently use spaces after let/var keywords in variable bindings, we need
1684
+ // this special exception for `async let` statements to avoid breaking prematurely between the
1685
+ // `async` and `let` keywords.
1686
+ let breakOrSpace : Token
1687
+ if node. name. tokenKind == . identifier( " async " ) {
1688
+ breakOrSpace = . space
1689
+ } else {
1690
+ breakOrSpace = . break
1691
+ }
1692
+ after ( node. lastToken, tokens: breakOrSpace)
1638
1693
return . visitChildren
1639
1694
}
1640
1695
1641
1696
override func visit( _ node: FunctionSignatureSyntax ) -> SyntaxVisitorContinueKind {
1642
1697
before ( node. asyncOrReasyncKeyword, tokens: . break)
1643
1698
before ( node. throwsOrRethrowsKeyword, tokens: . break)
1699
+ if let asyncOrReasyncKeyword = node. asyncOrReasyncKeyword,
1700
+ let throwsOrRethrowsKeyword = node. throwsOrRethrowsKeyword
1701
+ {
1702
+ before ( asyncOrReasyncKeyword, tokens: . open)
1703
+ after ( throwsOrRethrowsKeyword, tokens: . close)
1704
+ }
1644
1705
before ( node. output? . firstToken, tokens: . break)
1645
1706
return . visitChildren
1646
1707
}
@@ -2472,11 +2533,18 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
2472
2533
// MARK: - Various other helper methods
2473
2534
2474
2535
/// Applies formatting tokens around and between the attributes in an attribute list.
2475
- private func arrangeAttributeList( _ attributes: AttributeListSyntax ? ) {
2536
+ private func arrangeAttributeList(
2537
+ _ attributes: AttributeListSyntax ? ,
2538
+ suppressFinalBreak: Bool = false
2539
+ ) {
2476
2540
if let attributes = attributes {
2477
2541
before ( attributes. firstToken, tokens: . open)
2478
2542
insertTokens ( . break( . same) , betweenElementsOf: attributes)
2479
- after ( attributes. lastToken, tokens: . close, . break( . same) )
2543
+ var afterAttributeTokens = [ Token . close]
2544
+ if !suppressFinalBreak {
2545
+ afterAttributeTokens. append ( . break( . same) )
2546
+ }
2547
+ after ( attributes. lastToken, tokens: afterAttributeTokens)
2480
2548
}
2481
2549
}
2482
2550
@@ -3087,10 +3155,12 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
3087
3155
}
3088
3156
3089
3157
/// Returns whether the given expression consists of multiple subexpressions. Certain expressions
3090
- /// that are known to wrap an expressions , e.g. try expressions, are handled by checking the
3158
+ /// that are known to wrap an expression , e.g. try expressions, are handled by checking the
3091
3159
/// expression that they contain.
3092
3160
private func isCompoundExpression( _ expr: ExprSyntax ) -> Bool {
3093
3161
switch Syntax ( expr) . as ( SyntaxEnum . self) {
3162
+ case . awaitExpr( let awaitExpr) :
3163
+ return isCompoundExpression ( awaitExpr. expression)
3094
3164
case . sequenceExpr( let sequenceExpr) :
3095
3165
return sequenceExpr. elements. count > 1
3096
3166
case . ternaryExpr:
0 commit comments