Skip to content

Commit 5f8e664

Browse files
authored
Merge pull request #2727 from AppAppWorks/improve-diagnostic-for-unnamed-closure-parameter
improve diagnostic for unnamed closure parameters
2 parents 15b8ace + 55cd304 commit 5f8e664

File tree

2 files changed

+86
-2
lines changed

2 files changed

+86
-2
lines changed

Sources/SwiftParser/Parameters.swift

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,23 @@ extension Parser {
160160
let misplacedSpecifiers = parseMisplacedSpecifiers()
161161

162162
let names = self.parseParameterNames()
163-
let colon = self.consume(if: .colon)
163+
var colon = self.consume(if: .colon)
164+
// try to parse the type regardless of the presence of the preceding colon
165+
// to tackle any unnamed parameter or missing colon
166+
// e.g. [X], (:[X]) or (x [X])
167+
let canParseType = withLookahead { $0.canParseType() }
164168
let type: RawTypeSyntax?
165-
if colon != nil {
169+
if canParseType {
166170
type = self.parseType(misplacedSpecifiers: misplacedSpecifiers)
171+
if colon == nil {
172+
// mark the preceding colon as missing if the type is present
173+
// e.g. [X] or (x [X])
174+
colon = missingToken(.colon)
175+
}
176+
} else if colon != nil {
177+
// mark the type as missing if the preceding colon is present
178+
// e.g. (:) or (_:)
179+
type = RawTypeSyntax(RawMissingTypeSyntax(arena: self.arena))
167180
} else {
168181
type = nil
169182
}

Tests/SwiftParserTest/ExpressionTests.swift

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2875,6 +2875,77 @@ final class StatementExpressionTests: ParserTestCase {
28752875
)
28762876
}
28772877
2878+
func testClosureWithMalformedParameters() {
2879+
assertParse(
2880+
"""
2881+
test { (1️⃣[X]) in }
2882+
""",
2883+
diagnostics: [
2884+
DiagnosticSpec(message: "expected identifier and ':' in parameter", fixIts: ["insert identifier and ':'"])
2885+
],
2886+
fixedSource: """
2887+
test { (<#identifier#>: [X]) in }
2888+
"""
2889+
)
2890+
2891+
assertParse(
2892+
"""
2893+
test { (1️⃣: [X]) in }
2894+
""",
2895+
diagnostics: [
2896+
DiagnosticSpec(message: "expected identifier in parameter", fixIts: ["insert identifier"])
2897+
],
2898+
fixedSource: """
2899+
test { (<#identifier#>: [X]) in }
2900+
"""
2901+
)
2902+
2903+
assertParse(
2904+
"""
2905+
test { (1️⃣:2️⃣) in }
2906+
""",
2907+
diagnostics: [
2908+
DiagnosticSpec(
2909+
locationMarker: "1️⃣",
2910+
message: "expected identifier in parameter",
2911+
fixIts: ["insert identifier"]
2912+
),
2913+
DiagnosticSpec(
2914+
locationMarker: "2️⃣",
2915+
message: "expected type in parameter",
2916+
fixIts: ["insert type"]
2917+
),
2918+
],
2919+
fixedSource: """
2920+
test { (<#identifier#>: <#type#>) in }
2921+
"""
2922+
)
2923+
2924+
assertParse(
2925+
"""
2926+
test { (foo1️⃣ @bar baz) in }
2927+
""",
2928+
diagnostics: [
2929+
DiagnosticSpec(message: "expected ':' in parameter", fixIts: ["insert ':'"])
2930+
],
2931+
fixedSource: """
2932+
test { (foo: @bar baz) in }
2933+
"""
2934+
)
2935+
2936+
assertParse(
2937+
"""
2938+
test { (x: 1️⃣) in }
2939+
""",
2940+
diagnostics: [
2941+
DiagnosticSpec(message: "expected type in parameter", fixIts: ["insert type"])
2942+
],
2943+
fixedSource: """
2944+
test { (x: <#type#>) in }
2945+
"""
2946+
)
2947+
}
2948+
28782949
func testTypedThrowsDisambiguation() {
28792950
assertParse(
28802951
"[() throws(MyError) 1️⃣async -> Void]()",

0 commit comments

Comments
 (0)