Swift's concurrency features cannot be fully utilized in macros without being able to implement macro expansion functions as async.
The Swift Evolution proposals clearly state that the expansion functions that the different macro protocols require to be implemented should be marked as async (see below). But despite this, the macro protocols in swift-syntax are missing the async keyword from their expansion function requirements, making it impossible to implement them as async functions.
Changing the declarations in swift-syntax to async shouldn't break existing macros, as async function requirements can be implemented as non-async functions. Additional changes would have to be made within swift-syntax (changes at the expansion function call sites etc.), but they shouldn't affect the user-facing parts of the package.
Quotes from the proposals:
https://github.com/swiftlang/swift-evolution/blob/main/proposals/0382-expression-macros.md
public protocol ExpressionMacro: FreestandingMacro {
/// Expand a macro described by the given freestanding macro expansion
/// within the given context to produce a replacement expression.
static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) async throws -> ExprSyntax
}
The macro expansion operation is asynchronous, to account for potentially-asynchronous operations that will eventually be added to
MacroExpansionContext
. For example, operations that require additional communication with the compiler to get types of subexpressions, access files in the program, and so on.
- Make the
ExpressionMacro.expansion(of:in:)
requirementasync
.
https://github.com/swiftlang/swift-evolution/blob/main/proposals/0389-attached-macros.md
public PeerMacro: AttachedMacro {
/// Expand a macro described by the given attribute to
/// produce "peer" declarations of the declaration to which it
/// is attached.
///
/// The macro expansion can introduce "peer" declarations that
/// go alongside the given declaration.
static func expansion(
of node: AttributeSyntax,
providingPeersOf declaration: some DeclSyntaxProtocol,
in context: some MacroExpansionContext
) async throws -> [DeclSyntax]
}
protocol MemberMacro: AttachedMacro {
/// Expand a macro described by the given attribute to
/// produce additional members of the given declaration to which
/// the attribute is attached.
static func expansion(
of node: AttributeSyntax,
providingMembersOf declaration: some DeclGroupSyntax,
in context: some MacroExpansionContext
) async throws -> [DeclSyntax]
}
protocol AccessorMacro: AttachedMacro {
/// Expand a macro described by the given attribute to
/// produce accessors for the given declaration to which
/// the attribute is attached.
static func expansion(
of node: AttributeSyntax,
providingAccessorsOf declaration: some DeclSyntaxProtocol,
in context: some MacroExpansionContext
) async throws -> [AccessorDeclSyntax]
}
protocol MemberAttributeMacro: AttachedMacro {
/// Expand a macro described by the given custom attribute to
/// produce additional attributes for the members of the type.
static func expansion(
of node: AttributeSyntax,
attachedTo declaration: some DeclGroupSyntax,
providingAttributesOf member: some DeclSyntaxProtocol,
in context: some MacroExpansionContext
) async throws -> [AttributeSyntax]
}