@@ -67,7 +67,19 @@ extension Parser {
6767 arena: self . arena
6868 )
6969 )
70- case ( . lhs( . identifier) , let handle) ? :
70+ case ( . rhs( let introducer) , let handle) ? where self . withLookahead { $0. shouldParsePatternBinding ( introducer: introducer) } :
71+ let bindingSpecifier = self . eat ( handle)
72+ let value = self . parsePattern ( )
73+ return RawPatternSyntax (
74+ RawValueBindingPatternSyntax (
75+ bindingSpecifier: bindingSpecifier,
76+ pattern: value,
77+ arena: self . arena
78+ )
79+ )
80+ case ( . lhs( . identifier) , let handle) ? ,
81+ // If we shouldn't contextually parse a pattern binding introducer (because the previous pattern match guard failed), then parse it as an identifier.
82+ ( . rhs( _) , let handle) ? :
7183 let identifier = self . eat ( handle)
7284 return RawPatternSyntax (
7385 RawIdentifierPatternSyntax (
@@ -85,16 +97,6 @@ extension Parser {
8597 arena: self . arena
8698 )
8799 )
88- case ( . rhs, let handle) ? :
89- let bindingSpecifier = self . eat ( handle)
90- let value = self . parsePattern ( )
91- return RawPatternSyntax (
92- RawValueBindingPatternSyntax (
93- bindingSpecifier: bindingSpecifier,
94- pattern: value,
95- arena: self . arena
96- )
97- )
98100 case nil :
99101 break
100102 }
@@ -218,7 +220,7 @@ extension Parser {
218220 arena: self . arena
219221 )
220222 )
221- case ( . rhs, let handle) ? :
223+ case ( . rhs( let introducer ) , let handle) ? where self . withLookahead { $0 . shouldParsePatternBinding ( introducer : introducer ) } :
222224 let bindingSpecifier = self . eat ( handle)
223225 let value = self . parseMatchingPattern ( context: . bindingIntroducer)
224226 return RawPatternSyntax (
@@ -228,7 +230,8 @@ extension Parser {
228230 arena: self . arena
229231 )
230232 )
231- case nil :
233+ case ( . rhs( _) , _) ? ,
234+ nil :
232235 break
233236 }
234237
@@ -253,6 +256,21 @@ extension Parser {
253256// MARK: Lookahead
254257
255258extension Parser . Lookahead {
259+ /// Returns true if we should parse a pattern binding specifier contextually
260+ /// as one.
261+ mutating func shouldParsePatternBinding( introducer: ValueBindingPatternSyntax . BindingSpecifierOptions ) -> Bool {
262+ switch introducer {
263+ // TODO: the other ownership modifiers (borrowing/consuming/mutating) more
264+ // than likely need to be made contextual as well before finalizing their
265+ // grammar.
266+ case . _borrowing where experimentalFeatures. contains ( . borrowingSwitch) :
267+ return peek ( isAt: TokenSpec ( . identifier, allowAtStartOfLine: false ) )
268+ default :
269+ // Other keywords can be parsed unconditionally.
270+ return true
271+ }
272+ }
273+
256274 /// pattern ::= identifier
257275 /// pattern ::= '_'
258276 /// pattern ::= pattern-tuple
@@ -288,15 +306,18 @@ extension Parser.Lookahead {
288306 >
289307
290308 switch self . at ( anyIn: PatternStartTokens . self) {
291- case ( . lhs( . identifier) , let handle) ? ,
292- ( . lhs( . wildcard) , let handle) ? :
293- self . eat ( handle)
294- return true
295309 case ( . lhs( . leftParen) , _) ? :
296310 return self . canParsePatternTuple ( )
297- case ( . rhs, let handle) ? :
311+ case ( . rhs( let introducer) , let handle) ? where shouldParsePatternBinding ( introducer: introducer) :
312+ // Parse as a binding introducer, like `let x`.
298313 self . eat ( handle)
299314 return self . canParsePattern ( )
315+ case ( . lhs( . identifier) , let handle) ? ,
316+ ( . lhs( . wildcard) , let handle) ? ,
317+ // If a binding introducer is not contextually introducing a binding, then parse like an identifier.
318+ ( . rhs( _) , let handle) ? :
319+ self . eat ( handle)
320+ return true
300321 case nil :
301322 return false
302323 }
0 commit comments