I'm writing a macro Foo
, which expands code
@Foo
struct Bar {
var value: String
}
to
struct Bar {
var value: String
}
extension Bar: Comparable {
public static func < (lhs: Bar, rhs: Bar) -> Bool {
lhs.value < rhs.value
}
}
A key requirement is that, if user already defines <
function, the macro should skip generating the function. Since macro doesn't have built-in support for this, I borrow the code from Observation framework. The code itself works well. If user already defines <
function, the expanded code is as expected and compiles, but unfortunately the unexpanded code doesn't compile, with the following error:
Type 'Bar' does not conform to protocol 'Comparable'
Multiple matching functions named '<' with type '(Bar, Bar) -> Bool'
My further experiments show that, if I use the same approach to add CustomStringConvertible
conformance and skip generating description
computed variable if user already defined it, it works well and doesn't have this issue. I have yet to figure out what's the difference between the two cases (maybe function vs variable?). I wonder if anyone observed this issue too?
The issue can be consistently reproduced on my machine with the following code. Note I simplified the code so it doesn't even actually generate <
function in macro implementation, but just claims "<" function name in macro interface. But still it caused the error.
Macro implementation:
public enum FooMacro: ExtensionMacro {
public static func expansion(
of node: AttributeSyntax,
attachedTo declaration: some DeclGroupSyntax,
providingExtensionsOf type: some TypeSyntaxProtocol,
conformingTo protocols: [TypeSyntax],
in context: some MacroExpansionContext
) throws -> [ExtensionDeclSyntax] {
let comparableExtension = try ExtensionDeclSyntax(
"""
extension \(type.trimmed): Comparable {
}
"""
)
return [comparableExtension]
}
}
Macro interface:
// Note: chaning the name argument to "named(<(lhs:,rhs:))" has the same error
@attached(extension, conformances: Comparable, names: named(<))
public macro Foo() = #externalMacro(module: "impl", type: "FooMacro")
Test:
// Compile error:
// Type 'Name' does not conform to protocol 'Comparable'
// Multiple matching functions named '<' with type '(Name, Name) -> Bool'
// But the expanded code compiles.
@Foo
struct Name {
var value: String
public static func < (lhs: Name, rhs: Name) -> Bool {
lhs.value < rhs.value
}
}
My environment: Xcode 15.0, macOS 13.6. I don't think it's likely to be caused by my environment and I'm going to file a bug in Swift repo, but I'd appreciate if anyone can help to verify it on your machine.
UPDATE: I submited bug #70087