Skip to content

Commit b6adf00

Browse files
authored
Merge pull request #1397 from StevenWong12/produce-message-for-named-init
2 parents fbd615b + 2d02851 commit b6adf00

File tree

5 files changed

+87
-18
lines changed

5 files changed

+87
-18
lines changed

Sources/SwiftParser/Declarations.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,7 +1059,7 @@ extension Parser {
10591059
}
10601060

10611061
// Parse the signature.
1062-
let signature = self.parseFunctionSignature()
1062+
let signature = self.parseFunctionSignature(allowOutput: false)
10631063

10641064
let whereClause: RawGenericWhereClauseSyntax?
10651065
if self.at(.keyword(.where)) {
@@ -1389,12 +1389,12 @@ extension Parser {
13891389
}
13901390

13911391
@_spi(RawSyntax)
1392-
public mutating func parseFunctionSignature() -> RawFunctionSignatureSyntax {
1392+
public mutating func parseFunctionSignature(allowOutput: Bool = true) -> RawFunctionSignatureSyntax {
13931393
let input = self.parseParameterClause(for: .functionParameters)
13941394

13951395
var effectSpecifiers = self.parseDeclEffectSpecifiers()
13961396

1397-
let output: RawReturnClauseSyntax?
1397+
var output: RawReturnClauseSyntax?
13981398

13991399
/// Only allow recovery to the arrow with exprKeyword precedence so we only
14001400
/// skip over misplaced identifiers and don't e.g. recover to an arrow in a 'where' clause.
@@ -1404,10 +1404,19 @@ extension Parser {
14041404
output = nil
14051405
}
14061406

1407+
var unexpectedAfterOutput: RawUnexpectedNodesSyntax?
1408+
if !allowOutput,
1409+
let unexpectedOutput = output
1410+
{
1411+
output = nil
1412+
unexpectedAfterOutput = RawUnexpectedNodesSyntax([unexpectedOutput], arena: self.arena)
1413+
}
1414+
14071415
return RawFunctionSignatureSyntax(
14081416
input: input,
14091417
effectSpecifiers: effectSpecifiers,
14101418
output: output,
1419+
unexpectedAfterOutput,
14111420
arena: self.arena
14121421
)
14131422
}

Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,41 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
748748
return .visitChildren
749749
}
750750

751+
public override func visit(_ node: InitializerDeclSyntax) -> SyntaxVisitorContinueKind {
752+
if shouldSkip(node) {
753+
return .skipChildren
754+
}
755+
756+
if let unexpectedName = node.signature.input.unexpectedBeforeLeftParen,
757+
let previous = unexpectedName.previousToken(viewMode: .sourceAccurate)
758+
{
759+
addDiagnostic(
760+
unexpectedName,
761+
.initializerCannotHaveName,
762+
fixIts: [
763+
FixIt(
764+
message: RemoveNodesFixIt(unexpectedName),
765+
changes: [
766+
.makeMissing(unexpectedName),
767+
FixIt.Changes(changes: [.replaceTrailingTrivia(token: previous, newTrivia: .zero)]),
768+
]
769+
)
770+
],
771+
handledNodes: [unexpectedName.id]
772+
)
773+
}
774+
775+
if let unexpectedOutput = node.signature.unexpectedAfterOutput {
776+
addDiagnostic(
777+
unexpectedOutput,
778+
.initializerCannotHaveResultType,
779+
handledNodes: [unexpectedOutput.id]
780+
)
781+
}
782+
783+
return .visitChildren
784+
}
785+
751786
public override func visit(_ node: MemberDeclListItemSyntax) -> SyntaxVisitorContinueKind {
752787
if shouldSkip(node) {
753788
return .skipChildren

Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,12 @@ extension DiagnosticMessage where Self == StaticParserError {
131131
public static var initializerInPattern: Self {
132132
.init("unexpected initializer in pattern; did you mean to use '='?")
133133
}
134+
public static var initializerCannotHaveName: Self {
135+
.init("initializers cannot have a name")
136+
}
137+
public static var initializerCannotHaveResultType: Self {
138+
.init("initializers cannot have a result type")
139+
}
134140
public static var invalidFlagAfterPrecedenceGroupAssignment: Self {
135141
.init("expected 'true' or 'false' after 'assignment'")
136142
}

Tests/SwiftParserTest/translated/InitDeinitTests.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,11 @@ final class InitDeinitTests: XCTestCase {
8383
AssertParse(
8484
"""
8585
struct FooStructConstructorD {
86-
init() -> FooStructConstructorD { }
86+
init() 1️⃣-> FooStructConstructorD { }
8787
}
8888
""",
8989
diagnostics: [
90-
// TODO: Old parser expected error on line 2: initializers cannot have a result type
90+
DiagnosticSpec(message: "initializers cannot have a result type")
9191
]
9292
)
9393
}
@@ -391,6 +391,17 @@ final class InitDeinitTests: XCTestCase {
391391
)
392392
}
393393

394+
func testInitDeinit28() {
395+
AssertParse(
396+
"""
397+
init(_ foo: T) 1️⃣-> Int where T: Comparable {}
398+
""",
399+
diagnostics: [
400+
DiagnosticSpec(message: "initializers cannot have a result type")
401+
]
402+
)
403+
}
404+
394405
func testDeinitInSwiftinterfaceIsFollowedByFinalFunc() {
395406
AssertParse(
396407
"""

Tests/SwiftParserTest/translated/RecoveryTests.swift

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,7 +1741,7 @@ final class RecoveryTests: XCTestCase {
17411741
DiagnosticSpec(locationMarker: "1️⃣", message: "expected '>' to end generic parameter clause"),
17421742
DiagnosticSpec(locationMarker: "2️⃣", message: "expected type and ')' to end parameter clause"),
17431743
DiagnosticSpec(locationMarker: "3️⃣", message: "unexpected code ')}' before struct"),
1744-
DiagnosticSpec(locationMarker: "4️⃣", message: "unexpected code 'x' before parameter clause"),
1744+
DiagnosticSpec(locationMarker: "4️⃣", message: "initializers cannot have a name", fixIts: ["remove 'x'"]),
17451745
]
17461746
)
17471747
}
@@ -1752,9 +1752,11 @@ final class RecoveryTests: XCTestCase {
17521752
init 1️⃣a(b: Int) {}
17531753
""",
17541754
diagnostics: [
1755-
// TODO: (good first issue) Old parser expected error on line 3: initializers cannot have a name, Fix-It replacements: 8 - 9 = ''
1756-
DiagnosticSpec(message: "unexpected code 'a' before parameter clause")
1757-
]
1755+
DiagnosticSpec(message: "initializers cannot have a name", fixIts: ["remove 'a'"])
1756+
],
1757+
fixedSource: """
1758+
init(b: Int) {}
1759+
"""
17581760
)
17591761
}
17601762

@@ -1764,9 +1766,11 @@ final class RecoveryTests: XCTestCase {
17641766
init? 1️⃣c(_ d: Int) {}
17651767
""",
17661768
diagnostics: [
1767-
// TODO: (good first issue) Old parser expected error on line 1: initializers cannot have a name, Fix-It replacements: 9 - 10 = ''
1768-
DiagnosticSpec(message: "unexpected code 'c' before parameter clause")
1769-
]
1769+
DiagnosticSpec(message: "initializers cannot have a name", fixIts: ["remove 'c'"])
1770+
],
1771+
fixedSource: """
1772+
init?(_ d: Int) {}
1773+
"""
17701774
)
17711775
}
17721776

@@ -1776,9 +1780,11 @@ final class RecoveryTests: XCTestCase {
17761780
init 1️⃣e<T>(f: T) {}
17771781
""",
17781782
diagnostics: [
1779-
// TODO: (good first issue) Old parser expected error on line 1: initializers cannot have a name, Fix-It replacements: 8 - 9 = ''
1780-
DiagnosticSpec(message: "unexpected code 'e<T>' before parameter clause")
1781-
]
1783+
DiagnosticSpec(message: "initializers cannot have a name", fixIts: ["remove 'e<T>'"])
1784+
],
1785+
fixedSource: """
1786+
init(f: T) {}
1787+
"""
17821788
)
17831789
}
17841790

@@ -1788,9 +1794,11 @@ final class RecoveryTests: XCTestCase {
17881794
init? 1️⃣g<T>(_: T) {}
17891795
""",
17901796
diagnostics: [
1791-
// TODO: (good first issue) Old parser expected error on line 1: initializers cannot have a name, Fix-It replacements: 9 - 10 = ''
1792-
DiagnosticSpec(message: "unexpected code 'g<T>' before parameter clause")
1793-
]
1797+
DiagnosticSpec(message: "initializers cannot have a name", fixIts: ["remove 'g<T>'"])
1798+
],
1799+
fixedSource: """
1800+
init?(_: T) {}
1801+
"""
17941802
)
17951803
}
17961804

0 commit comments

Comments
 (0)