@@ -1746,7 +1746,9 @@ extension Parser {
1746
1746
var effectSpecifiers : RawTypeEffectSpecifiersSyntax ?
1747
1747
var returnClause : RawReturnClauseSyntax ? = nil
1748
1748
if !self . at ( . keyword( . in) ) {
1749
- if self . at ( . leftParen) {
1749
+ // If the next token is ':', then it looks like the code contained a non-shorthand closure parameter with a type annotation.
1750
+ // These need to be wrapped in parentheses.
1751
+ if self . at ( . leftParen) || self . peek ( isAt: . colon) {
1750
1752
// Parse the closure arguments.
1751
1753
let params = self . parseParameterClause ( RawClosureParameterClauseSyntax . self) { parser in
1752
1754
parser. parseClosureParameter ( )
@@ -2427,52 +2429,49 @@ extension Parser.Lookahead {
2427
2429
}
2428
2430
2429
2431
// Parse pattern-tuple func-signature-result? 'in'.
2430
- if lookahead. consume ( if: . leftParen) != nil { // Consume the ')'.
2431
-
2432
+ if lookahead. consume ( if: . leftParen) != nil { // Consume the '('.
2432
2433
// While we don't have '->' or ')', eat balanced tokens.
2433
2434
var skipProgress = LoopProgressCondition ( )
2434
- while !lookahead. at ( . endOfFile, . rightParen) && lookahead. hasProgressed ( & skipProgress) {
2435
+ while !lookahead. at ( . endOfFile, . rightParen, . keyword ( . in ) ) && !lookahead . at ( . arrow ) && lookahead. hasProgressed ( & skipProgress) {
2435
2436
lookahead. skipSingle ( )
2436
2437
}
2437
-
2438
- // Consume the ')', if it's there.
2439
- if lookahead. consume ( if: . rightParen) != nil {
2440
- lookahead. consumeEffectsSpecifiers ( )
2441
-
2442
- // Parse the func-signature-result, if present.
2443
- if lookahead. consume ( if: . arrow) != nil {
2444
- guard lookahead. canParseType ( ) else {
2445
- return false
2446
- }
2447
-
2448
- lookahead. consumeEffectsSpecifiers ( )
2449
- }
2450
- }
2451
- // Okay, we have a closure signature.
2452
2438
} else if lookahead. at ( . identifier) || lookahead. at ( . wildcard) {
2453
2439
// Parse identifier (',' identifier)*
2454
2440
lookahead. consumeAnyToken ( )
2455
2441
2442
+ /// If the next token is a colon, interpret is as a type annotation and consume a type after it.
2443
+ /// While type annotations aren’t allowed in shorthand closure parameters, we consume them to improve recovery.
2444
+ func consumeOptionalTypeAnnotation( ) -> Bool {
2445
+ if lookahead. consume ( if: . colon) != nil {
2446
+ return lookahead. canParseType ( )
2447
+ } else {
2448
+ return true
2449
+ }
2450
+ }
2451
+
2456
2452
var parametersProgress = LoopProgressCondition ( )
2457
- while lookahead. consume ( if: . comma) != nil && lookahead. hasProgressed ( & parametersProgress) {
2453
+ while consumeOptionalTypeAnnotation ( ) && lookahead. consume ( if: . comma) != nil && lookahead. hasProgressed ( & parametersProgress) {
2458
2454
if lookahead. at ( . identifier) || lookahead. at ( . wildcard) {
2459
2455
lookahead. consumeAnyToken ( )
2460
2456
continue
2461
2457
}
2462
2458
2463
2459
return false
2464
2460
}
2461
+ }
2465
2462
2466
- lookahead. consumeEffectsSpecifiers ( )
2463
+ // Consume the ')', if it's there.
2464
+ lookahead. consume ( if: . rightParen)
2467
2465
2468
- // Parse the func-signature-result, if present.
2469
- if lookahead. consume ( if: . arrow) != nil {
2470
- guard lookahead. canParseType ( ) else {
2471
- return false
2472
- }
2466
+ lookahead. consumeEffectsSpecifiers ( )
2473
2467
2474
- lookahead. consumeEffectsSpecifiers ( )
2468
+ // Parse the func-signature-result, if present.
2469
+ if lookahead. consume ( if: . arrow) != nil {
2470
+ guard lookahead. canParseType ( ) else {
2471
+ return false
2475
2472
}
2473
+
2474
+ lookahead. consumeEffectsSpecifiers ( )
2476
2475
}
2477
2476
2478
2477
// Parse the 'in' at the end.
0 commit comments