Hey @xedin I have been trying to explore macros and property wrappers on a small scale to see how do they actullay work and make packages that remove boilerplate code to increase productivity.
here were a few macro definations made by me that i would like you to review and comment if they are relevant to the project or not :
/// Macro that transforms a property declaration to use our custom property wrapper implementation
@attached(accessor)
public macro Wrapped<T>(_ wrapperType: Any.Type) = #externalMacro(module: "PropertyWrapperMacros", type: "WrappedMacro")
/// Macro that transforms a type into a property wrapper alternative
@attached(member)
public macro PropertyWrapperAlternative() = #externalMacro(module: "PropertyWrapperMacros", type: "PropertyWrapperAlternativeMacro")
reimplemented the property wrapper as follows :
@PropertyWrapperAlternative
struct Uppercase {
private var storage: String = ""
func get() -> String {
return storage
}
mutating func set(_ newValue: String) {
storage = newValue.uppercased()
}
init(_ initialValue: String) {
set(initialValue)
}
}
example useage of how it would look like if we redefined the property wrappers at a compiler level :
struct User {
// Original property wrapper
@OriginalUppercase var name: String
// Our reimplemented version using macros
@Wrapped(Uppercase.self) var email: String
}
the code may seem a litle more complex in terms of syntax but if more efficient in terms of compiler processing.
actual logic for the macros :
// This is what the macro expansion would look like behind the scenes
struct ExpandedUser {
// Original property wrapper
@OriginalUppercase var name: String
// Expanded version of our macro
private var _email: Uppercase
var email: String {
get {
return _email.get()
}
set {
_email.set(newValue)
}
}
init(name: String, email: String) {
self.name = name
self._email = Uppercase(email)
}
}
behind the scenes for the provided example :
import SwiftSyntax
import SwiftSyntaxMacros
struct WrappedMacro: AccessorMacro {
static func expansion(
of node: AttributeSyntax,
providingAccessorsOf declaration: VarDeclSyntax,
in context: MacroExpansionContext
) throws -> [AccessorDeclSyntax] {
guard let argument = node.arguments?.as(LabeledExprListSyntax.self)?.first?.expression,
let typeName = argument.as(MemberAccessExprSyntax.self)?.base?.as(IdentifierExprSyntax.self)?.identifier.text else {
throw MacroError("Expected a type as argument")
}
return [
"""
get {
return _\(declaration.identifier.text).get()
}
""",
"""
set {
_\(declaration.identifier.text).set(newValue)
}
"""
]
}
}
struct PropertyWrapperAlternativeMacro: MemberMacro {
static func expansion(
of node: AttributeSyntax,
attachedTo declaration: DeclSyntax,
in context: MacroExpansionContext
) throws -> [DeclSyntax] {
return [
"""
protocol PropertyWrapperProtocol {
associatedtype Value
func get() -> Value
mutating func set(_ newValue: Value)
}
"""
]
}
}
while creating this aproach i was struggling a little bit with adding required protocols and methods to make this type behave like a property wrapper and need more a bit more help on throwing errors to handle unexpected behaviour and make unit test cases to do so.
I understand there is lot of work to be done in terms of SIL code and implement the project and any sort of directions would be apriciated @ktoso
also while looking for good first issues reagarding label:"property wrappers" there weren't any issues that were open , and the ones that were open were not good first issues.
My implementation of " External property wrappers don't play well with variadic parameters #77824" wasn't related to how we may re-implement property wrappers but was just a geniune effort because when we form macros the way we handle vardic variables also becomes a probelm that needs to be addressed in my perosnal opinion.