Skip to content

Commit c40fd0d

Browse files
authored
Merge pull request #1763 from DougGregor/freestanding-macro-role-message-5.9
2 parents 7be636b + bdcd582 commit c40fd0d

File tree

5 files changed

+116
-22
lines changed

5 files changed

+116
-22
lines changed

Sources/SwiftCompilerPluginMessageHandling/CompilerPluginMessageHandler.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,10 @@ extension CompilerPluginMessageHandler {
8787
)
8888
try self.sendMessage(.getCapabilityResult(capability: capability))
8989

90-
case .expandFreestandingMacro(let macro, let discriminator, let expandingSyntax):
90+
case .expandFreestandingMacro(let macro, let macroRole, let discriminator, let expandingSyntax):
9191
try expandFreestandingMacro(
9292
macro: macro,
93+
macroRole: macroRole,
9394
discriminator: discriminator,
9495
expandingSyntax: expandingSyntax
9596
)

Sources/SwiftCompilerPluginMessageHandling/Diagnostics.swift

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,28 @@ import SwiftDiagnostics
1414
import SwiftSyntax
1515

1616
/// Errors in macro handing.
17-
enum MacroExpansionError: String {
18-
case macroTypeNotFound = "macro expanding type not found"
19-
case unmathedMacroRole = "macro doesn't conform to required macro role"
20-
case freestandingMacroSyntaxIsNotMacro = "macro syntax couldn't be parsed"
21-
case invalidExpansionMessage = "internal message error; please file a bug report"
17+
enum MacroExpansionError {
18+
case macroTypeNotFound(PluginMessage.MacroReference)
19+
case freestandingMacroSyntaxIsNotMacro
20+
case invalidExpansionMessage
21+
case invalidMacroRole(PluginMessage.MacroRole)
2222
}
2323

2424
extension MacroExpansionError: DiagnosticMessage {
2525
var message: String {
26-
self.rawValue
26+
switch self {
27+
case .macroTypeNotFound(let ref):
28+
return "macro type '\(ref.moduleName).\(ref.typeName)' not found when expanding macro '\(ref.name)'"
29+
30+
case .freestandingMacroSyntaxIsNotMacro:
31+
return "macro syntax couldn't be parsed"
32+
33+
case .invalidExpansionMessage:
34+
return "internal message error; please file a bug report"
35+
36+
case .invalidMacroRole(let role):
37+
return "invalid macro role '\(role)' for expansion"
38+
}
2739
}
2840
var diagnosticID: SwiftDiagnostics.MessageID {
2941
.init(domain: "SwiftCompilerPlugin", id: "\(type(of: self)).\(self)")

Sources/SwiftCompilerPluginMessageHandling/Macros.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ extension CompilerPluginMessageHandler {
2626
/// Expand `@freestainding(XXX)` macros.
2727
func expandFreestandingMacro(
2828
macro: PluginMessage.MacroReference,
29+
macroRole pluginMacroRole: PluginMessage.MacroRole?,
2930
discriminator: String,
3031
expandingSyntax: PluginMessage.Syntax
3132
) throws {
@@ -43,11 +44,19 @@ extension CompilerPluginMessageHandler {
4344
throw MacroExpansionError.freestandingMacroSyntaxIsNotMacro
4445
}
4546
guard let macroDefinition = resolveMacro(macro) else {
46-
throw MacroExpansionError.macroTypeNotFound
47+
throw MacroExpansionError.macroTypeNotFound(macro)
48+
}
49+
50+
let macroRole: MacroRole
51+
if let pluginMacroRole {
52+
macroRole = MacroRole(messageMacroRole: pluginMacroRole)
53+
} else {
54+
macroRole = try inferFreestandingMacroRole(definition: macroDefinition)
4755
}
4856

4957
expandedSource = SwiftSyntaxMacroExpansion.expandFreestandingMacro(
5058
definition: macroDefinition,
59+
macroRole: macroRole,
5160
node: macroSyntax,
5261
in: context
5362
)
@@ -89,7 +98,7 @@ extension CompilerPluginMessageHandler {
8998
let expandedSources: [String]?
9099
do {
91100
guard let macroDefinition = resolveMacro(macro) else {
92-
throw MacroExpansionError.macroTypeNotFound
101+
throw MacroExpansionError.macroTypeNotFound(macro)
93102
}
94103

95104
expandedSources = SwiftSyntaxMacroExpansion.expandAttachedMacro(

Sources/SwiftCompilerPluginMessageHandling/PluginMessages.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ internal enum HostToPluginMessage: Codable {
2020
/// Expand a '@freestanding' macro.
2121
case expandFreestandingMacro(
2222
macro: PluginMessage.MacroReference,
23+
macroRole: PluginMessage.MacroRole? = nil,
2324
discriminator: String,
2425
syntax: PluginMessage.Syntax
2526
)

Sources/SwiftSyntaxMacroExpansion/MacroExpansion.swift

Lines changed: 84 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,37 +12,74 @@ public enum MacroRole {
1212
case codeItem
1313
}
1414

15+
extension MacroRole {
16+
var protocolName: String {
17+
switch self {
18+
case .expression: return "ExpressionMacro"
19+
case .declaration: return "DeclarationMacro"
20+
case .accessor: return "AccessorMacro"
21+
case .memberAttribute: return "MemberAttributeMacro"
22+
case .member: return "MemberMacro"
23+
case .peer: return "PeerMacro"
24+
case .conformance: return "ConformanceMacro"
25+
case .codeItem: return "CodeItemMacro"
26+
}
27+
}
28+
}
29+
1530
/// Simple diagnostic message
16-
private enum MacroExpansionError: String, Error, CustomStringConvertible {
17-
case unmathedMacroRole = "macro doesn't conform to required macro role"
18-
case parentDeclGroupNil = "parent decl group is nil"
19-
case declarationNotDeclGroup = "declaration is not a decl group syntax"
20-
case declarationNotIdentified = "declaration is not a 'Identified' syntax"
21-
var description: String { self.rawValue }
31+
private enum MacroExpansionError: Error, CustomStringConvertible {
32+
case unmatchedMacroRole(Macro.Type, MacroRole)
33+
case parentDeclGroupNil
34+
case declarationNotDeclGroup
35+
case declarationNotIdentified
36+
case noFreestandingMacroRoles(Macro.Type)
37+
38+
var description: String {
39+
switch self {
40+
case .unmatchedMacroRole(let type, let role):
41+
return "macro implementation type '\(type)' doesn't conform to required protocol '\(role.protocolName)'"
42+
43+
case .parentDeclGroupNil:
44+
return "parent decl group is nil"
45+
46+
case .declarationNotDeclGroup:
47+
return "declaration is not a decl group syntax"
48+
49+
case .declarationNotIdentified:
50+
return "declaration is not a 'Identified' syntax"
51+
52+
case .noFreestandingMacroRoles(let type):
53+
return "macro implementation type '\(type)' does not conform to any freestanding macro protocol"
54+
55+
}
56+
}
2257
}
2358

2459
/// Expand `@freestanding(XXX)` macros.
2560
///
2661
/// - Parameters:
2762
/// - definition: a type conforms to one of freestanding `Macro` protocol.
63+
/// - macroRole: indicates which `Macro` protocol expansion should be performed
2864
/// - node: macro expansion syntax node (e.g. `#macroName(argument)`).
2965
/// - in: context of the expansion.
3066
/// - Returns: expanded source text. Upon failure (i.e. `defintion.expansion()`
3167
/// throws) returns `nil`, and the diagnostics representing the `Error` are
3268
/// guaranteed to be added to context.
3369
public func expandFreestandingMacro(
3470
definition: Macro.Type,
71+
macroRole: MacroRole,
3572
node: FreestandingMacroExpansionSyntax,
3673
in context: some MacroExpansionContext
3774
) -> String? {
3875
do {
3976
func _expand(node: some FreestandingMacroExpansionSyntax) throws -> String {
4077
let expandedSyntax: Syntax
41-
switch definition {
42-
case let exprMacroDef as ExpressionMacro.Type:
78+
switch (macroRole, definition) {
79+
case (.expression, let exprMacroDef as ExpressionMacro.Type):
4380
expandedSyntax = try Syntax(exprMacroDef.expansion(of: node, in: context))
4481

45-
case let declMacroDef as DeclarationMacro.Type:
82+
case (.declaration, let declMacroDef as DeclarationMacro.Type):
4683
var rewritten = try declMacroDef.expansion(of: node, in: context)
4784
// Copy attributes and modifiers to the generated decls.
4885
if let expansionDecl = node.as(MacroExpansionDeclSyntax.self) {
@@ -60,12 +97,13 @@ public func expandFreestandingMacro(
6097
)
6198
)
6299

63-
case let codeItemMacroDef as CodeItemMacro.Type:
100+
case (.codeItem, let codeItemMacroDef as CodeItemMacro.Type):
64101
let rewritten = try codeItemMacroDef.expansion(of: node, in: context)
65102
expandedSyntax = Syntax(CodeBlockItemListSyntax(rewritten))
66103

67-
default:
68-
throw MacroExpansionError.unmathedMacroRole
104+
case (.accessor, _), (.memberAttribute, _), (.member, _), (.peer, _), (.conformance, _), (.expression, _), (.declaration, _),
105+
(.codeItem, _):
106+
throw MacroExpansionError.unmatchedMacroRole(definition, macroRole)
69107
}
70108
return expandedSyntax.formattedExpansion(definition.formatMode)
71109
}
@@ -76,6 +114,39 @@ public func expandFreestandingMacro(
76114
}
77115
}
78116

117+
/// Try to infer the freestanding macro role from the type definition itself.
118+
///
119+
/// This is a workaround for older compilers with a newer plugin
120+
public func inferFreestandingMacroRole(definition: Macro.Type) throws -> MacroRole {
121+
switch definition {
122+
case is ExpressionMacro.Type: return .expression
123+
case is DeclarationMacro.Type: return .declaration
124+
case is CodeItemMacro.Type: return .codeItem
125+
126+
default:
127+
throw MacroExpansionError.noFreestandingMacroRoles(definition)
128+
}
129+
}
130+
131+
@available(*, deprecated, message: "pass a macro role, please!")
132+
public func expandFreestandingMacro(
133+
definition: Macro.Type,
134+
node: FreestandingMacroExpansionSyntax,
135+
in context: some MacroExpansionContext
136+
) -> String? {
137+
do {
138+
return expandFreestandingMacro(
139+
definition: definition,
140+
macroRole: try inferFreestandingMacroRole(definition: definition),
141+
node: node,
142+
in: context
143+
)
144+
} catch {
145+
context.addDiagnostics(from: error, node: node)
146+
return nil
147+
}
148+
}
149+
79150
/// Expand `@attached(XXX)` macros.
80151
///
81152
/// - Parameters:
@@ -213,7 +284,7 @@ public func expandAttachedMacro<Context: MacroExpansionContext>(
213284
}
214285

215286
default:
216-
throw MacroExpansionError.unmathedMacroRole
287+
throw MacroExpansionError.unmatchedMacroRole(definition, macroRole)
217288
}
218289
} catch {
219290
context.addDiagnostics(from: error, node: attributeNode)

0 commit comments

Comments
 (0)