8000 [Macros] Implement expansion of conformance macros · DougGregor/swift-syntax@318d6c7 · GitHub
[go: up one dir, main page]

Skip to content

Commit 318d6c7

Browse files
committed
[Macros] Implement expansion of conformance macros
Somehow, we forgot to implement this here, even though the compiler has supported it for a long time. Fixes swiftlang#1742 / rdar://110418242.
1 parent 937b85b commit 318d6c7

File tree

2 files changed

+94
-1
lines changed

2 files changed

+94
-1
lines changed

Sources/SwiftSyntaxMacros/MacroSystem.swift

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,23 @@ class MacroApplication<Context: MacroExpansionContext>: SyntaxRewriter {
178178
let newItem = visit(item.item)
179179
newItems.append(item.with(\.item, newItem))
180180

181-
// Expand any peer declarations triggered by macros used as attributes.
181+
// Expand any peer declarations or conformances triggered by macros used
182+
// as attributes.
182183
if case let .decl(decl) = item.item {
183184
let peers = expandPeers(of: decl)
184185
newItems.append(
185186
contentsOf: peers.map {
186187
newDecl in CodeBlockItemSyntax(item: .decl(newDecl))
187188
}
188189
)
190+
191+
if let declGroup = decl.asProtocol(DeclGroupSyntax.self) {
192+
newItems.append(
193+
contentsOf: expandConformances(of: declGroup).map {
194+
newDecl in CodeBlockItemSyntax(item: .decl(newDecl))
195+
}
196+
)
197+
}
189198
}
190199
}
191200

@@ -394,6 +403,43 @@ extension MacroApplication {
394403
return peers
395404
}
396405

406+
// If any of the custom attributes associated with the given declaration
407+
// refer to conformance macros, expand them and return the resulting
408+
// set of extension declarations.
409+
private func expandConformances(of decl: DeclGroupSyntax) -> [DeclSyntax] {
410+
let identifier: String
411+
if let identified = decl.asProtocol(IdentifiedDeclSyntax.self) {
412+
identifier = identified.identifier.text
413+
} else if let ext = decl.as(ExtensionDeclSyntax.self) {
414+
identifier = ext.extendedType.trimmedDescription
415+
} else {
416+
return []
417+
}
418+
419+
var extensions: [DeclSyntax] = []
420+
let macroAttributes = getMacroAttributes(attachedTo: decl.as(DeclSyntax.self)!, ofType: ConformanceMacro.Type.self)
421+
for (attribute, conformanceMacro) in macroAttributes {
422+
do {
423+
let newConformances = try conformanceMacro.expansion(of: attribute, providingConformancesOf: decl, in: context)
424+
425+
for (type, whereClause) in newConformances {
426+
var ext: DeclSyntax = """
427+
extension \(raw: identifier): \(type) { }
428+
"""
429+
if let whereClause {
430+
ext = DeclSyntax((ext.as(ExtensionDeclSyntax.self))!.with(\.genericWhereClause, whereClause))
431+
}
432+
433+
extensions.append(DeclSyntax(ext))
434+
}
435+
} catch {
436+
context.addDiagnostics(from: error, node: attribute)
437+
}
438+
}
439+
440+
return extensions
441+
}
442+
397443
/// Expands any attached custom attributes that refer to member declaration macros,
398444
/// and returns result of adding those members to the given declaration.
399445
private func expandMembers<Decl: DeclGroupSyntax & DeclSyntaxProtocol>(

Tests/SwiftSyntaxMacrosTest/MacroSystemTests.swift

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,16 @@ public struct DeclsFromStringsMacro: DeclarationMacro {
672672
}
673673
}
674674

675+
public struct SendableConformanceMacro: ConformanceMacro {
676+
public static func expansion(
677+
of node: AttributeSyntax,
678+
providingConformancesOf declaration: some DeclGroupSyntax,
679+
in context: some MacroExpansionContext
680+
) throws -> [(TypeSyntax, GenericWhereClauseSyntax?)] {
681+
return [("Sendable", nil)]
682+
}
683+
}
684+
675685
public struct DeclsFromStringsMacroNoAttrs: DeclarationMacro {
676686
public static var propagateFreestandingMacroAttributes: Bool { false }
677687
public static var propagateFreestandingMacroModifiers: Bool { false }
@@ -715,6 +725,7 @@ public let testMacros: [String: Macro.Type] = [
715725
"wrapStoredProperties": WrapStoredProperties.self,
716726
"customTypeWrapper": CustomTypeWrapperMacro.self,
717727
"unwrap": UnwrapMacro.self,
728+
"AddSendable": SendableConformanceMacro.self,
718729
]
719730

720731
final class MacroSystemTests: XCTestCase {
@@ -1156,4 +1167,40 @@ final class MacroSystemTests: XCTestCase {
11561167
)
11571168

11581169
}
1170+
1171+
func testConformanceExpansion() {
1172+
assertMacroExpansion(
1173+
"""
1174+
@AddSendable
1175+
struct MyType {
1176+
}
1177+
""",
1178+
expandedSource: """
1179+
1180+
struct MyType {
1181+
}
1182+
extension MyType: Sendable {
1183+
}
1184+
""",
1185+
macros: testMacros,
1186+
indentationWidth: indentationWidth
1187+
)
1188+
1189+
assertMacroExpansion(
1190+
"""
1191+
@AddSendable
1192+
extension A.B {
1193+
}
1194+
""",
1195+
expandedSource: """
1196+
1197+
extension A.B {
1198+
}
1199+
extension A.B: Sendable {
1200+
}
1201+
""",
1202+
macros: testMacros,
1203+
indentationWidth: indentationWidth
1204+
)
1205+
}
11591206
}

0 commit comments

Comments
 (0)
0