@@ -22,6 +22,7 @@ public enum MacroRole {
22
22
case peer
23
23
case conformance
24
24
case codeItem
25
+ case `extension`
25
26
}
26
27
27
28
extension MacroRole {
@@ -35,6 +36,7 @@ extension MacroRole {
35
36
case . peer: return " PeerMacro "
36
37
case . conformance: return " ConformanceMacro "
37
38
case . codeItem: return " CodeItemMacro "
39
+ case . extension: return " ExtensionMacro "
38
40
}
39
41
}
40
42
}
@@ -45,6 +47,7 @@ private enum MacroExpansionError: Error, CustomStringConvertible {
45
47
case parentDeclGroupNil
46
48
case declarationNotDeclGroup
47
49
case declarationNotIdentified
50
+ case noExtendedTypeSyntax
48
51
case noFreestandingMacroRoles( Macro . Type )
49
52
50
53
var description : String {
@@ -61,6 +64,9 @@ private enum MacroExpansionError: Error, CustomStringConvertible {
61
64
case . declarationNotIdentified:
62
65
return " declaration is not a 'Identified' syntax "
63
66
67
+ case . noExtendedTypeSyntax:
68
+ return " no extended type for extension macro "
69
+
64
70
case . noFreestandingMacroRoles( let type) :
65
71
return " macro implementation type ' \( type) ' does not conform to any freestanding macro protocol "
66
72
@@ -113,7 +119,7 @@ public func expandFreestandingMacro(
113
119
let rewritten = try codeItemMacroDef. expansion ( of: node, in: context)
114
120
expandedSyntax = Syntax ( CodeBlockItemListSyntax ( rewritten) )
115
121
116
- case ( . accessor, _) , ( . memberAttribute, _) , ( . member, _) , ( . peer, _) , ( . conformance, _) , ( . expression, _) , ( . declaration, _) ,
122
+ case ( . accessor, _) , ( . memberAttribute, _) , ( . member, _) , ( . peer, _) , ( . conformance, _) , ( . extension , _ ) , ( . expression, _) , ( . declaration, _) ,
117
123
( . codeItem, _) :
118
124
throw MacroExpansionError . unmatchedMacroRole ( definition, macroRole)
119
125
}
@@ -178,6 +184,7 @@ public func expandAttachedMacroWithoutCollapsing<Context: MacroExpansionContext>
178
184
attributeNode: AttributeSyntax ,
179
185
declarationNode: DeclSyntax ,
180
186
parentDeclNode: DeclSyntax ? ,
187
+ extendedType: TypeSyntax ? ,
181
188
in context: Context
182
189
) -> [ String ] ? {
183
190
do {
@@ -295,6 +302,39 @@ public func expandAttachedMacroWithoutCollapsing<Context: MacroExpansionContext>
295
302
return " extension \( typeName) : \( protocolName) \( whereClause) {} "
296
303
}
297
304
305
+ case ( let attachedMacro as ExtensionMacro . Type , . extension) :
306
+ guard let declGroup = declarationNode. asProtocol ( DeclGroupSyntax . self) else {
307
+ // Compiler error: type mismatch.
308
+ throw MacroExpansionError . declarationNotDeclGroup
309
+ }
310
+
311
+ guard let extendedType = extendedType else {
312
+ throw MacroExpansionError . noExtendedTypeSyntax
313
+ }
314
+
315
+ // Local function to expand an extension macro once we've opened up
316
+ // the existential.
317
+ func expandExtensionMacro(
318
+ _ node: some DeclGroupSyntax
319
+ ) throws -> [ ExtensionDeclSyntax ] {
320
+ return try attachedMacro. expansion (
321
+ of: attributeNode,
322
+ attachedTo: node,
323
+ providingExtensionsOf: extendedType,
324
+ in: context
325
+ )
326
+ }
327
+
328
+ let extensions = try _openExistential (
329
+ declGroup,
330
+ do: expandExtensionMacro
331
+ )
332
+
333
+ // Form a buffer of peer declarations to return to the caller.
334
+ return extensions. map {
335
+ $0. formattedExpansion ( definition. formatMode)
336
+ }
337
+
298
338
default :
299
339
throw MacroExpansionError . unmatchedMacroRole ( definition, macroRole)
300
340
}
@@ -323,6 +363,7 @@ public func expandAttachedMacro<Context: MacroExpansionContext>(
323
363
attributeNode: AttributeSyntax ,
324
364
declarationNode: DeclSyntax ,
325
365
parentDeclNode: DeclSyntax ? ,
366
+ extendedType: TypeSyntax ? ,
326
367
in context: Context
327
368
) -> String ? {
328
369
let expandedSources = expandAttachedMacroWithoutCollapsing (
@@ -331,6 +372,7 @@ public func expandAttachedMacro<Context: MacroExpansionContext>(
331
372
attributeNode: attributeNode,
332
373
declarationNode: declarationNode,
333
374
parentDeclNode: parentDeclNode,
375
+ extendedType: extendedType,
334
376
in: context
335
377
)
336
378
return expandedSources. map {
0 commit comments