Skip to content

Commit 5c4f14f

Browse files
committed
Allow leading dot syntax for StaticParserError
Convert StaticParserError into a struct, and define the diagnostics in a `DiagnosticMessage where Self == StaticParserError` extension. This allows us to use leading dot syntax to pass a StaticParserError anywhere a DiagnosticMessage is expected. To compute the diagnostic ID, we can (ab)use `#function` to pick up the name of the property.
1 parent 1cc5863 commit 5c4f14f

File tree

2 files changed

+82
-30
lines changed

2 files changed

+82
-30
lines changed

Sources/SwiftParser/Diagnostics/ParseDiagnosticsGenerator.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
464464
unexpected: node.output?.unexpectedBetweenArrowAndReturnType,
465465
unexpectedTokenCondition: { $0.tokenKind == .throwsKeyword },
466466
correctTokens: [node.throwsOrRethrowsKeyword],
467-
message: { _ in StaticParserError.throwsInReturnPosition },
467+
message: { _ in .throwsInReturnPosition },
468468
moveFixIt: { MoveTokensInFrontOfFixIt(movedTokens: $0, inFrontOf: .arrow) }
469469
)
470470
return .visitChildren
@@ -501,7 +501,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
501501
unexpected: node.unexpectedBeforeReturnKeyword,
502502
unexpectedTokenCondition: { $0.tokenKind == .tryKeyword },
503503
correctTokens: [node.expression?.as(TryExprSyntax.self)?.tryKeyword],
504-
message: { _ in StaticParserError.tryMustBePlacedOnReturnedExpr },
504+
message: { _ in .tryMustBePlacedOnReturnedExpr },
505505
moveFixIt: { MoveTokensAfterFixIt(movedTokens: $0, after: .returnKeyword) }
506506
)
507507
}
@@ -540,7 +540,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
540540
unexpected: node.unexpectedBeforeThrowKeyword,
541541
unexpectedTokenCondition: { $0.tokenKind == .tryKeyword },
542542
correctTokens: [node.expression.as(TryExprSyntax.self)?.tryKeyword],
543-
message: { _ in StaticParserError.tryMustBePlacedOnThrownExpr },
543+
message: { _ in .tryMustBePlacedOnThrownExpr },
544544
moveFixIt: { MoveTokensAfterFixIt(movedTokens: $0, after: .throwKeyword) }
545545
)
546546
return .visitChildren
@@ -595,7 +595,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
595595
removeToken(
596596
node.unexpectedBetweenIdentifierAndInheritanceClause,
597597
where: { $0.tokenKind == .ellipsis },
598-
message: { _ in StaticParserError.associatedTypeCannotUsePack }
598+
message: { _ in .associatedTypeCannotUsePack }
599599
)
600600
return .visitChildren
601601
}
@@ -611,7 +611,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
611611
unexpected: node.unexpectedBetweenModifiersAndLetOrVarKeyword,
612612
unexpectedTokenCondition: { $0.tokenKind == .tryKeyword },
613613
correctTokens: missingTries,
614-
message: { _ in StaticParserError.tryOnInitialValueExpression },
614+
message: { _ in .tryOnInitialValueExpression },
615615
moveFixIt: { MoveTokensAfterFixIt(movedTokens: $0, after: .equal) },
616616
removeRedundantFixIt: { RemoveRedundantFixIt(removeTokens: $0) }
617617
)

Sources/SwiftParser/Diagnostics/ParserDiagnosticMessages.swift

