It's a fundamental property of macros that the compiler only exposes certain information to them. While it's in theory possible for us to add APIs to the MacroExpansionContext
to expose more information, this takes a lot of careful engineering, and the more information we expose, the more it impacts the efficiency of tools (particularly features like code completion). As of yet, there's no way to just query an arbitrary type—even an enclosing type—and see all of its contents.
This means you often have to either figure out a place where you can attach a macro so that it can see what it needs, or you need to make assumptions about the environment and let the compiler diagnose a normal error if those assumptions are wrong.
Specifically:
The macro system doesn't currently provide enough visibility into enclosing types to implement this. Doug Gregor has pitched something that would let you see enclosing types, but their exact members are removed, so even that wouldn't help.
What I would recommmend is that you make @Cancelable
be an attached member macro you apply to the type. It will add both the cancellables
property and an addCancelable(_:)
method that you can use like this:
addCancelable(
self.somePublisher
.sink {
doStuff()
}
)
An ordinary method should work at the use site because there's really nothing special or macro-y that needs to happen when you add a cancelable to the property.
You can write a macro that generates a mock for one protocol as long as it's attached to the protocol:
@Mockable protocol ProtocolA {
func fromProtocolA()
}
But there's no way for a macro to see the declarations of more than one type at a time unless you do something disgusting like passing in a chunk of code as a string literal:
// Please don't do this
#Mockable("""
protocol ProtocolA {
func fromProtocolA()
}
protocol ProtocolB {
func fromProtocolB()
}
""")