Reputation: 1748
I've made a macro called Resettable
which creates a private constant initialised with the same value as the declaration the macro is attached to:
public struct ResettableMacro: PeerMacro {
public static func expansion(of node: AttributeSyntax,
providingPeersOf declaration: some DeclSyntaxProtocol,
in context: some MacroExpansionContext)
throws -> [DeclSyntax] {
guard let variableDecl = declaration.as(VariableDeclSyntax.self) else {
print("Can only be applied to variable declarations")
return []
}
guard variableDecl.bindingSpecifier.text == "var" else {
print("Can only be a variable")
return []
}
guard variableDecl.bindings.allSatisfy({ $0.initializer != nil }) else {
print("Must be an initialised stored property")
return []
}
// abstracted extracting the identifier pattern and the initial value for clarity
return zip(variableDecl.identifiers, variableDecl.values).map { name, value in
"private let $\(raw: name) = \(raw: value)"
}
}
}
This works very well, except when I use @Resettable
on a class marked with @Observable
. When I do that I get the following error which I don't understand:
'self' used in property access '$_name' before 'self.init' call
@Observable
class Person {
@Resettable var name = "John Doe"
// << error here due to @ObservationTracked
}
This is because the @Observable
macro adds another declaration:
@Resettable @ObservationIgnored private var _name = "John Doe"
which is emitting this error.
I thought this wouldn't be a problem because @Resettable
will only see "The original version of the declaration without expansions provided by others" (from the "Expand on Swift macros" talk). Even if you consider what the @Observable
macro is doing, it's creating one underscored property (_name
), and creating accessors for the non-underscored version (name
). Since in my macro implementation, an initialiser is required, the name
property with a getter and setter would be skipped as there is no initialiser. Yet, I am still getting an error. In fact, I don't even understand what this error means and why it's coming.
I initially thought of skipping delcarations marked with @ObservationTracked
, but this doesn't account for other macros that might expand similarly, nor if the @ObservationTracked
macro's name changes.
I would love to know how I can account for the @Observable
expansion in my macro in the simplest way.
Upvotes: 1
Views: 326