Lines changed: 77 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -64,38 +64,90 @@ public extension ParserFixIt {
6464

6565
// MARK: - Errors (please sort alphabetically)
6666

67-
/// Please order the cases in this enum alphabetically by case name.
68-
public enum StaticParserError: String, DiagnosticMessage {
69-
case allStatmentsInSwitchMustBeCoveredByCase = "all statements inside a switch must be covered by a 'case' or 'default' label"
70-
case caseOutsideOfSwitchOrEnum = "'case' can only appear inside a 'switch' statement or 'enum' declaration"
71-
case consecutiveDeclarationsOnSameLine = "consecutive declarations on a line must be separated by ';'"
72-
case consecutiveStatementsOnSameLine = "consecutive statements on a line must be separated by ';'"
73-
case cStyleForLoop = "C-style for statement has been removed in Swift 3"
74-
case defaultCannotBeUsedWithWhere = "'default' cannot be used with a 'where' guard expression"
75-
case defaultOutsideOfSwitch = "'default' label can only appear inside a 'switch' statement"
76-
case editorPlaceholderInSourceFile = "editor placeholder in source file"
77-
case expectedExpressionAfterTry = "expected expression after 'try'"
78-
case invalidFlagAfterPrecedenceGroupAssignment = "expected 'true' or 'false' after 'assignment'"
79-
case missingColonInTernaryExprDiagnostic = "expected ':' after '? ...' in ternary expression"
80-
case operatorShouldBeDeclaredWithoutBody = "operator should no longer be declared with body"
81-
case standaloneSemicolonStatement = "standalone ';' statements are not allowed"
82-
case subscriptsCannotHaveNames = "subscripts cannot have a name"
83-
case throwsInReturnPosition = "'throws' may only occur before '->'"
84-
case tryMustBePlacedOnReturnedExpr = "'try' must be placed on the returned expression"
85-
case tryMustBePlacedOnThrownExpr = "'try' must be placed on the thrown expression"
86-
case tryOnInitialValueExpression = "'try' must be placed on the initial value expression"
87-
case unexpectedSemicolon = "unexpected ';' separator"
88-
case associatedTypeCannotUsePack = "associated types cannot be variadic"
89-
90-
public var message: String { self.rawValue }
67+
/// A parser error with a static message.
68+
public struct StaticParserError: DiagnosticMessage {
69+
public let message: String
70+
private let messageID: String
71+
72+
/// This should only be called within a static var on DiagnosticMessage, such
73+
/// as the examples below. This allows us to pick up the messageID from the
74+
/// var name.
75+
fileprivate init(_ message: String, messageID: String = #function) {
76+
self.message = message
77+
self.messageID = messageID
78+
}
9179

9280
public var diagnosticID: MessageID {
93-
MessageID(domain: diagnosticDomain, id: "\(type(of: self)).\(self)")
81+
MessageID(domain: diagnosticDomain, id: "\(type(of: self)).\(messageID)")
9482
}
9583

9684
public var severity: DiagnosticSeverity { .error }
9785
}
9886

87+
extension DiagnosticMessage where Self == StaticParserError {
88+
/// Please order the diagnostics alphabetically by property name.
89+
public static var allStatmentsInSwitchMustBeCoveredByCase: Self {
90+
.init("all statements inside a switch must be covered by a 'case' or 'default' label")
91+
}
92+
public static var associatedTypeCannotUsePack: Self {
93+
.init("associated types cannot be variadic")
94+
}
95+
public static var caseOutsideOfSwitchOrEnum: Self {
96+
.init("'case' can only appear inside a 'switch' statement or 'enum' declaration")
97+
}
98+
public static var consecutiveDeclarationsOnSameLine: Self {
99+
.init("consecutive declarations on a line must be separated by ';'")
100+
}
101+
public static var consecutiveStatementsOnSameLine: Self {
102+
.init("consecutive statements on a line must be separated by ';'")
103+
}
104+
public static var cStyleForLoop: Self {
105+
.init("C-style for statement has been removed in Swift 3")
106+
}
107+
public static var defaultCannotBeUsedWithWhere: Self {
108+
.init("'default' cannot be used with a 'where' guard expression")
109+
}
110+
public static var defaultOutsideOfSwitch: Self {
111+
.init("'default' label can only appear inside a 'switch' statement")
112+
}
113+
public static var editorPlaceholderInSourceFile: Self {
114+
.init("editor placeholder in source file")
115+
}
116+
public static var expectedExpressionAfterTry: Self {
117+
.init("expected expression after 'try'")
118+
}
119+
public static var invalidFlagAfterPrecedenceGroupAssignment: Self {
120+
.init("expected 'true' or 'false' after 'assignment'")
121+
}
122+
public static var missingColonInTernaryExprDiagnostic: Self {
123+
.init("expected ':' after '? ...' in ternary expression")
124+
}
125+
public static var operatorShouldBeDeclaredWithoutBody: Self {
126+
.init("operator should no longer be declared with body")
127+
}
128+
public static var standaloneSemicolonStatement: Self {
129+
.init("standalone ';' statements are not allowed")
130+
}
131+
public static var subscriptsCannotHaveNames: Self {
132+
.init("subscripts cannot have a name")
133+
}
134+
public static var throwsInReturnPosition: Self {
135+
.init("'throws' may only occur before '->'")
136+
}
137+
public static var tryMustBePlacedOnReturnedExpr: Self {
138+
.init("'try' must be placed on the returned expression")
139+
}
140+
public static var tryMustBePlacedOnThrownExpr: Self {
141+
.init("'try' must be placed on the thrown expression")
142+
}
143+
public static var tryOnInitialValueExpression: Self {
144+
.init("'try' must be placed on the initial value expression")
145+
}
146+
public static var unexpectedSemicolon: Self {
147+
.init("unexpected ';' separator")
148+
}
149+
}
150+
99151
// MARK: - Diagnostics (please sort alphabetically)
100152

101153
public struct EffectsSpecifierAfterArrow: ParserError {

0 commit comments

Comments
 (0)