@@ -12,37 +12,74 @@ public enum MacroRole {
12
12
case codeItem
13
13
}
14
14
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
+
15
30
/// 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
+ }
22
57
}
23
58
24
59
/// Expand `@freestanding(XXX)` macros.
25
60
///
26
61
/// - Parameters:
27
62
/// - definition: a type conforms to one of freestanding `Macro` protocol.
63
+ /// - macroRole: indicates which `Macro` protocol expansion should be performed
28
64
/// - node: macro expansion syntax node (e.g. `#macroName(argument)`).
29
65
/// - in: context of the expansion.
30
66
/// - Returns: expanded source text. Upon failure (i.e. `defintion.expansion()`
31
67
/// throws) returns `nil`, and the diagnostics representing the `Error` are
32
68
/// guaranteed to be added to context.
33
69
public func expandFreestandingMacro(
34
70
definition: Macro . Type ,
71
+ macroRole: MacroRole ,
35
72
node: FreestandingMacroExpansionSyntax ,
36
73
in context: some MacroExpansionContext
37
74
) -> String ? {
38
75
do {
39
76
func _expand( node: some FreestandingMacroExpansionSyntax ) throws -> String {
40
77
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 ) :
43
80
expandedSyntax = try Syntax ( exprMacroDef. expansion ( of: node, in: context) )
44
81
45
- case let declMacroDef as DeclarationMacro . Type :
82
+ case ( . declaration , let declMacroDef as DeclarationMacro . Type ) :
46
83
var rewritten = try declMacroDef. expansion ( of: node, in: context)
47
84
// Copy attributes and modifiers to the generated decls.
48
85
if let expansionDecl = node. as ( MacroExpansionDeclSyntax . self) {
@@ -60,12 +97,13 @@ public func expandFreestandingMacro(
60
97
)
61
98
)
62
99
63
- case let codeItemMacroDef as CodeItemMacro . Type :
100
+ case ( . codeItem , let codeItemMacroDef as CodeItemMacro . Type ) :
64
101
let rewritten = try codeItemMacroDef. expansion ( of: node, in: context)
65
102
expandedSyntax = Syntax ( CodeBlockItemListSyntax ( rewritten) )
66
103
67
- default :
68
- throw MacroExpansionError . unmathedMacroRole
104
+ case ( . accessor, _) , ( . memberAttribute, _) , ( . member, _) , ( . peer, _) , ( . conformance, _) , ( . expression, _) , ( . declaration, _) ,
105
+ ( . codeItem, _) :
106
+ throw MacroExpansionError . unmatchedMacroRole ( definition, macroRole)
69
107
}
70
108
return expandedSyntax. formattedExpansion ( definition. formatMode)
71
109
}
@@ -76,6 +114,39 @@ public func expandFreestandingMacro(
76
114
}
77
115
}
78
116
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
+
79
150
/// Expand `@attached(XXX)` macros.
80
151
///
81
152
/// - Parameters:
@@ -213,7 +284,7 @@ public func expandAttachedMacro<Context: MacroExpansionContext>(
213
284
}
214
285
215
286
default :
216
- throw MacroExpansionError . unmathedMacroRole
287
+ throw MacroExpansionError . unmatchedMacroRole ( definition , macroRole )
217
288
}
218
289
} catch {
219
290
context. addDiagnostics ( from: error, node: attributeNode)
0 commit comments