@@ -19,7 +19,13 @@ import SwiftSyntaxBuilder
19
19
/// - `distributed actor $MyDistributedActor<ActorSystem>: $MyDistributedActor, _DistributedActorStub where ...`
20
20
/// - `extension MyDistributedActor where Self: _DistributedActorStub {}`
21
21
public struct DistributedProtocolMacro : ExtensionMacro , PeerMacro {
22
+ }
23
+
24
+
25
+ // ===== -----------------------------------------------------------------------
26
+ // MARK: Default Stub implementations Extension
22
27
28
+ extension DistributedProtocolMacro {
23
29
/// Introduce the `extension MyDistributedActor` which contains default
24
30
/// implementations of the protocol's requirements.
25
31
public static func expansion(
@@ -58,57 +64,167 @@ public struct DistributedProtocolMacro: ExtensionMacro, PeerMacro {
58
64
"""
59
65
return [ extensionDecl. cast ( ExtensionDeclSyntax . self) ]
60
66
}
67
+ }
68
+
69
+ // ===== -----------------------------------------------------------------------
70
+ // MARK: Distributed Actor Stub type
61
71
72
+ extension DistributedProtocolMacro {
62
73
public static func expansion(
63
74
of node: AttributeSyntax ,
64
75
providingPeersOf declaration: some DeclSyntaxProtocol ,
65
76
in context: some MacroExpansionContext
66
77
) throws -> [ DeclSyntax ] {
67
78
guard let proto = declaration. as ( ProtocolDeclSyntax . self) else {
68
- return [ ]
79
+ try throwIllegalTargetDecl ( node : node , declaration )
69
80
}
70
81
82
+ var isGenericStub = false
83
+ var specificActorSystemRequirement : TypeSyntax ?
71
84
// FIXME must detect this off the protocol
72
85
let serializationRequirementType : String = " Codable "
73
- let specificActorSystemRequirement : TypeSyntax ?
74
86
75
87
for req in proto. genericWhereClause? . requirements ?? [ ] {
76
88
print ( " req.requirement: \( req. requirement) " )
77
89
switch req. requirement {
78
- case . conformanceRequirement( let conformanceReq) :
90
+ case . conformanceRequirement( let conformanceReq)
91
+ where conformanceReq. leftType. isActorSystem:
79
92
print ( " conf: \( conformanceReq) " )
93
+ specificActorSystemRequirement = conformanceReq. rightType. trimmed
94
+ isGenericStub = true
80
95
81
- case . sameTypeRequirement( let sameTypeReq) :
96
+ case . sameTypeRequirement( let sameTypeReq)
97
+ where sameTypeReq. leftType. isActorSystem:
82
98
print ( " same type: \( sameTypeReq) " )
83
- if sameTypeReq. leftType. trimmedDescription == " ActorSystem " {
84
- let specificActorSystemRequirement = sameTypeReq. rightType. trimmed
85
-
86
- return [
87
- """
88
- distributed actor $ \( proto. name. trimmed) : \( proto. name. trimmed) ,
89
- Distributed._DistributedActorStub
90
- {
91
- typealias ActorSystem = \( specificActorSystemRequirement)
92
- }
93
- """
94
- ]
95
- }
96
- case . layoutRequirement( let layoutReq) :
97
- print ( " layout: \( layoutReq) " )
99
+ specificActorSystemRequirement = sameTypeReq. rightType. trimmed
100
+ isGenericStub = false
101
+
102
+ default :
103
+ print ( " SKIP: \( req) " )
104
+ continue
98
105
}
99
106
}
100
107
101
108
let stubActorDecl : DeclSyntax =
102
- """
103
- distributed actor $ \( proto. name. trimmed) <ActorSystem>: \( proto. name. trimmed) ,
104
- Distributed._DistributedActorStub
105
- where ActorSystem: DistributedActorSystem<any \( raw: serializationRequirementType) >,
106
- ActorSystem.ActorID: \( raw: serializationRequirementType)
107
- { }
108
- """
109
+ if ( isGenericStub) {
110
+ """
111
+ distributed actor $ \( proto. name. trimmed) <ActorSystem>: \( proto. name. trimmed) ,
112
+ Distributed._DistributedActorStub
113
+ where ActorSystem: DistributedActorSystem<any \( raw: serializationRequirementType) >,
114
+ ActorSystem.ActorID: \( raw: serializationRequirementType)
115
+ { }
116
+ """
117
+ } else if let specificActorSystemRequirement {
118
+ """
119
+ distributed actor $ \\ (proto.name.trimmed): \\ (proto.name.trimmed),
120
+ Distributed._DistributedActorStub
121
+ {
122
+ \( typealiasActorSystem ( specificActorSystemRequirement) )
123
+ }
124
+ """
125
+ } else {
126
+ throw DiagnosticsError (
127
+ syntax: node,
128
+ message: " '@DistributedProtocolMacro' cannot be applied to " , id: . invalidApplication)
129
+ }
109
130
110
- // return [extensionDecl, stubActorDecl]
111
131
return [ stubActorDecl]
112
132
}
113
133
134
+ private static func typealiasActorSystem( _ type: TypeSyntax ) -> DeclSyntax {
135
+ " typealias ActorSystem = \( type) "
136
+ }
137
+ }
138
+
139
+ // ===== -----------------------------------------------------------------------
140
+ // MARK: Convenience Extensions
141
+
142
+ extension TypeSyntax {
143
+ fileprivate var isActorSystem : Bool {
144
+ self . trimmedDescription == " ActorSystem "
145
+ }
146
+ }
147
+
148
+ extension DeclSyntaxProtocol {
149
+ var isClass : Bool {
150
+ return self . is ( ClassDeclSyntax . self)
151
+ }
152
+
153
+ var isActor : Bool {
154
+ return self . is ( ActorDeclSyntax . self)
155
+ }
156
+
157
+ var isEnum : Bool {
158
+ return self . is ( EnumDeclSyntax . self)
159
+ }
160
+
161
+ var isStruct : Bool {
162
+ return self . is ( StructDeclSyntax . self)
163
+ }
164
+ }
165
+
166
+ // ===== -----------------------------------------------------------------------
167
+ // MARK: DistributedProtocol macro errors
168
+
169
+ extension DistributedProtocolMacro {
170
+ static func throwIllegalTargetDecl( node: AttributeSyntax , _ declaration: some DeclSyntaxProtocol ) throws -> Never {
171
+ let kind =
172
+ if declaration. isClass {
173
+ " class "
174
+ } else if declaration. isActor {
175
+ " actor "
176
+ } else if declaration. isStruct {
177
+ " struct "
178
+ } else if declaration. isStruct {
179
+ " enum "
180
+ } else {
181
+ " \( declaration. kind) "
182
+ }
183
+
184
+ throw DiagnosticsError (
185
+ syntax: node,
186
+ message: " '@DistributedProtocol' can only be applied to 'protocol', but was attached to ' \( kind) ' " , id: . invalidApplication)
187
+ }
188
+ }
189
+
190
+ struct DistributedProtocolMacroDiagnostic : DiagnosticMessage {
191
+ enum ID : String {
192
+ case invalidApplication = " invalid type "
193
+ case missingInitializer = " missing initializer "
194
+ }
195
+
196
+ var message : String
197
+ var diagnosticID : MessageID
198
+ var severity : DiagnosticSeverity
199
+
200
+ init ( message: String , diagnosticID: SwiftDiagnostics . MessageID , severity: SwiftDiagnostics . DiagnosticSeverity = . error) {
201
+ self . message = message
202
+ self . diagnosticID = diagnosticID
203
+ self . severity = severity
204
+ }
205
+
206
+ init ( message: String , domain: String , id: ID , severity: SwiftDiagnostics . DiagnosticSeverity = . error) {
207
+ self . message = message
208
+ self . diagnosticID = MessageID ( domain: domain, id: id. rawValue)
209
+ self . severity = severity
210
+ }
211
+ }
212
+
213
+ extension DiagnosticsError {
214
+ init < S: SyntaxProtocol > (
215
+ syntax: S ,
216
+ message: String ,
217
+ domain: String = " Distributed " ,
218
+ id: DistributedProtocolMacroDiagnostic . ID ,
219
+ severity: SwiftDiagnostics . DiagnosticSeverity = . error) {
220
+ self . init ( diagnostics: [
221
+ Diagnostic (
222
+ node: Syntax ( syntax) ,
223
+ message: DistributedProtocolMacroDiagnostic (
224
+ message: message,
225
+ domain: domain,
226
+ id: id,
227
+ severity: severity) )
228
+ ] )
229
+ }
114
230
}
0 commit comments