Maybe I actually did use a relevant example. Since B inherits A, you only need to add that it conforms to B. For example, I could have removed the Equatable conformance and just used Hashable, which inherits from Equatable.
Then MyStruct isn't properly conforming to A, which it got from conforming to B. Are you sure the names are added correctly to the macro interface? I'm frankly unsure that about options 2 and 3, they seem to me like caching issues from the previous attempts. At this point, I don't know if this is a macro issue.
The following works, but note that the protocol requirements for variables must not have a setter because variables are declared in an extension. I haven't read the threads that went over the evolution of these specific macros, but that seems like something that should be looked at (somehow allowing conformances for protocols with stored properties).
public protocol A {
var foo: Int { get }
}
public protocol B: A { }
@attached(extension, conformances: B, names: named(foo))
public macro Conforming() = ...
public struct ConformingMacro: ExtensionMacro {
public static func expansion(...) throws -> [ExtensionDeclSyntax] {
// provide the requirements for A
return [try ExtensionDeclSyntax("extension \(type.trimmed): B { var foo: Int { 420 } }")]
}
}
// usage
@Conforming
struct MyStruct { }
// expands
extension MyStruct: B {
var foo: Int {
420
}
}
Edit: Actually you can get away with a get/set for a protocol requirement with the good ol' private variable for the storage, been a while. While this may not have been your intention, just something for me to work on while making a presentation on macros.
Example P2
public protocol A {
var foo: Int { get set }
}
public protocol B: A { }
@attached(extension, conformances: B, names: named(foo))
@attached(member, names: named(_foo))
public macro equatable() = ...
public struct EquatableMacro: ExtensionMacro, MemberMacro {
public static func expansion(...) throws -> [DeclSyntax] {
return [DeclSyntax("private var _foo: Int = 420")]
}
public static func expansion(...) throws -> [ExtensionDeclSyntax] {
return [try ExtensionDeclSyntax("extension \(type.trimmed): B { var foo: Int { get { _foo } set { _foo = newValue } } }")]
}
}
Haha indeed, I realized that right after I posted my reply.
But unfortunately, I don't always want to conform to protocol B. The macro decides whether to conform to B or just A according to the declaration it's added to. Therefore, I still need the conformances: A, B.
So, going back to my last post,
I tested the code using a fresh macro template, and A and B are actual protocol as declared in the project, so they have no requirement at all. I also tested your code (P2), and indeed it works. But it breaks as soon as I change
That actually is interesting. It does break when I add A, however that's only when I expand to B in the macro. When expanding to extension Bar: A, B, it works.
I am unsure if this is a bug or intended behavior. All named() declarations don't need to be in the expansion (I don't think it's checked) but to me it seems safer that the protocol conformances as declared must be in the expansion. I didn't read any language in the evolutions that said that this was required or missed it. However I am not that knowledgeable of macro implementation to know that much.
So at least right now, I don't think the macro system can do what you want. Personally, I would just have two macros that have separate A and B conformances which are used together.
Thanks for checking! That's exactly the same behavior I'm observing.
For the time being, I just make the macro add extension MyStruct: A, B { } every time I need something to conform to B. Having two separate macros would in fact be a more reasonable choice, but I'm sticking with a single macro for now in order to introduce as few names as possible from my package.
I believe this could be a bug, since it's okay to have a macro that expands to extension MyStruct: A { }, or even an empty ExtensionDeclSyntax list, when the interface is @attached(extension, conformances: A, B). Also the error is not properly reported, it's either "Type 'MyStruct' does not conform to protocol 'A", which is a false claim, or in many cases, just a non-zero return value.
I'll post a new topic later if I still think it's a bug after some more tests. Thank you again @Pippin for your help!