Skip to content

Commit ef9a434

Browse files
authored
Merge pull request #1370 from ahoppen/ahoppen/open
Fix a misparser where we would classify a call to 'open' as a DeclModifier
2 parents 39e9c75 + 701743d commit ef9a434

File tree

3 files changed

+83
-4
lines changed

3 files changed

+83
-4
lines changed

Sources/SwiftParser/Declarations.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ extension TokenConsumer {
6060
modifierProgress.evaluate(subparser.currentToken)
6161
{
6262
subparser.eat(handle)
63-
if subparser.at(.leftParen) && modifierKind.canHaveParenthesizedArgument {
63+
if modifierKind != .open && subparser.at(.leftParen) && modifierKind.canHaveParenthesizedArgument {
64+
// When determining whether we are at a declaration, don't consume anything in parentheses after 'open'
65+
// so we don't consider a function call to open as a decl modifier. This matches the C++ parser.
6466
subparser.consumeAnyToken()
6567
subparser.consume(to: .rightParen)
6668
}
@@ -100,7 +102,7 @@ extension TokenConsumer {
100102
var lookahead = subparser.lookahead()
101103
repeat {
102104
lookahead.consumeAnyToken()
103-
} while lookahead.atStartOfDeclaration(allowInitDecl: allowInitDecl)
105+
} while lookahead.atStartOfDeclaration(isAtTopLevel: isAtTopLevel, allowInitDecl: allowInitDecl)
104106
return lookahead.at(.identifier)
105107
case .caseKeyword:
106108
// When 'case' appears inside a function, it's probably a switch

Sources/SwiftParser/TopLevel.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ extension Parser {
249249
return .decl(RawDeclSyntax(directive))
250250
} else if self.at(.poundSourceLocationKeyword) {
251251
return .decl(RawDeclSyntax(self.parsePoundSourceLocationDirective()))
252-
} else if self.atStartOfDeclaration(allowInitDecl: allowInitDecl) {
252+
} else if self.atStartOfDeclaration(isAtTopLevel: isAtTopLevel, allowInitDecl: allowInitDecl) {
253253
return .decl(self.parseDeclaration())
254254
} else if self.atStartOfStatement() {
255255
return self.parseStatementItem()

Tests/SwiftParserTest/DeclarationTests.swift

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,11 @@ final class DeclarationTests: XCTestCase {
286286
fileprivate fileprivate(set) var fileprivateProp = 0
287287
private private(set) var privateProp = 0
288288
internal(set) var defaultProp = 0
289-
"""
289+
""",
290+
diagnostics: [
291+
DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'"),
292+
DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'"),
293+
]
290294
)
291295

292296
AssertParse(
@@ -1408,6 +1412,79 @@ final class DeclarationTests: XCTestCase {
14081412
"""
14091413
)
14101414
}
1415+
1416+
func testCallToOpenThatLooksLikeDeclarationModifier() {
1417+
AssertParse(
1418+
"""
1419+
func test() {
1420+
open(set)
1421+
var foo = 2
1422+
}
1423+
""",
1424+
substructure: Syntax(
1425+
FunctionCallExprSyntax(
1426+
calledExpression: IdentifierExprSyntax(identifier: .identifier("open")),
1427+
leftParen: .leftParenToken(),
1428+
argumentList: TupleExprElementListSyntax([
1429+
TupleExprElementSyntax(
1430+
expression: IdentifierExprSyntax(identifier: .identifier("set"))
1431+
)
1432+
]),
1433+
rightParen: .rightParenToken()
1434+
)
1435+
)
1436+
)
1437+
}
1438+
1439+
func testReferenceToOpenThatLooksLikeDeclarationModifier() {
1440+
// Ideally, this should be parsed as an identifier expression to 'open',
1441+
// followed by a variable declaration but the current behavior matches the C++ parser.
1442+
AssertParse(
1443+
"""
1444+
func test() {
1445+
open
1446+
var foo = 2
1447+
}
1448+
""",
1449+
substructure: Syntax(
1450+
VariableDeclSyntax(
1451+
modifiers: ModifierListSyntax([
1452+
DeclModifierSyntax(name: .keyword(.open))
1453+
]),
1454+
bindingKeyword: .keyword(.var),
1455+
bindings: PatternBindingListSyntax([
1456+
PatternBindingSyntax(
1457+
pattern: IdentifierPatternSyntax(identifier: .identifier("foo")),
1458+
initializer: InitializerClauseSyntax(
1459+
value: IntegerLiteralExprSyntax(digits: .integerLiteral("2"))
1460+
)
1461+
)
1462+
])
1463+
)
1464+
)
1465+
)
1466+
}
1467+
1468+
func testOpenVarInCodeBlockItemList() {
1469+
AssertParse(
1470+
"""
1471+
func test() {
1472+
open var foo = 2
1473+
}
1474+
""",
1475+
substructure: Syntax(DeclModifierSyntax(name: .keyword(.open)))
1476+
)
1477+
}
1478+
1479+
func testAsyncLetInLocalContext() {
1480+
AssertParse(
1481+
"""
1482+
func foo() async {
1483+
async let x: String = "x"
1484+
}
1485+
"""
1486+
)
1487+
}
14111488
}
14121489

14131490
extension Parser.DeclAttributes {

0 commit comments

Comments
 (0)