@@ -130,7 +130,7 @@ extension DistributedResolvableMacro {
130
130
return [ ]
131
131
}
132
132
133
- var isGenericStub = false
133
+ var isGenericOverActorSystem = false
134
134
var specificActorSystemRequirement : TypeSyntax ?
135
135
136
136
let accessModifiers = proto. accessControlModifiers
@@ -140,15 +140,15 @@ extension DistributedResolvableMacro {
140
140
case . conformanceRequirement( let conformanceReq)
141
141
where conformanceReq. leftType. isActorSystem:
142
142
specificActorSystemRequirement = conformanceReq. rightType. trimmed
143
- isGenericStub = true
143
+ isGenericOverActorSystem = true
144
144
145
145
case . sameTypeRequirement( let sameTypeReq) :
146
146
switch sameTypeReq. leftType {
147
147
case . type( let type) where type. isActorSystem:
148
148
switch sameTypeReq. rightType. trimmed {
149
149
case . type( let rightType) :
150
150
specificActorSystemRequirement = rightType
151
- isGenericStub = false
151
+ isGenericOverActorSystem = false
152
152
153
153
case . expr:
154
154
throw DiagnosticsError (
@@ -167,41 +167,78 @@ extension DistributedResolvableMacro {
167
167
}
168
168
}
169
169
170
- if isGenericStub, let specificActorSystemRequirement {
171
- return [
172
- """
173
- \( proto. modifiers) distributed actor $ \( proto. name. trimmed) <ActorSystem>: \( proto. name. trimmed) ,
174
- Distributed._DistributedActorStub
175
- where ActorSystem: \( specificActorSystemRequirement)
176
- { }
177
- """
178
- ]
179
- } else if let specificActorSystemRequirement {
180
- return [
181
- """
182
- \( proto. modifiers) distributed actor $ \( proto. name. trimmed) : \( proto. name. trimmed) ,
183
- Distributed._DistributedActorStub
184
- {
185
- \( typealiasActorSystem ( access: accessModifiers, proto, specificActorSystemRequirement) )
186
- }
187
- """
188
- ]
189
- } else {
190
- // there may be no `where` clause specifying an actor system,
191
- // but perhaps there is a typealias (or extension with a typealias),
192
- // specifying a concrete actor system so we let this synthesize
193
- // an empty `$Greeter` -- this may fail, or succeed depending on
194
- // surrounding code using a default distributed actor system,
195
- // or extensions providing it.
196
- return [
197
- """
198
- \( proto. modifiers) distributed actor $ \( proto. name. trimmed) : \( proto. name. trimmed) ,
199
- Distributed._DistributedActorStub
200
- {
170
+ var primaryAssociatedTypes : [ PrimaryAssociatedTypeSyntax ] = [ ]
171
+ if let primaryTypes = proto. primaryAssociatedTypeClause? . primaryAssociatedTypes {
172
+ primaryAssociatedTypes. append ( contentsOf: primaryTypes)
173
+ }
174
+
175
+ // The $Stub is always generic over the actor system: $Stub<ActorSystem>
176
+ var primaryTypeParams : [ String ] = primaryAssociatedTypes. map {
177
+ $0. as ( PrimaryAssociatedTypeSyntax . self) !. name. trimmed. text
178
+ }
179
+
180
+ // Don't duplicate the ActorSystem type parameter if it already was declared
181
+ // on the protocol as a primary associated type;
182
+ // otherwise, add it as first primary associated type.
183
+ let actorSystemTypeParam : [ String ] =
184
+ if primaryTypeParams. contains ( " ActorSystem " ) {
185
+ [ ]
186
+ } else if isGenericOverActorSystem {
187
+ [ " ActorSystem " ]
188
+ } else {
189
+ [ ]
190
+ }
191
+
192
+ // Prepend the actor system type parameter, as we want it to be the first one
193
+ primaryTypeParams = actorSystemTypeParam + primaryTypeParams
194
+ let typeParamsClause =
195
+ primaryTypeParams. isEmpty ? " " : " < " + primaryTypeParams. joined ( separator: " , " ) + " > "
196
+
197
+ var whereClause : String = " "
198
+ do {
199
+ let associatedTypeDecls = proto. associatedTypeDecls
200
+ var typeParamConstraints : [ String ] = [ ]
201
+ for typeParamName in primaryTypeParams {
202
+ if let decl = associatedTypeDecls [ typeParamName] {
203
+ if let inheritanceClause = decl. inheritanceClause {
204
+ typeParamConstraints. append ( " \( typeParamName) \( inheritanceClause) " )
205
+ }
201
206
}
202
- """
203
- ]
207
+ }
208
+
209
+ if isGenericOverActorSystem, let specificActorSystemRequirement {
210
+ typeParamConstraints = [ " ActorSystem: \( specificActorSystemRequirement) " ] + typeParamConstraints
211
+ }
212
+
213
+ if !typeParamConstraints. isEmpty {
214
+ whereClause += " \n where " + typeParamConstraints. joined ( separator: " , \n " )
215
+ }
204
216
}
217
+
218
+ let stubActorBody : String =
219
+ if isGenericOverActorSystem {
220
+ // there may be no `where` clause specifying an actor system,
221
+ // but perhaps there is a typealias (or extension with a typealias),
222
+ // specifying a concrete actor system so we let this synthesize
223
+ // an empty `$Greeter` -- this may fail, or succeed depending on
224
+ // surrounding code using a default distributed actor system,
225
+ // or extensions providing it.
226
+ " "
227
+ } else if let specificActorSystemRequirement {
228
+ " \( typealiasActorSystem ( access: accessModifiers, proto, specificActorSystemRequirement) ) "
229
+ } else {
230
+ " "
231
+ }
232
+
233
+ return [
234
+ """
235
+ \( proto. modifiers) distributed actor $ \( proto. name. trimmed) \( raw: typeParamsClause) : \( proto. name. trimmed) ,
236
+ Distributed._DistributedActorStub \( raw: whereClause)
237
+ {
238
+ \( raw: stubActorBody)
239
+ }
240
+ """
241
+ ]
205
242
}
206
243
207
244
private static func typealiasActorSystem( access: DeclModifierListSyntax ,
@@ -253,6 +290,23 @@ extension DeclModifierSyntax {
253
290
}
254
291
}
255
292
293
+ extension ProtocolDeclSyntax {
294
+ var associatedTypeDecls : [ String : AssociatedTypeDeclSyntax ] {
295
+ let visitor = AssociatedTypeDeclVisitor ( viewMode: . all)
296
+ visitor. walk ( self )
297
+ return visitor. associatedTypeDecls
298
+ }
299
+
300
+ final class AssociatedTypeDeclVisitor : SyntaxVisitor {
301
+ var associatedTypeDecls : [ String : AssociatedTypeDeclSyntax ] = [ : ]
302
+
303
+ override func visit( _ node: AssociatedTypeDeclSyntax ) -> SyntaxVisitorContinueKind {
304
+ associatedTypeDecls [ node. name. text] = node
305
+ return . skipChildren
306
+ }
307
+ }
308
+ }
309
+
256
310
// ===== -----------------------------------------------------------------------
257
311
// MARK: @Distributed.Resolvable macro errors
258
312
0 commit comments