Skip to content

Commit b055993

Browse files
committed
[Macros] Support function body macros on closures.
1 parent 9787cd2 commit b055993

File tree

3 files changed

+49
-12
lines changed

3 files changed

+49
-12
lines changed

Sources/SwiftCompilerPluginMessageHandling/Macros.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ extension PluginProviderMessageHandler {
125125
attributeSyntax,
126126
foldingWith: .standardOperators
127127
).cast(AttributeSyntax.self)
128-
let declarationNode = sourceManager.add(declSyntax).cast(DeclSyntax.self)
128+
let declarationNode = sourceManager.add(declSyntax)
129129
let parentDeclNode = parentDeclSyntax.map { sourceManager.add($0).cast(DeclSyntax.self) }
130130
let extendedType = extendedTypeSyntax.map {
131131
sourceManager.add($0).cast(TypeSyntax.self)

Sources/SwiftSyntaxMacroExpansion/MacroExpansion.swift

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ public func expandAttachedMacroWithoutCollapsing<Context: MacroExpansionContext>
215215
definition: Macro.Type,
216216
macroRole: MacroRole,
217217
attributeNode: AttributeSyntax,
218-
declarationNode: DeclSyntax,
218+
declarationNode: some SyntaxProtocol,
219219
parentDeclNode: DeclSyntax?,
220220
extendedType: TypeSyntax?,
221221
conformanceList: InheritedTypeListSyntax?,
@@ -225,6 +225,7 @@ public func expandAttachedMacroWithoutCollapsing<Context: MacroExpansionContext>
225225
do {
226226
switch (definition, macroRole) {
227227
case (let attachedMacro as AccessorMacro.Type, .accessor):
228+
let declarationNode = declarationNode.cast(DeclSyntax.self)
228229
let accessors = try attachedMacro.expansion(
229230
of: attributeNode,
230231
providingAccessorsOf: declarationNode,
@@ -235,6 +236,7 @@ public func expandAttachedMacroWithoutCollapsing<Context: MacroExpansionContext>
235236
}
236237

237238
case (let attachedMacro as MemberAttributeMacro.Type, .memberAttribute):
239+
let declarationNode = declarationNode.cast(DeclSyntax.self)
238240
guard
239241
let parentDeclGroup = parentDeclNode?.asProtocol(DeclGroupSyntax.self)
240242
else {
@@ -274,6 +276,7 @@ public func expandAttachedMacroWithoutCollapsing<Context: MacroExpansionContext>
274276
}
275277

276278
case (let attachedMacro as PeerMacro.Type, .peer):
279+
let declarationNode = declarationNode.cast(DeclSyntax.self)
277280
let peers = try attachedMacro.expansion(
278281
of: attributeNode,
279282
providingPeersOf: declarationNode,
@@ -335,19 +338,26 @@ public func expandAttachedMacroWithoutCollapsing<Context: MacroExpansionContext>
335338
}
336339

337340
case (let attachedMacro as BodyMacro.Type, .body):
338-
guard
339-
let declToPass = Syntax(declarationNode).asProtocol(SyntaxProtocol.self)
340-
as? (DeclSyntaxProtocol & WithOptionalCodeBlockSyntax)
341-
else {
341+
let body: [CodeBlockItemSyntax]
342+
if let closureSyntax = declarationNode.as(ClosureExprSyntax.self) {
343+
body = try attachedMacro.expansion(
344+
of: attributeNode,
345+
providingBodyFor: closureSyntax,
346+
in: context
347+
)
348+
} else if let declToPass = Syntax(declarationNode).asProtocol(SyntaxProtocol.self)
349+
as? (DeclSyntaxProtocol & WithOptionalCodeBlockSyntax)
350+
{
351+
body = try attachedMacro.expansion(
352+
of: attributeNode,
353+
providingBodyFor: declToPass,
354+
in: context
355+
)
356+
} else {
342357
// Compiler error: declaration must have a body.
343358
throw MacroExpansionError.declarationHasNoBody
344359
}
345360

346-
let body = try attachedMacro.expansion(
347-
of: attributeNode,
348-
providingBodyFor: declToPass,
349-
in: context
350-
)
351361
return body.map {
352362
$0.formattedExpansion(definition.formatMode, indentationWidth: indentationWidth)
353363
}
@@ -380,7 +390,7 @@ public func expandAttachedMacro<Context: MacroExpansionContext>(
380390
definition: Macro.Type,
381391
macroRole: MacroRole,
382392
attributeNode: AttributeSyntax,
383-
declarationNode: DeclSyntax,
393+
declarationNode: some SyntaxProtocol,
384394
parentDeclNode: DeclSyntax?,
385395
extendedType: TypeSyntax?,
386396
conformanceList: InheritedTypeListSyntax?,

Sources/SwiftSyntaxMacros/MacroProtocols/BodyMacro.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,31 @@ public protocol BodyMacro: AttachedMacro {
2929
providingBodyFor declaration: some DeclSyntaxProtocol & WithOptionalCodeBlockSyntax,
3030
in context: some MacroExpansionContext
3131
) throws -> [CodeBlockItemSyntax]
32+
33+
/// Expand a macro described by the given custom attribute and
34+
/// attached to the given closure and evaluated within a
35+
/// particular expansion context.
36+
///
37+
/// The macro expansion can replace the body of the given closure.
38+
static func expansion(
39+
of node: AttributeSyntax,
40+
providingBodyFor closure: ClosureExprSyntax,
41+
in context: some MacroExpansionContext
42+
) throws -> [CodeBlockItemSyntax]
43+
}
44+
45+
private struct ClosureNotSupported: Error, CustomStringConvertible {
46+
var description: String {
47+
"Function body macro cannot be applied to closure"
48+
}
49+
}
50+
51+
extension BodyMacro {
52+
public static func expansion(
53+
of node: AttributeSyntax,
54+
providingBodyFor closure: ClosureExprSyntax,
55+
in context: some MacroExpansionContext
56+
) throws -> [CodeBlockItemSyntax] {
57+
throw ClosureNotSupported()
58+
}
3259
}

0 commit comments

Comments
 (0)