@@ -186,7 +186,7 @@ extension Parser {
186186 var keepGoing : RawTokenSyntax ? = nil
187187 var loopProgress = LoopProgressCondition ( )
188188 repeat {
189- let condition = self . parseConditionElement ( )
189+ let condition = self . parseConditionElement ( lastBindingKind : elements . last ? . condition . as ( RawOptionalBindingConditionSyntax . self ) ? . bindingKeyword )
190190 let unexpectedBeforeKeepGoing : RawUnexpectedNodesSyntax ?
191191 keepGoing = self . consume ( if: . comma)
192192 if keepGoing == nil , let andOperator = self . consumeIfContextualPunctuator ( " && " ) {
@@ -219,15 +219,16 @@ extension Parser {
219219 /// optional-binding-condition → 'let' pattern initializer? | 'var' pattern initializer? |
220220 /// 'inout' pattern initializer?
221221 @_spi ( RawSyntax)
222- public mutating func parseConditionElement( ) -> RawConditionElementSyntax . Condition {
222+ /// `lastBindingKind` will be used to get a correct fall back, when there is missing `var` or `let` in a `if` statement etc.
223+ public mutating func parseConditionElement( lastBindingKind: RawTokenSyntax ? ) -> RawConditionElementSyntax . Condition {
223224 // Parse a leading #available/#unavailable condition if present.
224225 if self . at ( . poundAvailableKeyword, . poundUnavailableKeyword) {
225226 return self . parsePoundAvailableConditionElement ( )
226227 }
227228
228229 // Parse the basic expression case. If we have a leading let, var, inout,
229230 // borrow, case keyword or an assignment, then we know this is a binding.
230- guard self . at ( . keyword( . let) , . keyword( . var) , . keyword( . case) ) || self . at ( . keyword( . inout) ) else {
231+ guard self . at ( . keyword( . let) , . keyword( . var) , . keyword( . case) ) || self . at ( . keyword( . inout) ) || ( lastBindingKind != nil && self . peek ( ) . rawTokenKind == . equal ) else {
231232 // If we lack it, then this is theoretically a boolean condition.
232233 // However, we also need to handle migrating from Swift 2 syntax, in
233234 // which a comma followed by an expression could actually be a pattern
@@ -244,20 +245,28 @@ extension Parser {
244245 }
245246
246247 // We're parsing a conditional binding.
247- precondition ( self . at ( . keyword( . let) , . keyword( . var) ) || self . at ( . keyword( . inout) , . keyword( . case) ) )
248248 enum BindingKind {
249249 case pattern( RawTokenSyntax , RawPatternSyntax )
250- case optional( RawTokenSyntax , RawPatternSyntax )
250+ case optional( RawUnexpectedNodesSyntax ? , RawTokenSyntax , RawPatternSyntax )
251251 }
252252
253253 let kind : BindingKind
254254 if let caseKeyword = self . consume ( if: . keyword( . case) ) {
255255 let pattern = self . parseMatchingPattern ( context: . matching)
256256 kind = . pattern( caseKeyword, pattern)
257257 } else {
258- let letOrVar = self . consumeAnyToken ( )
258+ let unexpectedBeforeBindingKeyword : RawUnexpectedNodesSyntax ?
259+ let letOrVar : RawTokenSyntax
260+
261+ if self . at ( . identifier) , let lastBindingKind = lastBindingKind {
262+ ( unexpectedBeforeBindingKeyword, letOrVar) = self . expect ( . keyword( . let) , . keyword( . var) , default: . keyword( Keyword ( lastBindingKind. tokenText) ?? . let) )
263+ } else {
264+ letOrVar = self . consume ( if: TokenSpec . keyword ( . let) , . keyword( . var) ) ?? self . missingToken ( . let)
265+ unexpectedBeforeBindingKeyword = nil
266+ }
267+
259268 let pattern = self . parseMatchingPattern ( context: . bindingIntroducer)
260- kind = . optional( letOrVar, pattern)
269+ kind = . optional( unexpectedBeforeBindingKeyword , letOrVar, pattern)
261270 }
262271
263272 // Now parse an optional type annotation.
@@ -289,9 +298,10 @@ extension Parser {
289298 }
290299
291300 switch kind {
292- case let . optional( bindingKeyword, pattern) :
301+ case let . optional( unexpectedBeforeBindingKeyword , bindingKeyword, pattern) :
293302 return . optionalBinding(
294303 RawOptionalBindingConditionSyntax (
304+ unexpectedBeforeBindingKeyword,
295305 bindingKeyword: bindingKeyword,
296306 pattern: pattern,
297307 typeAnnotation: annotation,
0 commit comments