@@ -25,11 +25,23 @@ extension SyntaxProtocol {
25
25
macros: [ String : Macro . Type ] ,
26
26
in context: some MacroExpansionContext ,
27
27
indentationWidth: Trivia ? = nil
28
+ ) -> Syntax {
29
+ let specs = Dictionary ( uniqueKeysWithValues: macros. map { ( $0. key, MacroSpec ( type: $0. value) ) } )
30
+ return self . expand ( macroSpecs: specs, in: context, indentationWidth: indentationWidth)
31
+ }
32
+
33
+ /// Expand all uses of the given set of macros with specifications within this syntax node.
34
+ public func expand(
35
+ macroSpecs: [ String : MacroSpec ] ,
36
+ in context: some MacroExpansionContext ,
37
+ indentationWidth: Trivia ? = nil
28
38
) -> Syntax {
29
39
// Build the macro system.
30
40
var system = MacroSystem ( )
31
- for (macroName, macroType) in macros {
32
- try ! system. add ( macroType, name: macroName)
41
+ for (macroName, macroSpec) in macroSpecs {
42
+ try ! system. add ( macroSpec. type, name: macroName)
43
+ let conformedTypes = InheritedTypeListSyntax ( macroSpec. conformances. map { InheritedTypeSyntax ( type: $0) } )
44
+ try ! system. add ( conformedTypes, name: macroName)
33
45
}
34
46
35
47
let applier = MacroApplication (
@@ -316,6 +328,7 @@ private func expandExtensionMacro(
316
328
definition: ExtensionMacro . Type ,
317
329
attributeNode: AttributeSyntax ,
318
330
attachedTo: DeclSyntax ,
331
+ conformanceList: InheritedTypeListSyntax ? ,
319
332
in context: some MacroExpansionContext ,
320
333
indentationWidth: Trivia
321
334
) throws -> CodeBlockItemListSyntax ? {
@@ -336,7 +349,7 @@ private func expandExtensionMacro(
336
349
declarationNode: attachedTo. detach ( in: context) ,
337
350
parentDeclNode: nil ,
338
351
extendedType: extendedType. detach ( in: context) ,
339
- conformanceList: [ ] ,
352
+ conformanceList: conformanceList ?? [ ] ,
340
353
in: context,
341
354
indentationWidth: indentationWidth
342
355
)
@@ -355,11 +368,14 @@ private func expandExtensionMacro(
355
368
enum MacroSystemError : Error {
356
369
/// Indicates that a macro with the given name has already been defined.
357
370
case alreadyDefined( new: Macro . Type , existing: Macro . Type )
371
+ /// Indicates that protocol conformances for a macro with the given name has already been defined.
372
+ case alreadyConforming( new: InheritedTypeListSyntax , existing: InheritedTypeListSyntax )
358
373
}
359
374
360
375
/// A system of known macros that can be expanded syntactically
361
376
struct MacroSystem {
362
377
var macros : [ String : Macro . Type ] = [ : ]
378
+ var conformanceMap : [ String : InheritedTypeListSyntax ] = [ : ]
363
379
364
380
/// Create an empty macro system.
365
381
init ( ) { }
@@ -375,10 +391,26 @@ struct MacroSystem {
375
391
macros [ name] = macro
376
392
}
377
393
394
+ /// Add protocol conformances for a macro to the system.
395
+ ///
396
+ /// Throws an error if there is already conformances for a macro with this name.
397
+ mutating func add( _ conformanceList: InheritedTypeListSyntax , name: String ) throws {
398
+ if let knownConformanceList = conformanceMap [ name] {
399
+ throw MacroSystemError . alreadyConforming ( new: conformanceList, existing: knownConformanceList)
400
+ }
401
+
402
+ conformanceMap [ name] = conformanceList
403
+ }
404
+
378
405
/// Look for a macro with the given name.
379
406
func lookup( _ macroName: String ) -> Macro . Type ? {
380
407
return macros [ macroName]
381
408
}
409
+
410
+ /// Look for protocol conformances of a macro with the given name.
411
+ func conformaces( forMacro macroName: String ) -> InheritedTypeListSyntax ? {
412
+ return conformanceMap [ macroName]
413
+ }
382
414
}
383
415
384
416
// MARK: - MacroApplication
@@ -729,12 +761,13 @@ private class MacroApplication<Context: MacroExpansionContext>: SyntaxRewriter {
729
761
// MARK: Attached macro expansions.
730
762
731
763
extension MacroApplication {
732
- /// Get pairs of a macro attribute and the macro definition attached to `decl`.
764
+ /// Get macro attribute, the macro definition and optional
765
+ /// conformance protocols list attached to `decl`.
733
766
///
734
767
/// The macros must be registered in `macroSystem`.
735
768
private func macroAttributes(
736
769
attachedTo decl: DeclSyntax
737
- ) -> [ ( attributeNode: AttributeSyntax , definition: Macro . Type ) ] {
770
+ ) -> [ ( attributeNode: AttributeSyntax , definition: Macro . Type , conformanceList : InheritedTypeListSyntax ? ) ] {
738
771
guard let attributedNode = decl. asProtocol ( WithAttributesSyntax . self) else {
739
772
return [ ]
740
773
}
@@ -747,22 +780,22 @@ extension MacroApplication {
747
780
return nil
748
781
}
749
782
750
- return ( attribute, macro)
783
+ return ( attribute, macro, macroSystem . conformaces ( forMacro : attributeName ) )
751
784
}
752
785
}
753
786
754
- /// Get pairs of a macro attribute and the macro definition attached to `decl`
755
- /// matching `ofType` macro type.
787
+ /// Get macro attribute, the macro definition and optional conformance
788
+ /// protocols list attached to `decl` matching `ofType` macro type.
756
789
///
757
790
/// The macros must be registered in `macroSystem`.
758
791
private func macroAttributes< MacroType> (
759
792
attachedTo decl: DeclSyntax ,
760
793
ofType: MacroType . Type
761
- ) -> [ ( attributeNode: AttributeSyntax , definition: MacroType ) ] {
794
+ ) -> [ ( attributeNode: AttributeSyntax , definition: MacroType , conformanceList : InheritedTypeListSyntax ? ) ] {
762
795
return macroAttributes ( attachedTo: decl)
763
- . compactMap { ( attributeNode: AttributeSyntax , definition: Macro . Type ) in
796
+ . compactMap { ( attributeNode: AttributeSyntax , definition: Macro . Type , conformanceList : InheritedTypeListSyntax ? ) in
764
797
if let macroType = definition as? MacroType {
765
- return ( attributeNode, macroType)
798
+ return ( attributeNode, macroType, conformanceList )
766
799
} else {
767
800
return nil
768
801
}
@@ -778,13 +811,13 @@ extension MacroApplication {
778
811
> (
779
812
attachedTo decl: DeclSyntax ,
780
813
ofType: MacroType . Type ,
781
- expandMacro: ( _ attributeNode: AttributeSyntax , _ definition: MacroType ) throws -> ExpanedNodeCollection ?
814
+ expandMacro: ( _ attributeNode: AttributeSyntax , _ definition: MacroType , _ conformanceList : InheritedTypeListSyntax ? ) throws -> ExpanedNodeCollection ?
782
815
) -> [ ExpandedNode ] {
783
816
var result : [ ExpandedNode ] = [ ]
784
817
785
818
for macroAttribute in macroAttributes ( attachedTo: decl, ofType: ofType) {
786
819
do {
787
- if let expanded = try expandMacro ( macroAttribute. attributeNode, macroAttribute. definition) {
820
+ if let expanded = try expandMacro ( macroAttribute. attributeNode, macroAttribute. definition, macroAttribute . conformanceList ) {
788
821
result += expanded
789
822
}
790
823
} catch {
@@ -802,7 +835,7 @@ extension MacroApplication {
802
835
///
803
836
/// - Returns: The macro-synthesized peers
804
837
private func expandMemberDeclPeers( of decl: DeclSyntax ) -> [ MemberBlockItemSyntax ] {
805
- return expandMacros ( attachedTo: decl, ofType: PeerMacro . Type. self) { attributeNode, definition in
838
+ return expandMacros ( attachedTo: decl, ofType: PeerMacro . Type. self) { attributeNode, definition, conformanceList in
806
839
return try expandPeerMacroMember (
807
840
definition: definition,
808
841
attributeNode: attributeNode,
@@ -822,7 +855,7 @@ extension MacroApplication {
822
855
///
823
856
/// - Returns: The macro-synthesized peers
824
857
private func expandCodeBlockPeers( of decl: DeclSyntax ) -> [ CodeBlockItemSyntax ] {
825
- return expandMacros ( attachedTo: decl, ofType: PeerMacro . Type. self) { attributeNode, definition in
858
+ return expandMacros ( attachedTo: decl, ofType: PeerMacro . Type. self) { attributeNode, definition, conformanceList in
826
859
return try expandPeerMacroCodeItem (
827
860
definition: definition,
828
861
attributeNode: attributeNode,
@@ -837,11 +870,12 @@ extension MacroApplication {
837
870
///
838
871
/// - Returns: The macro-synthesized extensions
839
872
private func expandExtensions( of decl: DeclSyntax ) -> [ CodeBlockItemSyntax ] {
840
- return expandMacros ( attachedTo: decl, ofType: ExtensionMacro . Type. self) { attributeNode, definition in
873
+ return expandMacros ( attachedTo: decl, ofType: ExtensionMacro . Type. self) { attributeNode, definition, conformanceList in
841
874
return try expandExtensionMacro (
842
875
definition: definition,
843
876
attributeNode: attributeNode,
844
877
attachedTo: decl,
878
+ conformanceList: conformanceList,
845
879
in: context,
846
880
indentationWidth: indentationWidth
847
881
)
@@ -850,7 +884,7 @@ extension MacroApplication {
850
884
851
885
/// Expand all 'member' macros attached to `decl`.
852
886
private func expandMembers( of decl: DeclSyntax ) -> [ MemberBlockItemSyntax ] {
853
- return expandMacros ( attachedTo: decl, ofType: MemberMacro . Type. self) { attributeNode, definition in
887
+ return expandMacros ( attachedTo: decl, ofType: MemberMacro . Type. self) { attributeNode, definition, conformanceList in
854
888
return try expandMemberMacro (
855
889
definition: definition,
856
890
attributeNode: attributeNode,
@@ -870,7 +904,7 @@ extension MacroApplication {
870
904
of decl: DeclSyntax ,
871
905
parentDecl: DeclSyntax
872
906
) -> [ AttributeListSyntax . Element ] {
873
- return expandMacros ( attachedTo: parentDecl, ofType: MemberAttributeMacro . Type. self) { attributeNode, definition in
907
+ return expandMacros ( attachedTo: parentDecl, ofType: MemberAttributeMacro . Type. self) { attributeNode, definition, conformanceList in
874
908
return try expandMemberAttributeMacro (
875
909
definition: definition,
876
910
attributeNode: attributeNode,
0 commit comments