@@ -1103,8 +1103,48 @@ extension Parser {
1103
1103
continue
1104
1104
}
1105
1105
1106
- // Check for a .name or .1 suffix.
1106
+ // Check for a .name, .1, .name(), .name("Kiwi"), .name(fruit:),
1107
+ // .name(_:), .name(fruit: "Kiwi) suffix.
1107
1108
if self . at ( . period) {
1109
+ // Parse as a keypath method if fully applied.
1110
+ if self . experimentalFeatures. contains ( . keypathWithMethodMembers)
1111
+ && self . withLookahead ( { $0. isAppliedKeyPathMethod ( ) } )
1112
+ {
1113
+ let ( unexpectedPeriod, period, declName, _) = parseDottedExpressionSuffix (
1114
+ previousNode: components. last? . raw ?? rootType? . raw ?? backslash. raw
1115
+ )
1116
+ let leftParen = self . consumeAnyToken ( )
1117
+ var args : [ RawLabeledExprSyntax ] = [ ]
1118
+ if !self . at ( . rightParen) {
1119
+ args = self . parseArgumentListElements (
1120
+ pattern: pattern,
1121
+ allowTrailingComma: true
1122
+ )
1123
+ }
1124
+ let ( unexpectedBeforeRParen, rightParen) = self . expect ( . rightParen)
1125
+ components. append (
1126
+ RawKeyPathComponentSyntax (
1127
+ unexpectedPeriod,
1128
+ period: period,
1129
+ component: . method(
1130
+ RawKeyPathMethodComponentSyntax (
1131
+ declName: declName,
1132
+ leftParen: leftParen,
1133
+ arguments: RawLabeledExprListSyntax (
1134
+ elements: args,
1135
+ arena: self . arena
1136
+ ) ,
1137
+ unexpectedBeforeRParen,
1138
+ rightParen: rightParen,
1139
+ arena: self . arena
1140
+ )
1141
+ ) ,
1142
+ arena: self . arena
1143
+ )
1144
+ )
1145
+ continue
1146
+ }
1147
+ // Else, parse as a property.
1108
1148
let ( unexpectedPeriod, period, declName, generics) = parseDottedExpressionSuffix (
1109
1149
previousNode: components. last? . raw ?? rootType? . raw ?? backslash. raw
1110
1150
)
@@ -1128,7 +1168,6 @@ extension Parser {
1128
1168
// No more postfix expressions.
1129
1169
break
1130
1170
}
1131
-
1132
1171
return RawKeyPathExprSyntax (
1133
1172
unexpectedBeforeBackslash,
1134
1173
backslash: backslash,
@@ -2017,6 +2056,37 @@ extension Parser {
2017
2056
}
2018
2057
2019
2058
extension Parser . Lookahead {
2059
+ /// Check if the keypath method is applied, and not partially applied which should be parsed as a key path property.
2060
+ mutating func isAppliedKeyPathMethod( ) -> Bool {
2061
+ var lookahead = self . lookahead ( )
2062
+ var hasLParen = false , hasRParen = false
2063
+
2064
+ while true {
2065
+ let token = lookahead. peek ( ) . rawTokenKind
2066
+ if token == . endOfFile || lookahead. atStartOfLine {
2067
+ break
2068
+ }
2069
+ if token == . leftParen {
2070
+ hasLParen = true
2071
+ }
2072
+ if token == . colon {
2073
+ lookahead. consumeAnyToken ( )
2074
+ // If there's a colon followed by a right parenthesis, it is
2075
+ // a partial application and should be parsed as a property.
2076
+ if lookahead. peek ( ) . rawTokenKind == . rightParen {
2077
+ return false
2078
+ }
2079
+ }
2080
+ if token == . rightParen {
2081
+ hasRParen = true
2082
+ }
2083
+ lookahead. consumeAnyToken ( )
2084
+ }
2085
+ // If parentheses exist with no partial application pattern,
2086
+ // parse as a key path method.
2087
+ return hasLParen && hasRParen ? true : false
2088
+ }
2089
+
2020
2090
mutating func atStartOfLabelledTrailingClosure( ) -> Bool {
2021
2091
// Fast path: the next two tokens must be a label and a colon.
2022
2092
// But 'default:' is ambiguous with switch cases and we disallow it
0 commit comments