Skip to content

Commit 7ad2a4f

Browse files
committed
Add missing switch expression error
1 parent 2d42e8d commit 7ad2a4f

File tree

4 files changed

+49
-26
lines changed

4 files changed

+49
-26
lines changed

Sources/SwiftParser/Expressions.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2222,7 +2222,14 @@ extension Parser {
22222222
) -> RawSwitchExprSyntax {
22232223
let (unexpectedBeforeSwitchKeyword, switchKeyword) = self.eat(switchHandle)
22242224

2225-
let subject = self.parseExpression(.basic)
2225+
let subject: RawExprSyntax
2226+
2227+
if self.at(.leftBrace) {
2228+
subject = RawExprSyntax(RawMissingExprSyntax(arena: self.arena))
2229+
} else {
2230+
subject = self.parseExpression(.basic)
2231+
}
2232+
22262233
let (unexpectedBeforeLBrace, lbrace) = self.expect(.leftBrace)
22272234

22282235
let cases = self.parseSwitchCases(allowStandaloneStmtRecovery: !lbrace.isMissing)

Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,18 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
10251025
return .visitChildren
10261026
}
10271027

1028+
public override func visit(_ node: SwitchExprSyntax) -> SyntaxVisitorContinueKind {
1029+
if shouldSkip(node) {
1030+
return .skipChildren
1031+
}
1032+
1033+
if node.expression.is(MissingExprSyntax.self) && !node.cases.isEmpty {
1034+
addDiagnostic(node.expression, .missingExpressionInSwitchStatement, handledNodes: [node.expression.id])
1035+
}
1036+
1037+
return .visitChildren
1038+
}
1039+
10281040
public override func visit(_ node: SwitchCaseSyntax) -> SyntaxVisitorContinueKind {
10291041
if shouldSkip(node) {
10301042
return .skipChildren

Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ extension DiagnosticMessage where Self == StaticParserError {
164164
public static var missingConformanceRequirement: Self {
165165
.init("expected ':' or '==' to indicate a conformance or same-type requirement")
166166
}
167+
public static var missingExpressionInSwitchStatement: Self {
168+
.init("expected expression in 'switch' statement")
169+
}
167170
public static var misspelledAsync: Self {
168171
.init("expected async specifier; did you mean 'async'?")
169172
}

Tests/SwiftParserTest/translated/RecoveryTests.swift

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -621,82 +621,83 @@ final class RecoveryTests: XCTestCase {
621621
func testRecovery46() {
622622
AssertParse(
623623
"""
624-
switch {
625-
}1️⃣
624+
switch 1️⃣{
625+
}
626626
""",
627627
diagnostics: [
628-
// TODO: Old parser expected error on line 1: expected expression in 'switch' statement
628+
DiagnosticSpec(message: "expected expression in 'switch' statement")
629629
// TODO: Old parser expected error on line 1: 'switch' statement body must have at least one 'case' or 'default' block
630-
DiagnosticSpec(message: "expected '{}' in 'switch' statement")
631630
]
632631
)
633632
}
634633

635634
func testRecovery47() {
636635
AssertParse(
637636
"""
638-
switch
637+
switch 1️⃣
639638
{
640-
}1️⃣
639+
}
641640
""",
642641
diagnostics: [
643-
// TODO: Old parser expected error on line 1: expected expression in 'switch' statement
642+
DiagnosticSpec(message: "expected expression in 'switch' statement")
644643
// TODO: Old parser expected error on line 1: 'switch' statement body must have at least one 'case' or 'default' block
645-
DiagnosticSpec(message: "expected '{}' in 'switch' statement")
646644
]
647645
)
648646
}
649647

650648
func testRecovery48() {
651649
AssertParse(
652650
"""
653-
switch {
654-
1️⃣case _: return
655-
}2️⃣
651+
switch 1️⃣{
652+
2️⃣case _: return
653+
}
656654
""",
657655
diagnostics: [
658-
// TODO: Old parser expected error on line 1: expected expression in 'switch' statement
659-
DiagnosticSpec(locationMarker: "1️⃣", message: "'case' can only appear inside a 'switch' statement or 'enum' declaration"),
660-
DiagnosticSpec(locationMarker: "2️⃣", message: "expected '{}' in 'switch' statement"),
656+
DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression in 'switch' statement")
661657
]
662658
)
663659
}
664660

665661
func testRecovery49() {
666662
AssertParse(
667663
"""
668-
switch {
669-
1️⃣case Int: return
670-
2️⃣case _: return
671-
}3️⃣
664+
switch 1️⃣{
665+
case Int: return
666+
case _: return
667+
}
672668
""",
673669
diagnostics: [
674-
// TODO: Old parser expected error on line 1: expected expression in 'switch' statement
670+
DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression in 'switch' statement"),
675671
// TODO: Old parser expected error on line 2: 'is' keyword required to pattern match against type name, Fix-It replacements: 10 - 10 = 'is '
676-
DiagnosticSpec(locationMarker: "1️⃣", message: "'case' can only appear inside a 'switch' statement or 'enum' declaration"),
677672
DiagnosticSpec(locationMarker: "2️⃣", message: "'case' can only appear inside a 'switch' statement or 'enum' declaration"),
678-
DiagnosticSpec(locationMarker: "3️⃣", message: "expected '{}' in 'switch' statement"),
673+
DiagnosticSpec(locationMarker: "3️⃣", message: "'case' can only appear inside a 'switch' statement or 'enum' declaration"),
679674
]
680675
)
681676
}
682677

683678
func testRecovery50() {
684679
AssertParse(
685680
"""
686-
switch { 42 } {
681+
switch 1️⃣{ 42 } {
687682
case _: return
688683
}
689-
"""
684+
""",
685+
diagnostics: [
686+
DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression in 'switch' statement")
687+
]
690688
)
691689
}
692690

693691
func testRecovery51() {
694692
AssertParse(
695693
"""
696-
switch { 42 }() {
694+
switch 1️⃣{ 42 }() {
697695
case _: return
698696
}
699-
"""
697+
""",
698+
diagnostics: [
699+
DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression in 'switch' statement")
700+
]
700701
)
701702
}
702703

0 commit comments

Comments
 (0)