Skip to content

Commit dc80da7

Browse files
CodaFijpsim
authored andcommitted
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 swiftlang#721 rdar://99657721
1 parent f8bd345 commit dc80da7

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
@@ -1689,12 +1689,18 @@ extension Parser {
16891689
arena: self.arena))
16901690
} while keepGoing != nil && loopProgress.evaluate(currentToken)
16911691
}
1692+
// We were promised a right square bracket, so we're going to get it.
1693+
var unexpectedNodes = [RawSyntax]()
1694+
while !self.at(.eof) && !self.at(.rightSquareBracket) && !self.at(.inKeyword) {
1695+
unexpectedNodes.append(RawSyntax(self.consumeAnyToken()))
1696+
}
16921697
let (unexpectedBeforeRSquare, rsquare) = self.expect(.rightSquareBracket)
1698+
unexpectedNodes.append(contentsOf: unexpectedBeforeRSquare?.elements ?? [])
16931699

16941700
captures = RawClosureCaptureSignatureSyntax(
16951701
leftSquare: lsquare,
16961702
items: elements.isEmpty ? nil : RawClosureCaptureItemListSyntax(elements: elements, arena: self.arena),
1697-
unexpectedBeforeRSquare,
1703+
unexpectedNodes.isEmpty ? nil : RawUnexpectedNodesSyntax(elements: unexpectedNodes, arena: self.arena),
16981704
rightSquare: rsquare, arena: self.arena)
16991705
} else {
17001706
captures = nil
@@ -1781,7 +1787,7 @@ extension Parser {
17811787
}
17821788
specifiers.append(self.expectWithoutLookahead(.rightParen))
17831789
}
1784-
} else if (self.currentToken.isIdentifier || self.at(.selfKeyword)) {
1790+
} else if self.currentToken.isIdentifier || self.at(.selfKeyword) {
17851791
let next = self.peek()
17861792
// "x = 42", "x," and "x]" are all strong captures of x.
17871793
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)