The struct
label here brings up a minor nit with the examples: We don't need to instantiate instances of the macro types, so they ought to be written as uninhabited enum
s, right? And if so, we probably don't want to use struct
as the label—we'd want type
or maybe enum
instead.
For what it's worth, the vision document originally included the macro kind(s) and various other information in a long argument list on a macro
modifier; I asked if we could remove or reformat that information for better readability, and one of the changes Doug made in response was to get the macro kinds from the conformances on the implementation, since it already had to be written there.
From what I can see, we could write the macro kind on the decl, but (a) it would be entirely redundant and (b) we would have to decide if it makes sense to have more than one kind and how that should be written. I'll let Doug chime in on those issues.
On the gripping hand, ExpressionMacro
only has one function in it anyway. Do we anticipate that other kinds of macros will require several functions? If not, perhaps we should drop the type entirely, define the macro expansions as free functions, and write the macro kind only in the macro
decl, removing the redundancy in the other direction.
// module declaring the macro
expression macro stringify<T>(_: T) -> (T, String) = #externalMacro(module: "ExampleMacros", func: "expandStringify(of:in:)")
// module defining the expansion
public func expandStringify(
of node: MacroExpansionExprSyntax, in context: inout MacroExpansionContext
) -> ExprSyntax {
guard let argument = node.argumentList.first?.expression else {
fatalError("compiler bug: the macro does not have any arguments")
}
return "(\(argument), \(literal: argument.description))"
}