Skip to content

Commit f7b27ec

Browse files
committed
[DistributedMacros] handle access control on generated code
1 parent 118f924 commit f7b27ec

File tree

2 files changed

+109
-52
lines changed

2 files changed

+109
-52
lines changed

lib/Macros/Sources/SwiftMacros/DistributedProtocolMacro.swift

Lines changed: 89 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,15 @@ extension DistributedProtocolMacro {
4545
return []
4646
}
4747

48+
let accessModifiers: String = proto.accessModifiersString
49+
4850
let requirements =
4951
proto.memberBlock.members.map { member in
5052
member.trimmed
5153
}
5254
let requirementStubs = requirements
53-
.map(stubMethod).joined(separator: "\n ")
55+
.map { stubMethod(access: accessModifiers, $0) }
56+
.joined(separator: "\n ")
5457

5558
let extensionDecl: DeclSyntax =
5659
"""
@@ -61,9 +64,9 @@ extension DistributedProtocolMacro {
6164
return [extensionDecl.cast(ExtensionDeclSyntax.self)]
6265
}
6366

64-
static func stubMethod(_ requirementDeclaration: MemberBlockItemListSyntax.Element) -> String {
67+
static func stubMethod(access: String, _ requirementDeclaration: MemberBlockItemListSyntax.Element) -> String {
6568
"""
66-
\(requirementDeclaration) {
69+
\(access)\(requirementDeclaration) {
6770
\(stubFunctionBody())
6871
}
6972
"""
@@ -109,6 +112,8 @@ extension DistributedProtocolMacro {
109112
""", id: .invalidApplication)
110113
}
111114

115+
let accessModifiers = proto.accessModifiersString
116+
112117
for req in proto.genericWhereClause?.requirements ?? [] {
113118
switch req.requirement {
114119
case .conformanceRequirement(let conformanceReq)
@@ -126,51 +131,68 @@ extension DistributedProtocolMacro {
126131
}
127132
}
128133

129-
if isGenericStub, let specificActorSystemRequirement {
130-
return [
131-
"""
132-
\(proto.modifiers) distributed actor $\(proto.name.trimmed)<ActorSystem>: \(proto.name.trimmed),
133-
Distributed._DistributedActorStub
134-
where ActorSystem: \(specificActorSystemRequirement)
135-
{ }
136-
"""
137-
]
138-
} else if let specificActorSystemRequirement {
139-
return [
140-
"""
141-
\(proto.modifiers) distributed actor $\(proto.name.trimmed): \(proto.name.trimmed),
142-
Distributed._DistributedActorStub
143-
{
144-
\(typealiasActorSystem(proto, specificActorSystemRequirement))
145-
}
146-
"""
147-
]
148-
} else {
149-
// there may be no `where` clause specifying an actor system,
150-
// but perhaps there is a typealias (or extension with a typealias),
151-
// specifying a concrete actor system so we let this synthesize
152-
// an empty `$Greeter` -- this may fail, or succeed depending on
153-
// surrounding code using a default distributed actor system,
154-
// or extensions providing it.
155-
return [
156-
"""
157-
\(proto.modifiers) distributed actor $\(proto.name.trimmed): \(proto.name.trimmed),
158-
Distributed._DistributedActorStub
159-
{
160-
}
161-
"""
162-
]
163-
}
134+
if isGenericStub, let specificActorSystemRequirement {
135+
return [
136+
"""
137+
\(proto.modifiers) distributed actor $\(proto.name.trimmed)<ActorSystem>: \(proto.name.trimmed),
138+
Distributed._DistributedActorStub
139+
where ActorSystem: \(specificActorSystemRequirement)
140+
{ }
141+
"""
142+
]
143+
} else if let specificActorSystemRequirement {
144+
return [
145+
"""
146+
\(proto.modifiers) distributed actor $\(proto.name.trimmed): \(proto.name.trimmed),
147+
Distributed._DistributedActorStub
148+
{
149+
\(typealiasActorSystem(access: accessModifiers, proto, specificActorSystemRequirement))
150+
}
151+
"""
152+
]
153+
} else {
154+
// there may be no `where` clause specifying an actor system,
155+
// but perhaps there is a typealias (or extension with a typealias),
156+
// specifying a concrete actor system so we let this synthesize
157+
// an empty `$Greeter` -- this may fail, or succeed depending on
158+
// surrounding code using a default distributed actor system,
159+
// or extensions providing it.
160+
return [
161+
"""
162+
\(proto.modifiers) distributed actor $\(proto.name.trimmed): \(proto.name.trimmed),
163+
Distributed._DistributedActorStub
164+
{
165+
}
166+
"""
167+
]
168+
}
164169
}
165170

