@@ -909,15 +909,17 @@ extension TokenConsumer {
909909 /// - acceptClosure: When the next token is '{' and it looks like a closure, use this value as the result.
910910 /// - preferPostfixExpr: When the next token is '.', '(', or '[' and there is a space between the word,
911911 /// use `!preferPostfixExpr` as the result.
912+ /// - allowNextLineOperand: Whether the keyword-prefixed syntax accepts the operand on the next line.
912913 mutating func atContextualKeywordPrefixedSyntax(
913914 exprFlavor: Parser . ExprFlavor ,
914915 acceptClosure: Bool = false ,
915- preferPostfixExpr: Bool = true
916+ preferPostfixExpr: Bool = true ,
917+ allowNextLineOperand: Bool = false
916918 ) -> Bool {
917919 let next = peek ( )
918920
919921 // The next token must be at the same line.
920- if next. isAtStartOfLine {
922+ if next. isAtStartOfLine && !allowNextLineOperand {
921923 return false
922924 }
923925
@@ -990,26 +992,28 @@ extension TokenConsumer {
990992 // - Call vs. tuple expression
991993 // - Subscript vs. collection literal
992994 //
993- let hasSpace = ( next. leadingTriviaByteLength + currentToken. trailingTriviaByteLength) != 0
994- if !hasSpace {
995- // No space, the word is an decl-ref expression
995+ if preferPostfixExpr {
996996 return false
997997 }
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
9991002
10001003 case . leftBrace:
10011004 // E.g. <word> { ... }
10021005 // Trailing closure is also ambiguous:
10031006 //
10041007 // - Trailing closure vs. immediately-invoked closure
10051008 //
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 { ... }()'
10101009 if !acceptClosure {
10111010 return false
10121011 }
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 { ... }()'
10131017 return self . withLookahead {
10141018 $0. consumeAnyToken ( )
10151019 return $0. atValidTrailingClosure ( flavor: exprFlavor)
@@ -1068,9 +1072,16 @@ extension Parser.Lookahead {
10681072 // with a closure pattern.
10691073 return self . peek ( ) . rawTokenKind == . leftBrace
10701074 case . yield? , . discard? :
1071- return atContextualKeywordPrefixedSyntax ( exprFlavor: . basic, preferPostfixExpr: true )
1075+ return atContextualKeywordPrefixedSyntax (
1076+ exprFlavor: . basic,
1077+ preferPostfixExpr: true
1078+ )
10721079 case . then? :
1073- return atContextualKeywordPrefixedSyntax ( exprFlavor: . basic, preferPostfixExpr: false )
1080+ return atContextualKeywordPrefixedSyntax (
1081+ exprFlavor: . basic,
1082+ preferPostfixExpr: false ,
1083+ allowNextLineOperand: !preferExpr
1084+ )
10741085
10751086 case nil :
10761087 return false
0 commit comments