Skip to content

Commit 84d8cb5

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

File tree

1 file changed

+67
-4
lines changed

1 file changed

+67
-4
lines changed

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

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# "Re-usable" unique names in Macros.
1+
# "Reusable" unique names in Macros.
22

33
* Proposal: [SE-NNNN](nnnn-reusable-unique-names-in-macros.md)
44
* Authors: [Joe Newton](https://github.com/SomeRandomiOSDev)
@@ -10,7 +10,7 @@
1010

1111
## Introduction
1212

13-
This document outlines a proposal for adding support for creating unique names in macro expansions that can be re-used across invocations of different roles for the same macro invocation.
13+
This document outlines a proposal for adding support for creating unique names in macro expansions that can be reused across invocations of different roles for the same macro invocation.
1414

1515
## Motivation
1616

@@ -146,7 +146,7 @@ class MyClass {
146146

147147
## Proposed solution
148148

149-
To account for cases like the one described above, we need to extend the `makeUniqueName(_:)` function, or create a new one, that allows for the creation of "re-usable" unique identifiers that will guaranteed to be equivalent across different roles of the same macro invocation. The proposed solution is to add an optional flag to the `makeUniqueName(_:)` function that, if provided and set to `true`, will create a unique name that follows the same pattern as above but will be the same when invoked from other macro role implementations:
149+
To account for cases like the one described above, we need to extend the `makeUniqueName(_:)` function, or create a new one, that allows for the creation of "reusable" unique identifiers that will guaranteed to be equivalent across different roles of the same macro invocation. The proposed solution is to add an optional flag to the `makeUniqueName(_:)` function that, if provided and set to `true`, will create a unique name that follows the same pattern as above but will be the same when invoked from other macro role implementations:
150150

151151
```swift
152152
protocol MacroExpansionContext {
@@ -170,7 +170,7 @@ or:
170170
macro-expansion-operator ::= decl-name identifier 'fMr' // reusable uniquely-named entity
171171
```
172172

173-
The compiler should also be updated in the relevant reas to account for this new mangling identifier.
173+
The compiler should also be updated in the relevant areas to account for this new mangling specification/identifer.
174174

175175
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:
176176

@@ -259,6 +259,69 @@ class MyClass {
259259
}
260260
```
261261

262+
As a side note, this only applies for different *role* invocations of the same macro, if the same macro is used more than once on a given declaration, the reusable names generated for each macro invocation would be distinct. For example, if we have the following macro that's used more than once on the same declaration, the generated names would be as follows:
263+
264+
```swift
265+
// Declaration
266+
@attached(member)
267+
macro FooBarMacro() = #externalMacro(...)
268+
269+
// Usage (in module "MyModule")
270+
@FooBarMacro @FooBarMacro @FooBarMacro
271+
struct FooBar {
272+
...
273+
}
274+
275+
// Implementation
276+
struct FooBarMacroImpl: MemberMacro {
277+
static func expansion(
278+
of node: AttributeSyntax,
279+
providingMembersOf declaration: some DeclGroupSyntax,
280+
conformingTo protocols: [TypeSyntax],
281+
in context: some MacroExpansionContext
282+
) throws -> [DeclSyntax] {
283+
let uniqueName = context.makeUniqueName("foobar")
284+
...
285+
}
286+
}
287+
288+
// Three unique names would be generated, one for each of the macros attached to `FooBar`:
289+
//
290+
// First `@FooBarMacro` attribute:
291+
// uniqueName == "$s8MyModule6FooBar11FooBarMacrofMm_6foobarfMu_"
292+
// ^~~~
293+
// Second `@FooBarMacro` attribute:
294+
// uniqueName == "$s8MyModule6FooBar11FooBarMacrofMm0_6foobarfMu_"
295+
// ^~~~~
296+
// Third `@FooBarMacro` attribute:
297+
// uniqueName == "$s8MyModule6FooBar11FooBarMacrofMm1_6foobarfMu_"
298+
// ^~~~~
299+
```
300+
301+
If a given macro with multiple roles makes reusable unique identifers, each *macro invocation* will be able to reuse the created identifiers across *role invocations* of that same macro instanace, however, the other reusable identifiers created for the other *macro invocations* would be unique to their role invocations. Continuing with out associated object macro example, if the macro were used twice on the same property, the final output would be as follows:
302+
303+
```swift
304+
class MyClass {
305+
private static let $s8MyModule7MyClass6foobarfMA_19associatedObjectKeyfMu_: UnsafeRawPointer = ...
306+
^~~~
307+
private static let $s8MyModule7MyClass6foobarfMA0_19associatedObjectKeyfMu_: UnsafeRawPointer = ...
308+
^~~~~
309+
310+
var foobar: AnyObject? {
311+
get { objc_getAssociatedObject(self, Self.$s8MyModule7MyClass6foobarfMA_19associatedObjectKeyfMu_) }
312+
^~~~
313+
set { objc_getAssociatedObject(self, Self.$s8MyModule7MyClass6foobarfMA_19associatedObjectKeyfMu_, newValue, .OBJC_ASSOCIATION_POLICY) }
314+
^~~~
315+
get { objc_getAssociatedObject(self, Self.$s8MyModule7MyClass6foobarfMA0_19associatedObjectKeyfMu_) }
316+
^~~~~
317+
set { objc_getAssociatedObject(self, Self.$s8MyModule7MyClass6foobarfMA0_19associatedObjectKeyfMu_, newValue, .OBJC_ASSOCIATION_POLICY) }
318+
^~~~~
319+
}
320+
}
321+
```
322+
323+
Although this limits the reusability of the generated identifiers, this seems appropriate given a macro that would require or have different behavior being attached multiple times to the same declaration doesn't seem like a well-designed macro nor would be necessarily practical. This is an arbitrary decision that was made but isn't central to the propsal overall.
324+
262325
## Source compatibility
263326

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

0 commit comments

Comments
 (0)