Skip to content

Commit 791127b

Browse files
committed
[Macros] Add Macro.inferNonisolatedConformances to control inference of nonisolated conformances
When this property returns true, infer nonisolated conformances for the produced macro expansion. Do this by default, so that existing macros will work with isolated conformance inference. Macros can opt out by returning false, in which case we will skip this transformation.
1 parent 200ffec commit 791127b

File tree

3 files changed

+66
-1
lines changed

3 files changed

+66
-1
lines changed

Sources/SwiftSyntaxMacroExpansion/MacroExpansion.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,12 @@ fileprivate extension SyntaxProtocol {
520520
for macro: Macro.Type,
521521
indentationWidth: Trivia?
522522
) -> String {
523-
let syntax = Syntax(self)
523+
var syntax = Syntax(self)
524+
525+
// Infer nonisolated conformances.
526+
if macro.inferNonisolatedConformances {
527+
syntax = syntax.inferNonisolatedConformances()
528+
}
524529

525530
// Formatting.
526531
switch macro.formatMode {

Sources/SwiftSyntaxMacros/MacroProtocols/Macro.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,29 @@ public protocol Macro {
1515
/// How the resulting expansion should be formatted, `.auto` by default.
1616
/// Use `.disabled` for the expansion to be used as is.
1717
static var formatMode: FormatMode { get }
18+
19+
/// Whether to infer "nonisolated" on protocol conformances introduced in
20+
/// the macro expansion when there are some nonisolated members in the
21+
/// corresponding declaration group. When true, macro expansion will adjust
22+
/// expanded code such as
23+
///
24+
/// extension C: P {
25+
/// nonisolated func f() { }
26+
/// }
27+
///
28+
/// to
29+
///
30+
/// extension C: nonisolated P {
31+
/// nonisolated func f() { }
32+
/// }
33+
///
34+
/// This operation defaults to `true`. Macros can implement it to return
35+
/// `false` to prevent this adjustment to the macro-expanded code.
36+
static var inferNonisolatedConformances: Bool { get }
37+
}
38+
39+
extension Macro {
40+
/// Default implementation of the Macro protocol's
41+
/// `inferNonisolatedConformances` that returns `true`.
42+
public static var inferNonisolatedConformances: Bool { true }
1843
}

Tests/SwiftSyntaxMacroExpansionTest/ExtensionMacroTests.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,41 @@ final class ExtensionMacroTests: XCTestCase {
251251
indentationWidth: indentationWidth
252252
)
253253
}
254+
255+
func testNonisolatedConformances() {
256+
struct NonisolatedConformanceMacro: ExtensionMacro {
257+
static func expansion(
258+
of node: AttributeSyntax,
259+
attachedTo declaration: some DeclGroupSyntax,
260+
providingExtensionsOf type: some TypeSyntaxProtocol,
261+
conformingTo protocols: [TypeSyntax],
262+
in context: some MacroExpansionContext
263+
) throws -> [ExtensionDeclSyntax] {
264+
return [
265+
("""
266+
extension \(type): P {
267+
nonisolated func f() { }
268+
}
269+
""" as DeclSyntax).cast(ExtensionDeclSyntax.self)
270+
]
271+
}
272+
}
273+
274+
assertMacroExpansion(
275+
"@NonisolatedConformance struct Foo {}",
276+
expandedSource: """
277+
struct Foo {}
278+
279+
extension Foo: nonisolated P {
280+
nonisolated func f() {
281+
}
282+
}
283+
""",
284+
macros: [
285+
"NonisolatedConformance": NonisolatedConformanceMacro.self
286+
]
287+
)
288+
}
254289
}
255290

256291
fileprivate struct SendableExtensionMacro: ExtensionMacro {

0 commit comments

Comments
 (0)