166-
private static func typealiasActorSystem(_ proto: ProtocolDeclSyntax, _ type: TypeSyntax) -> DeclSyntax {
167-
"typealias ActorSystem = \(type)"
171+
private static func typealiasActorSystem(access: String, _ proto: ProtocolDeclSyntax, _ type: TypeSyntax) -> DeclSyntax {
172+
"\(raw: access)typealias ActorSystem = \(type)"
168173
}
169174
}
170175

171176
// ===== -----------------------------------------------------------------------
172177
// MARK: Convenience Extensions
173178

179+
extension ProtocolDeclSyntax {
180+
var accessModifiersString: String {
181+
let modifiers = modifiers.filter { modifier in
182+
modifier.isAccessControl
183+
}
184+
185+
guard !modifiers.isEmpty else {
186+
return ""
187+
}
188+
189+
let string = modifiers
190+
.map { "\($0.trimmed)" }
191+
.joined(separator: " ")
192+
return "\(string) "
193+
}
194+
}
195+
174196
extension TypeSyntax {
175197
fileprivate var isActorSystem: Bool {
176198
self.trimmedDescription == "ActorSystem"
@@ -195,23 +217,38 @@ extension DeclSyntaxProtocol {
195217
}
196218
}
197219

220+
extension DeclModifierSyntax {
221+
var isAccessControl: Bool {
222+
switch self.name.tokenKind {
223+
case .keyword(.private): fallthrough
224+
case .keyword(.fileprivate): fallthrough
225+
case .keyword(.internal): fallthrough
226+
case .keyword(.package): fallthrough
227+
case .keyword(.public):
228+
return true
229+
default:
230+
return false
231+
}
232+
}
233+
}
234+
198235
// ===== -----------------------------------------------------------------------
199236
// MARK: DistributedProtocol macro errors
200237

201238
extension DistributedProtocolMacro {
202239
static func throwIllegalTargetDecl(node: AttributeSyntax, _ declaration: some DeclSyntaxProtocol) throws -> Never {
203-
let kind =
204-
if declaration.isClass {
205-
"class"
206-
} else if declaration.isActor {
207-
"actor"
208-
} else if declaration.isStruct {
209-
"struct"
210-
} else if declaration.isStruct {
211-
"enum"
212-
} else {
213-
"\(declaration.kind)"
214-
}
240+
let kind: String
241+
if declaration.isClass {
242+
kind = "class"
243+
} else if declaration.isActor {
244+
kind = "actor"
245+
} else if declaration.isStruct {
246+
kind = "struct"
247+
} else if declaration.isStruct {
248+
kind = "enum"
249+
} else {
250+
kind = "\(declaration.kind)"
251+
}
215252

216253
throw DiagnosticsError(
217254
syntax: node,

test/Distributed/Macros/distributed_macro_expansion_DistributedProtocol_various_requirements.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,23 @@ protocol Greeter3: DistributedActor where ActorSystem: DistributedActorSystem<an
7676
// CHECK: }
7777
// CHECK: }
7878
// CHECK: }
79+
80+
@_DistributedProtocol
81+
public protocol Greeter4: DistributedActor where ActorSystem == FakeActorSystem {
82+
distributed func greet(name: String) -> String
83+
}
84+
// CHECK: public distributed actor $Greeter4: Greeter4,
85+
// CHECK: Distributed._DistributedActorStub
86+
// CHECK: {
87+
// CHECK: public typealias ActorSystem = FakeActorSystem
88+
// CHECK: }
89+
90+
// CHECK: extension Greeter4 where Self: Distributed._DistributedActorStub {
91+
// CHECK: public distributed func greet(name: String) -> String {
92+
// CHECK: if #available (SwiftStdlib 6.0, *) {
93+
// CHECK: Distributed._distributedStubFatalError()
94+
// CHECK: } else {
95+
// CHECK: fatalError()
96+
// CHECK: }
97+
// CHECK: }
98+
// CHECK: }

0 commit comments

Comments
 (0)