Skip to content

Commit 3b255d6

Browse files
committed
Parse Much Harder for a Right Bracket in Capture Specifiers
All the lookahead we did before this promised us a right bracket here, but the precedence of right brackets is too weak to overcome keywords. The attached test case shows that we fall all the way through closure signature parsing and nothing picks up the slack and eats the remaining parts of the signature. Instead, do `expect`'s job for it and try to munge through to the right bracket ourselves. Fixes #721 rdar://99657721
1 parent 5e3f994 commit 3b255d6

File tree

2 files changed

+18
-3
lines changed

2 files changed

+18
-3
lines changed

Sources/SwiftParser/Expressions.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1668,12 +1668,18 @@ extension Parser {
16681668
arena: self.arena))
16691669
} while keepGoing != nil && loopProgress.evaluate(currentToken)
16701670
}
1671+
// We were promised a right square bracket, so we're going to get it.
1672+
var unexpectedNodes = [RawSyntax]()
1673+
while !self.at(.eof) && !self.at(.rightSquareBracket) && !self.at(.inKeyword) {
1674+
unexpectedNodes.append(RawSyntax(self.consumeAnyToken()))
1675+
}
16711676
let (unexpectedBeforeRSquare, rsquare) = self.expect(.rightSquareBracket)
1677+
unexpectedNodes.append(contentsOf: unexpectedBeforeRSquare?.elements ?? [])
16721678

16731679
captures = RawClosureCaptureSignatureSyntax(
16741680
leftSquare: lsquare,
16751681
items: elements.isEmpty ? nil : RawClosureCaptureItemListSyntax(elements: elements, arena: self.arena),
1676-
unexpectedBeforeRSquare,
1682+
unexpectedNodes.isEmpty ? nil : RawUnexpectedNodesSyntax(elements: unexpectedNodes, arena: self.arena),
16771683
rightSquare: rsquare, arena: self.arena)
16781684
} else {
16791685
captures = nil
@@ -1760,7 +1766,7 @@ extension Parser {
17601766
}
17611767
specifiers.append(self.expectWithoutLookahead(.rightParen))
17621768
}
1763-
} else if (self.currentToken.isIdentifier || self.at(.selfKeyword)) {
1769+
} else if self.currentToken.isIdentifier || self.at(.selfKeyword) {
17641770
let next = self.peek()
17651771
// "x = 42", "x," and "x]" are all strong captures of x.
17661772
guard next.tokenKind == .equal || next.tokenKind == .comma

Tests/SwiftParserTest/Types.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ final class TypeTests: XCTestCase {
4242

4343
AssertParse("""
4444
{ [weak a, unowned(safe) self, b = 3] (a: Int, b: Int, _: Int) -> Int in }
45-
""")
45+
""",
46+
{ $0.parseClosureExpression() })
47+
48+
AssertParse("{[#^DIAG_1^#class]in#^DIAG_2^#",
49+
{ $0.parseClosureExpression() },
50+
diagnostics: [
51+
DiagnosticSpec(locationMarker: "DIAG_1", message: "Expected '' in closure capture item"),
52+
DiagnosticSpec(locationMarker: "DIAG_1", message: "Unexpected text 'class' found in closure capture signature"),
53+
DiagnosticSpec(locationMarker: "DIAG_2", message: "Expected '}' to end closure"),
54+
])
4655
}
4756
}

0 commit comments

Comments
 (0)