@@ -909,15 +909,17 @@ extension TokenConsumer {
909
909
/// - acceptClosure: When the next token is '{' and it looks like a closure, use this value as the result.
910
910
/// - preferPostfixExpr: When the next token is '.', '(', or '[' and there is a space between the word,
911
911
/// use `!preferPostfixExpr` as the result.
912
+ /// - allowNextLineOperand: Whether the keyword-prefixed syntax accepts the operand on the next line.
912
913
mutating func atContextualKeywordPrefixedSyntax(
913
914
exprFlavor: Parser . ExprFlavor ,
914
915
acceptClosure: Bool = false ,
915
- preferPostfixExpr: Bool = true
916
+ preferPostfixExpr: Bool = true ,
917
+ allowNextLineOperand: Bool = false
916
918
) -> Bool {
917
919
let next = peek ( )
918
920
919
921
// The next token must be at the same line.
920
- if next. isAtStartOfLine {
922
+ if next. isAtStartOfLine && !allowNextLineOperand {
921
923
return false
922
924
}
923
925
@@ -990,26 +992,28 @@ extension TokenConsumer {
990
992
// - Call vs. tuple expression
991
993
// - Subscript vs. collection literal
992
994
//
993
- let hasSpace = ( next. leadingTriviaByteLength + currentToken. trailingTriviaByteLength) != 0
994
- if !hasSpace {
995
- // No space, the word is an decl-ref expression
995
+ if preferPostfixExpr {
996
996
return false
997
997
}
998
- return !preferPostfixExpr
998
+
999
+ // If there's no space between the tokens, consider it's an expression.
1000
+ // Otherwise, it looks like a keyword followed by an expression.
1001
+ return ( next. leadingTriviaByteLength + currentToken. trailingTriviaByteLength) != 0
999
1002
1000
1003
case . leftBrace:
1001
1004
// E.g. <word> { ... }
1002
1005
// Trailing closure is also ambiguous:
1003
1006
//
1004
1007
// - Trailing closure vs. immediately-invoked closure
1005
1008
//
1006
- // Checking whitespace between the word cannot help this because people
1007
- // usually put a space before trailing closures. Even though that is source
1008
- // breaking, we prefer parsing it as a keyword if the syntax accepts
1009
- // immediately-invoked closure patterns. E.g. 'unsafe { ... }()'
1010
1009
if !acceptClosure {
1011
1010
return false
1012
1011
}
1012
+
1013
+ // Checking whitespace between the word cannot help this because people
1014
+ // usually put a space before trailing closures. Even though that is source
1015
+ // breaking, we prefer parsing it as a keyword if the syntax accepts
1016
+ // expressions starting with a closure. E.g. 'unsafe { ... }()'
1013
1017
return self . withLookahead {
1014
1018
$0. consumeAnyToken ( )
1015
1019
return $0. atValidTrailingClosure ( flavor: exprFlavor)
@@ -1068,9 +1072,16 @@ extension Parser.Lookahead {
1068
1072
// with a closure pattern.
1069
1073
return self . peek ( ) . rawTokenKind == . leftBrace
1070
1074
case . yield? , . discard? :
1071
- return atContextualKeywordPrefixedSyntax ( exprFlavor: . basic, preferPostfixExpr: true )
1075
+ return atContextualKeywordPrefixedSyntax (
1076
+ exprFlavor: . basic,
1077
+ preferPostfixExpr: true
1078
+ )
1072
1079
case . then? :
1073
- return atContextualKeywordPrefixedSyntax ( exprFlavor: . basic, preferPostfixExpr: false )
1080
+ return atContextualKeywordPrefixedSyntax (
1081
+ exprFlavor: . basic,
1082
+ preferPostfixExpr: false ,
1083
+ allowNextLineOperand: !preferExpr
1084
+ )
1074
1085
1075
1086
case nil :
1076
1087
return false
0 commit comments