Skip to content

Commit e0913ee

Browse files
Update nnnn-reusable-unique-names-in-macros.md
1 parent b5c3831 commit e0913ee

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

proposals/nnnn-reusable-unique-names-in-macros.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,93 @@ macro-expansion-operator ::= decl-name identifier 'fMr' // reusable uniquely-nam
172172

173173
The compiler should also be updated in the relevant reas to account for this new mangling identifier.
174174

175+
Next the SwiftSyntax library would be updated to add in support for this additional parameter on the `makeUniqueName(_:)` function. The logic for this method wouldn't change very much from how its currently implemented today:
176+
177+
```swift
178+
// Lines prefixed with '-' are part of the current implementation being changed.
179+
// Lines prefixed with '+' are part of the new implementation.
180+
// Lines without a '-' or '+' prefix are part of the current implementation that are *not* being modified.
181+
182+
func makeUniqueName(_ providedName: String, reusable: Bool = false) -> TokenSyntax {
183+
// If provided with an empty name, substitute in something.
184+
let name = providedName.isEmpty ? "__local" : providedName
185+
186+
// Grab a unique index value for this name.
187+
- let uniqueIndex = uniqueNames[name, default: 0]
188+
- uniqueNames[name] = uniqueIndex + 1
189+
+ let uniqueIndex: Int
190+
+ if reusable {
191+
+ uniqueIndex = reusableUniqueNames[name, default: 0]
192+
+ reusableUniqueNames[name] = uniqueIndex + 1
193+
+ } else {
194+
+ uniqueIndex = uniqueNames[name, default: 0]
195+
+ uniqueNames[name] = uniqueIndex + 1
196+
+ }
197+
198+
// Start with the expansion discriminator.
199+
- var resultString = expansionDiscriminator
200+
+ var resultString: String
201+
+ if reusable {
202+
+ resultString = reusableExpansionDiscriminator
203+
+ } else {
204+
+ resultString = expansionDiscriminator
205+
+ }
206+
207+
// Mangle the name
208+
resultString += "\(name.count)\(name)"
209+
210+
// Mangle the operator for unique macro names.
211+
resultString += "fMu"
212+
213+
// Mangle the index.
214+
if uniqueIndex > 0 {
215+
resultString += "\(uniqueIndex - 1)"
216+
}
217+
resultString += "_"
218+
219+
return TokenSyntax(.identifier(resultString), presence: .present)
220+
}
221+
```
222+
223+
Each macro expansion context will keep track of two separate sets of unique names, one for reusable names, and one for unique names as they exist today. With this implementation in place our running example of a macro for associated object accessors would generate the same unique identifier for both macro roles:
224+
225+
```swift
226+
extension AssociatedObjectMacro: PeerMacro {
227+
static func expansion(
228+
of node: AttributeSyntax,
229+
providingPeersOf declaration: some DeclSyntaxProtocol,
230+
in context: some MacroExpansionContext
231+
) throws -> [DeclSyntax] {
232+
let uniqueVariableName = context.makeUniqueName("associatedObjectKey")
233+
// uniqueVariableName == "$s8MyModule7MyClass6foobarfMA_19associatedObjectKeyfMu_"
234+
}
235+
}
236+
237+
extension AssociatedObjectMacro: AccessorMacro {
238+
static func expansion(
239+
of node: AttributeSyntax,
240+
providingAccessorsOf declaration: some DeclSyntaxProtocol,
241+
in context: some MacroExpansionContext
242+
) throws -> [AccessorDeclSyntax] {
243+
let uniqueVariableName = context.makeUniqueName("associatedObjectKey")
244+
// uniqueVariableName == "$s8MyModule7MyClass6foobarfMA_19associatedObjectKeyfMu_"
245+
}
246+
}
247+
```
248+
249+
With the final expansion of the macro being as follows:
250+
251+
```swift
252+
class MyClass {
253+
private static let $s8MyModule7MyClass6foobarfMA_19associatedObjectKeyfMu_: UnsafeRawPointer = ...
254+
255+
var foobar: AnyObject? {
256+
get { objc_getAssociatedObject(self, Self.$s8MyModule7MyClass6foobarfMA_19associatedObjectKeyfMu_) }
257+
set { objc_getAssociatedObject(self, Self.$s8MyModule7MyClass6foobarfMA_19associatedObjectKeyfMu_, newValue, .OBJC_ASSOCIATION_POLICY) }
258+
}
259+
}
260+
```
261+
175262
## Source compatibility
176263

177264
Describe the impact of this proposal on source compatibility. As a

0 commit comments

Comments
 (0)