@@ -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.
3369public 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