Skip to content

Commit 7b1cee2

Browse files
authored
Merge pull request #885 from flashspys/detect-missing-type-colon
Detect and recover from missing type colon
2 parents 9d13a48 + b289029 commit 7b1cee2

File tree

3 files changed

+33
-10
lines changed

3 files changed

+33
-10
lines changed

Sources/SwiftParser/Patterns.swift

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -120,20 +120,33 @@ extension Parser {
120120
/// =======
121121
///
122122
/// typed-pattern → pattern ':' attributes? inout? type
123-
mutating func parseTypedPattern() -> (RawPatternSyntax, RawTypeAnnotationSyntax?) {
123+
mutating func parseTypedPattern(allowRecoveryFromMissingColon: Bool = true) -> (RawPatternSyntax, RawTypeAnnotationSyntax?) {
124124
let pattern = self.parsePattern()
125125

126126
// Now parse an optional type annotation.
127-
guard let colon = self.consume(if: .colon) else {
128-
return (pattern, nil)
127+
let colon = self.consume(if: .colon)
128+
var lookahead = self.lookahead()
129+
var type: RawTypeAnnotationSyntax?
130+
if let colon = colon {
131+
let result = self.parseResultType()
132+
type = RawTypeAnnotationSyntax(
133+
colon: colon,
134+
type: result,
135+
arena: self.arena
136+
)
137+
} else if allowRecoveryFromMissingColon
138+
&& !self.currentToken.isAtStartOfLine
139+
&& lookahead.canParseType() {
140+
// Recovery if the user forgot to add ':'
141+
let result = self.parseResultType()
142+
type = RawTypeAnnotationSyntax(
143+
colon: self.missingToken(.colon, text: nil),
144+
type: result,
145+
arena: self.arena
146+
)
129147
}
130148

131-
let result = self.parseResultType()
132-
let type = RawTypeAnnotationSyntax(
133-
colon: colon,
134-
type: result,
135-
arena: self.arena
136-
)
149+
137150
return (pattern, type)
138151
}
139152

Sources/SwiftParser/Statements.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ extension Parser {
580580
type = nil
581581
}
582582
} else {
583-
(pattern, type) = self.parseTypedPattern()
583+
(pattern, type) = self.parseTypedPattern(allowRecoveryFromMissingColon: false)
584584
}
585585

586586
let (unexpectedBeforeInKeyword, inKeyword) = self.expect(.inKeyword)

Tests/SwiftParserTest/Types.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@
33
import XCTest
44

55
final class TypeTests: XCTestCase {
6+
7+
func testMissingColonInType() {
8+
AssertParse(
9+
"""
10+
var foo 1️⃣Bar = 1
11+
""", diagnostics: [
12+
DiagnosticSpec(message: "expected ':' in type annotation")
13+
])
14+
}
15+
616
func testClosureParsing() throws {
717
AssertParse(
818
"(a, b) -> c",

0 commit comments

Comments
 (0)