@@ -1391,26 +1391,19 @@ extension Parser {
1391
1391
arena: self . arena)
1392
1392
}
1393
1393
1394
- /// If a `throws` keyword appears right in front of the `arrow`, it is returned as `misplacedThrowsKeyword` so it can be synthesized in front of the arrow.
1394
+ /// If effect specifiers appear in front of the `arrow` or after the return type, they are returned so that they can be synthesized in front of the arrow.
1395
1395
@_spi ( RawSyntax)
1396
- public mutating func parseFunctionReturnClause( ) -> ( returnClause: RawReturnClauseSyntax , misplacedThrowsKeyword: RawTokenSyntax ? ) {
1397
- let ( unexpectedBeforeArrow, arrow) = self . expect ( . arrow)
1398
- var misplacedThrowsKeyword : RawTokenSyntax ? = nil
1399
- let unexpectedBeforeReturnType : RawUnexpectedNodesSyntax ?
1400
- if let throwsKeyword = self . consume ( ifAny: [ . rethrowsKeyword, . throwsKeyword] ) {
1401
- misplacedThrowsKeyword = throwsKeyword
1402
- unexpectedBeforeReturnType = RawUnexpectedNodesSyntax ( elements: [ RawSyntax ( throwsKeyword) ] , arena: self . arena)
1403
- } else {
1404
- unexpectedBeforeReturnType = nil
1405
- }
1396
+ public mutating func parseFunctionReturnClause( _ handle: RecoveryConsumptionHandle ) -> ( returnClause: RawReturnClauseSyntax , misplacedEffects: RawUnexpectedNodesSyntax ? ) {
1397
+ let ( unexpectedBeforeArrow, arrow) = self . eat ( handle)
1398
+ let unexpectedBeforeReturnType = RawUnexpectedNodesSyntax ( unexpectedTokens: parseAllEffectsSpecifiers ( ) , arena: self . arena)
1406
1399
let result = self . parseResultType ( )
1407
1400
let returnClause = RawReturnClauseSyntax (
1408
1401
unexpectedBeforeArrow,
1409
1402
arrow: arrow,
1410
1403
unexpectedBeforeReturnType,
1411
1404
returnType: result,
1412
1405
arena: self . arena)
1413
- return ( returnClause, misplacedThrowsKeyword )
1406
+ return ( returnClause, unexpectedBeforeReturnType )
1414
1407
}
1415
1408
}
1416
1409
@@ -1495,32 +1488,27 @@ extension Parser {
1495
1488
public mutating func parseFunctionSignature( ) -> RawFunctionSignatureSyntax {
1496
1489
let input = self . parseParameterClause ( for: . functionParameters)
1497
1490
1498
- let async : RawTokenSyntax ?
1499
- if let asyncTok = self . consumeIfContextualKeyword ( " async " ) {
1500
- async = asyncTok
1501
- } else if let reasync = self . consumeIfContextualKeyword ( " reasync " ) {
1502
- async = reasync
1503
- } else {
1504
- async = nil
1505
- }
1506
-
1507
- var throwsKeyword = self . consume ( ifAny: [ . throwsKeyword, . rethrowsKeyword] )
1491
+ var asyncOrReasync : RawTokenSyntax ?
1492
+ var throwsOrRethrows : RawTokenSyntax ?
1493
+ let unexpectedAfterThrows : RawUnexpectedNodesSyntax ?
1494
+ ( asyncOrReasync, throwsOrRethrows, unexpectedAfterThrows) = parseExpectedEffectsSpecifiers ( )
1508
1495
1509
1496
let output : RawReturnClauseSyntax ?
1510
- if self . at ( . arrow) {
1511
- let result = self . parseFunctionReturnClause ( )
1497
+ if let handle = self . canRecoverTo ( . arrow) {
1498
+ let result = self . parseFunctionReturnClause ( handle )
1512
1499
output = result. returnClause
1513
- if let misplacedThrowsKeyword = result. misplacedThrowsKeyword, throwsKeyword == nil {
1514
- throwsKeyword = RawTokenSyntax ( missing: misplacedThrowsKeyword. tokenKind, arena: self . arena)
1515
- }
1500
+ addMissingEffectSpecifiers ( from: result. misplacedEffects, asyncOrReasync: & asyncOrReasync, throwsOrRethrows: & throwsOrRethrows)
1516
1501
} else {
1517
1502
output = nil
1518
1503
}
1519
1504
1505
+ // Check for more specifiers?
1506
+
1520
1507
return RawFunctionSignatureSyntax (
1521
1508
input: input,
1522
- asyncOrReasyncKeyword: async ,
1523
- throwsOrRethrowsKeyword: throwsKeyword,
1509
+ asyncOrReasyncKeyword: asyncOrReasync,
1510
+ throwsOrRethrowsKeyword: throwsOrRethrows,
1511
+ unexpectedAfterThrows,
1524
1512
output: output,
1525
1513
arena: self . arena)
1526
1514
}
@@ -1553,8 +1541,8 @@ extension Parser {
1553
1541
let indices = self . parseParameterClause ( for: . indices)
1554
1542
1555
1543
let result : RawReturnClauseSyntax
1556
- if self . at ( . arrow) {
1557
- result = self . parseFunctionReturnClause ( ) . returnClause
1544
+ if let handle = self . canRecoverTo ( . arrow) {
1545
+ result = self . parseFunctionReturnClause ( handle ) . returnClause
1558
1546
} else {
1559
1547
result = RawReturnClauseSyntax (
1560
1548
arrow: RawTokenSyntax ( missing: . arrow, arena: self . arena) ,
@@ -1728,33 +1716,14 @@ extension Parser {
1728
1716
attributes: attrs, modifier: modifier, kind: kind, token: introducer)
1729
1717
}
1730
1718
1731
- @_spi ( RawSyntax)
1732
- public mutating func parseEffectsSpecifier( ) -> RawTokenSyntax ? {
1733
- // 'async'
1734
- if let async = self . consumeIfContextualKeyword ( " async " ) {
1735
- return async
1736
- }
1737
-
1738
- // 'reasync'
1739
- if let reasync = self . consumeIfContextualKeyword ( " reasync " ) {
1740
- return reasync
1719
+ mutating func parseEffectsSpecifier( ) -> RawTokenSyntax ? {
1720
+ if let ( _, handle) = self . at ( anyIn: EffectsSpecifier . self) {
1721
+ return self . eat ( handle)
1741
1722
}
1742
-
1743
- // 'throws'/'rethrows'
1744
- if let throwsRethrows = self . consume ( ifAny: [ . throwsKeyword, . rethrowsKeyword] ) {
1745
- return throwsRethrows
1746
- }
1747
-
1748
- // diagnose 'throw'/'try'.
1749
- if let throwTry = self . consume ( ifAny: [ . throwKeyword, . tryKeyword] , where: { !$0. isAtStartOfLine } ) {
1750
- return throwTry
1751
- }
1752
-
1753
1723
return nil
1754
1724
}
1755
1725
1756
- @_spi ( RawSyntax)
1757
- public mutating func parseEffectsSpecifiers( ) -> [ RawTokenSyntax ] {
1726
+ mutating func parseAllEffectsSpecifiers( ) -> [ RawTokenSyntax ] {
1758
1727
var specifiers = [ RawTokenSyntax] ( )
1759
1728
var loopProgress = LoopProgressCondition ( )
1760
1729
while let specifier = self . parseEffectsSpecifier ( ) , loopProgress. evaluate ( currentToken) {
@@ -1763,6 +1732,69 @@ extension Parser {
1763
1732
return specifiers
1764
1733
}
1765
1734
1735
+ private func addMissingEffectSpecifiers( from unexpectedTokens: RawUnexpectedNodesSyntax ? , asyncOrReasync: inout RawTokenSyntax ? , throwsOrRethrows: inout RawTokenSyntax ? ) {
1736
+ guard let unexpectedTokens = unexpectedTokens else {
1737
+ return
1738
+ }
1739
+
1740
+ for unexpectedToken in unexpectedTokens. elements {
1741
+ guard asyncOrReasync == nil || throwsOrRethrows == nil , let specifier = unexpectedToken. as ( RawTokenSyntax . self) else {
1742
+ break
1743
+ }
1744
+
1745
+ switch specifier. tokenKind {
1746
+ case . contextualKeyword:
1747
+ if asyncOrReasync == nil , specifier. tokenText == " async " || specifier. tokenText == " reasync " {
1748
+ asyncOrReasync = RawTokenSyntax ( missing: specifier. tokenKind, text: specifier. tokenText, arena: self . arena)
1749
+ }
1750
+ break
1751
+ case . throwsKeyword:
1752
+ fallthrough
1753
+ case . rethrowsKeyword:
1754
+ if throwsOrRethrows == nil {
1755
+ throwsOrRethrows = RawTokenSyntax ( missing: specifier. tokenKind, text: specifier. tokenText, arena: self . arena)
1756
+ }
1757
+ break
1758
+ default :
1759
+ break
1760
+ }
1761
+ }
1762
+ }
1763
+
1764
+ mutating func parseExpectedEffectsSpecifiers( ) -> ( asyncOrReasync: RawTokenSyntax ? , throwsOrRethrows: RawTokenSyntax ? , unexpected: RawUnexpectedNodesSyntax ? ) {
1765
+ guard let firstSpecifier = parseEffectsSpecifier ( ) else {
1766
+ return ( nil , nil , nil )
1767
+ }
1768
+
1769
+ var asyncOrReasync : RawTokenSyntax ? = nil
1770
+ var throwsOrRethrows : RawTokenSyntax ? = nil
1771
+ var unexpectedTokens = [ RawTokenSyntax] ( )
1772
+
1773
+ // Not a fan of the number of places contextual + async/reasync is checked (or throws/rethrows for that matter). Can we use EffectSpecifier somehow?
1774
+ if firstSpecifier. tokenKind == . contextualKeyword,
1775
+ firstSpecifier. tokenText == " async " || firstSpecifier. tokenText == " reasync " {
1776
+ asyncOrReasync = firstSpecifier
1777
+
1778
+ if let secondSpecifier = parseEffectsSpecifier ( ) {
1779
+ if secondSpecifier. tokenKind == . throwsKeyword || secondSpecifier. tokenKind == . rethrowsKeyword {
1780
+ throwsOrRethrows = firstSpecifier
1781
+ } else {
1782
+ unexpectedTokens. append ( secondSpecifier)
1783
+ }
1784
+ }
1785
+ } else if firstSpecifier. tokenKind == . throwsKeyword || firstSpecifier. tokenKind == . rethrowsKeyword {
1786
+ throwsOrRethrows = firstSpecifier
1787
+ } else {
1788
+ unexpectedTokens. append ( firstSpecifier)
1789
+ }
1790
+ unexpectedTokens. append ( contentsOf: parseAllEffectsSpecifiers ( ) )
1791
+
1792
+ let unexpected = RawUnexpectedNodesSyntax ( unexpectedTokens: unexpectedTokens, arena: self . arena)
1793
+ addMissingEffectSpecifiers ( from: unexpected, asyncOrReasync: & asyncOrReasync, throwsOrRethrows: & throwsOrRethrows)
1794
+
1795
+ return ( asyncOrReasync, throwsOrRethrows, unexpected)
1796
+ }
1797
+
1766
1798
/// Parse the body of a variable declaration. This can include explicit
1767
1799
/// getters, setters, and observers, or the body of a computed property.
1768
1800
///
0 commit comments