Skip to content

Commit 7a7c56a

Browse files
committed
Make unowned parsing accept RecoveryConsumptionHandle
Mark modifiers after fixity unexpected
1 parent dab15c3 commit 7a7c56a

File tree

5 files changed

+56
-9
lines changed

5 files changed

+56
-9
lines changed

Sources/SwiftParser/Declarations.swift

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,26 +1717,31 @@ extension Parser {
17171717
var unexpectedBeforeFixity = RawUnexpectedNodesSyntax(attrs.attributes?.elements ?? [], arena: self.arena)
17181718

17191719
var fixity: RawTokenSyntax?
1720-
var leftInFixityModifier: RawUnexpectedNodesSyntax?
1720+
var unexpectedAfterFixity: RawUnexpectedNodesSyntax?
17211721

17221722
if let modifiers = attrs.modifiers?.elements {
17231723
if let firstFixityIndex = modifiers.firstIndex(where: { isFixity($0) }) {
17241724
let fixityModifier = modifiers[firstFixityIndex]
17251725
fixity = fixityModifier.name
17261726

1727-
leftInFixityModifier = RawUnexpectedNodesSyntax(combining: fixityModifier.unexpectedBetweenNameAndDetail, RawUnexpectedNodesSyntax([fixityModifier.detail], arena: self.arena), fixityModifier.unexpectedAfterDetail, arena: self.arena)
1727+
unexpectedBeforeFixity = RawUnexpectedNodesSyntax(combining: unexpectedBeforeFixity, RawUnexpectedNodesSyntax(Array(modifiers[0..<firstFixityIndex]), arena: self.arena), fixityModifier.unexpectedBeforeName, arena: self.arena)
17281728

1729-
let beforeFixity = Array(modifiers[0..<firstFixityIndex])
1729+
unexpectedAfterFixity = RawUnexpectedNodesSyntax(
1730+
combining: fixityModifier.unexpectedBetweenNameAndDetail,
1731+
RawUnexpectedNodesSyntax([fixityModifier.detail], arena: self.arena),
1732+
fixityModifier.unexpectedAfterDetail,
1733+
RawUnexpectedNodesSyntax(Array(modifiers[modifiers.index(after: firstFixityIndex)...]), arena: self.arena),
1734+
arena: self.arena
1735+
)
17301736

1731-
unexpectedBeforeFixity = RawUnexpectedNodesSyntax(combining: unexpectedBeforeFixity, RawUnexpectedNodesSyntax(beforeFixity, arena: self.arena), fixityModifier.unexpectedBeforeName, arena: self.arena)
17321737
} else {
17331738
unexpectedBeforeFixity = RawUnexpectedNodesSyntax(combining: unexpectedBeforeFixity, RawUnexpectedNodesSyntax(modifiers, arena: self.arena), arena: self.arena)
17341739
}
17351740
}
17361741

17371742
var (unexpectedBeforeOperatorKeyword, operatorKeyword) = self.expect(.keyword(.operator))
17381743

1739-
unexpectedBeforeOperatorKeyword = RawUnexpectedNodesSyntax(combining: leftInFixityModifier, unexpectedBeforeOperatorKeyword, arena: self.arena)
1744+
unexpectedBeforeOperatorKeyword = RawUnexpectedNodesSyntax(combining: unexpectedAfterFixity, unexpectedBeforeOperatorKeyword, arena: self.arena)
17401745

17411746
return OperatorDeclIntroducer(
17421747
unexpectedBeforeFixity: unexpectedBeforeFixity,

Sources/SwiftParser/Modifiers.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ extension Parser {
5858
} else {
5959
break MODIFIER_LOOP
6060
}
61-
case (.declarationModifier(.unowned), _)?:
62-
elements.append(self.parseUnownedModifier())
61+
case (.declarationModifier(.unowned), let handle)?:
62+
elements.append(self.parseUnownedModifier(handle))
6363
case (.declarationModifier(.final), let handle)?,
6464
(.declarationModifier(.required), let handle)?,
6565
(.declarationModifier(.optional), let handle)?,
@@ -113,8 +113,8 @@ extension Parser {
113113
)
114114
}
115115

116-
mutating func parseUnownedModifier() -> RawDeclModifierSyntax {
117-
let (unexpectedBeforeKeyword, keyword) = self.expect(.keyword(.unowned))
116+
mutating func parseUnownedModifier(_ handle: RecoveryConsumptionHandle) -> RawDeclModifierSyntax {
117+
let (unexpectedBeforeKeyword, keyword) = self.eat(handle)
118118

119119
let detail: RawDeclModifierDetailSyntax?
120120
if self.at(.leftParen) {

Sources/SwiftParser/SyntaxUtils.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ extension RawUnexpectedNodesSyntax {
8080
init?(combining syntax1: some UnexpectedNodesCombinable, _ syntax2: some UnexpectedNodesCombinable, _ syntax3: some UnexpectedNodesCombinable, arena: __shared SyntaxArena) {
8181
self.init(syntax1.elements + syntax2.elements + syntax3.elements, arena: arena)
8282
}
83+
84+
init?(combining syntax1: some UnexpectedNodesCombinable, _ syntax2: some UnexpectedNodesCombinable, _ syntax3: some UnexpectedNodesCombinable, _ syntax4: some UnexpectedNodesCombinable, arena: __shared SyntaxArena) {
85+
self.init(syntax1.elements + syntax2.elements + syntax3.elements + syntax4.elements, arena: arena)
86+
}
8387
}
8488

8589
// MARK: - Misc

Tests/SwiftParserTest/DeclarationTests.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2163,4 +2163,31 @@ final class DeclarationTests: XCTestCase {
21632163
]
21642164
)
21652165
}
2166+
2167+
func testUnexpectedTokenInClassFollowedByUnownedModifier() {
2168+
assertParse(
2169+
"""
2170+
class A ℹ️{
2171+
1️⃣^
2172+
}
2173+
unowned 2️⃣B 3️⃣{
2174+
}4️⃣
2175+
""",
2176+
diagnostics: [
2177+
DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected code before modifier"),
2178+
DiagnosticSpec(locationMarker: "2️⃣", message: "expected 'func' in function", fixIts: ["insert 'func'"]),
2179+
DiagnosticSpec(locationMarker: "3️⃣", message: "expected parameter clause in function signature", fixIts: ["insert parameter clause"]),
2180+
DiagnosticSpec(locationMarker: "4️⃣", message: "expected '}' to end class", notes: [NoteSpec(message: "to match this opening '{'")], fixIts: ["insert '}'"]),
2181+
],
2182+
fixedSource:
2183+
"""
2184+
class A {
2185+
^
2186+
}
2187+
unowned func B() {
2188+
}
2189+
}
2190+
"""
2191+
)
2192+
}
21662193
}

Tests/SwiftParserTest/translated/OperatorDeclTests.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,17 @@ final class OperatorDeclTests: XCTestCase {
598598
)
599599
}
600600

601+
func testMultipleFixity() {
602+
assertParse(
603+
"""
604+
prefix 1️⃣infix operator &+&
605+
""",
606+
diagnostics: [
607+
DiagnosticSpec(message: "unexpected code 'infix' in operator declaration")
608+
]
609+
)
610+
}
611+
601612
func testIdentifierAsOperatorName() {
602613
assertParse(
603614
"postfix operator 1️⃣aa",

0 commit comments

Comments
 (0)