-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
Description
I have a macro Foo
which may add CustomStringConvertible
conformance or does nothing, depending on a flag argument it takes. Below is a scenario why I'd like the macro to output nothing.
protocol BarProtocol: CustomStringConvertible {
var value: String { get }
}
extension BarProtocol {
var description: String {
value
}
}
@Foo(noOp: true)
struct Bar: BarProtocol {
var value: String
}
In above case, since Bar
conforms to CustomStringConvertible
by inheriting BarProtocol
and its extension, there is no need for the macro to generate any code. Unfortunately the above code doesn't compile. Error:
Type 'Bar' does not conform to protocol 'CustomStringConvertible'
It seems that the description
computed variable defined in BarProtocol
becomes invisible to compiler during conformance check.
(In case you're curious why I couldn't just remove the macro in above scenario, it's because the above code is a simplification. In my actual code the macro adds conformance to multiple protocols, so I can't remove it just because the type already conforms to one of the protocols through inheritance.)
Reproduction
Please note I simplied the macro code so that it always generate nothing.
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] {
return []
}
}
Macro interface:
@attached(extension, conformances: CustomStringConvertible, names: named(description))
public macro Foo() = #externalMacro(module: "impl", type: "FooMacro")
Test:
protocol BarProtocol: CustomStringConvertible {
var value: String
}
extension BarProtocol {
var description: String {
value
}
}
@Foo
struct Bar: BarProtocol {
var value: String
}
The test caused compile error:
Type 'Bar' does not conform to protocol 'CustomStringConvertible'
Expected behavior
It should compile.
Environment
$ /Users/app/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -version
swift-driver version: 1.87.1 Apple Swift version 5.9 (swiftlang-5.9.0.128.108 clang-1500.0.40.1)
Target: x86_64-apple-macosx13.0
Xcode: 15.0, macOS: 13.6
Additional information
I think there are three ways to add protocol conformance to a type:
- Inheriting from another protocol (and its extension)
- Using macro
- Doing it manually
This bug makes it impossible to use method 1 and 2 together.