15
15
// ===----------------------------------------------------------------------===//
16
16
#include " DerivedConformances.h"
17
17
#include " TypeChecker.h"
18
+ #include " TypeCheckConcurrency.h"
19
+ #include " swift/AST/NameLookupRequests.h"
18
20
#include " swift/AST/ParameterList.h"
19
21
20
22
using namespace swift ;
@@ -46,49 +48,237 @@ static Type getPartialAsyncTaskType(ASTContext &ctx) {
46
48
return Type ();
47
49
}
48
50
51
+ // / Look for the default actor queue type.
52
+ static Type getDefaultActorQueueType (DeclContext *dc, SourceLoc loc) {
53
+ ASTContext &ctx = dc->getASTContext ();
54
+ UnqualifiedLookupOptions options;
55
+ options |= UnqualifiedLookupFlags::TypeLookup;
56
+ auto desc = UnqualifiedLookupDescriptor (
57
+ DeclNameRef (ctx.getIdentifier (" _DefaultActorQueue" )), dc, loc, options);
58
+ auto lookup =
59
+ evaluateOrDefault (ctx.evaluator , UnqualifiedLookupRequest{desc}, {});
60
+ for (const auto &result : lookup) {
61
+ if (auto typeDecl = dyn_cast<TypeDecl>(result.getValueDecl ()))
62
+ return typeDecl->getDeclaredInterfaceType ();
63
+ }
64
+
65
+ return Type ();
66
+ }
67
+
68
+ // / Look for the initialization function for the default actor storage.
69
+ static FuncDecl *getDefaultActorQueueCreate (DeclContext *dc, SourceLoc loc) {
70
+ ASTContext &ctx = dc->getASTContext ();
71
+ auto desc = UnqualifiedLookupDescriptor (
72
+ DeclNameRef (ctx.getIdentifier (" _defaultActorQueueCreate" )), dc, loc,
73
+ UnqualifiedLookupOptions ());
74
+ auto lookup =
75
+ evaluateOrDefault (ctx.evaluator , UnqualifiedLookupRequest{desc}, {});
76
+ for (const auto &result : lookup) {
77
+ // FIXME: Validate this further, because we're assuming the exact type.
78
+ if (auto func = dyn_cast<FuncDecl>(result.getValueDecl ()))
79
+ return func;
80
+ }
81
+
82
+ return nullptr ;
83
+ }
84
+
85
+ // / Look for the default enqueue operation.
86
+ static FuncDecl *getDefaultActorQueueEnqueue (DeclContext *dc, SourceLoc loc) {
87
+ ASTContext &ctx = dc->getASTContext ();
88
+ auto desc = UnqualifiedLookupDescriptor (
89
+ DeclNameRef (ctx.getIdentifier (" _defaultActorQueueEnqueuePartialTask" )),
90
+ dc, loc, UnqualifiedLookupOptions ());
91
+ auto lookup =
92
+ evaluateOrDefault (ctx.evaluator , UnqualifiedLookupRequest{desc}, {});
93
+ for (const auto &result : lookup) {
94
+ // FIXME: Validate this further, because we're assuming the exact type.
95
+ if (auto func = dyn_cast<FuncDecl>(result.getValueDecl ()))
96
+ return func;
97
+ }
98
+
99
+ return nullptr ;
100
+ }
101
+
49
102
static std::pair<BraceStmt *, bool >
50
103
deriveBodyActor_enqueuePartialTask (
51
104
AbstractFunctionDecl *enqueuePartialTask, void *) {
105
+ // func enqueue(partialTask: PartialAsyncTask) {
106
+ // _defaultActorQueueEnqueuePartialTask(
107
+ // actor: self, queue: &self.$__actor_storage, partialTask: partialTask)
108
+ // }
52
109
ASTContext &ctx = enqueuePartialTask->getASTContext ();
53
110
54
- // FIXME: Call into runtime API to enqueue the task, once we figure out
55
- // what that runtime API should look like.
111
+ // Dig out the $__actor_storage property.
112
+ auto classDecl = enqueuePartialTask->getDeclContext ()->getSelfClassDecl ();
113
+ VarDecl *storageVar = nullptr ;
114
+ for (auto decl : classDecl->lookupDirect (ctx.Id_actorStorage )) {
115
+ storageVar = dyn_cast<VarDecl>(decl);
116
+ if (storageVar)
117
+ break ;
118
+ }
119
+
120
+ // Produce an empty brace statement on failure.
121
+ auto failure = [&]() -> std::pair<BraceStmt *, bool > {
122
+ auto body = BraceStmt::create (
123
+ ctx, SourceLoc (), { }, SourceLoc (), /* implicit=*/ true );
124
+ return { body, /* isTypeChecked=*/ true };
125
+ };
126
+
127
+ if (!storageVar) {
128
+ classDecl->diagnose (
129
+ diag::concurrency_lib_missing, ctx.Id_actorStorage .str ());
130
+ return failure ();
131
+ }
132
+
133
+ // Call into the runtime to enqueue the task.
134
+ auto fn = getDefaultActorQueueEnqueue (classDecl, classDecl->getLoc ());
135
+ if (!fn) {
136
+ classDecl->diagnose (
137
+ diag::concurrency_lib_missing, " _defaultActorQueueEnqueuePartialTask" );
138
+ return failure ();
139
+ }
140
+
141
+ // Reference to _defaultActorQueueEnqueuePartialTask.
142
+ auto fnRef = new (ctx) DeclRefExpr (fn, DeclNameLoc (), /* Implicit=*/ true );
143
+ fnRef->setType (fn->getInterfaceType ());
144
+
145
+ // self argument to the function.
146
+ auto selfDecl = enqueuePartialTask->getImplicitSelfDecl ();
147
+ Type selfType = enqueuePartialTask->mapTypeIntoContext (
148
+ selfDecl->getValueInterfaceType ());
149
+ Expr *selfArg = new (ctx) DeclRefExpr (
150
+ selfDecl, DeclNameLoc (), /* Implicit=*/ true , AccessSemantics::Ordinary,
151
+ selfType);
152
+ selfArg = ErasureExpr::create (ctx, selfArg, ctx.getAnyObjectType (), { });
153
+ selfArg->setImplicit ();
154
+
155
+ // Address of the actor storage.
156
+ auto module = classDecl->getModuleContext ();
157
+ Expr *selfBase = new (ctx) DeclRefExpr (
158
+ selfDecl, DeclNameLoc (), /* Implicit=*/ true , AccessSemantics::Ordinary,
159
+ selfType);
160
+ SubstitutionMap storageVarSubs = classDecl->getDeclaredTypeInContext ()
161
+ ->getMemberSubstitutionMap (module , storageVar);
162
+ ConcreteDeclRef storageVarDeclRef (storageVar, storageVarSubs);
163
+ Type storageVarType = classDecl->mapTypeIntoContext (
164
+ storageVar->getValueInterfaceType ());
165
+ Type storageVarRefType = LValueType::get (storageVarType);
166
+ Expr *storageVarRefExpr = new (ctx) MemberRefExpr (
167
+ selfBase, SourceLoc (), storageVarDeclRef, DeclNameLoc (),
168
+ /* Implicit=*/ true );
169
+ storageVarRefExpr->setType (storageVarRefType);
170
+ storageVarRefExpr = new (ctx) InOutExpr (
171
+ SourceLoc (), storageVarRefExpr, storageVarType, /* isImplicit=*/ true );
172
+
173
+ // The partial asynchronous task.
174
+ auto partialTaskParam = enqueuePartialTask->getParameters ()->get (0 );
175
+ Expr *partialTask = new (ctx) DeclRefExpr (
176
+ partialTaskParam, DeclNameLoc (), /* Implicit=*/ true ,
177
+ AccessSemantics::Ordinary,
178
+ enqueuePartialTask->mapTypeIntoContext (
179
+ partialTaskParam->getValueInterfaceType ()));
180
+
181
+ // Form the call itself.
182
+ auto call = CallExpr::createImplicit (
183
+ ctx, fnRef, { selfArg, storageVarRefExpr, partialTask },
184
+ { ctx.getIdentifier (" actor" ), ctx.getIdentifier (" queue" ),
185
+ ctx.Id_partialTask });
186
+ call->setType (fn->getResultInterfaceType ());
187
+ call->setThrows (false );
56
188
57
189
auto body = BraceStmt::create (
58
- ctx, SourceLoc (), { }, SourceLoc (), /* implicit=*/ true );
190
+ ctx, SourceLoc (), { call }, SourceLoc (), /* implicit=*/ true );
59
191
return { body, /* isTypeChecked=*/ true };
60
192
}
61
193
62
194
// / Derive the declaration of Actor's enqueue(partialTask:).
63
195
static ValueDecl *deriveActor_enqueuePartialTask (DerivedConformance &derived) {
64
196
ASTContext &ctx = derived.Context ;
65
197
198
+ // Retrieve the types and declarations we'll need to form this operation.
66
199
Type partialTaskType = getPartialAsyncTaskType (ctx);
67
200
if (!partialTaskType) {
68
- derived.Nominal ->diagnose (diag::partial_task_type_missing);
201
+ derived.Nominal ->diagnose (
202
+ diag::concurrency_lib_missing, ctx.Id_PartialAsyncTask .str ());
69
203
return nullptr ;
70
204
}
71
205
72
206
auto parentDC = derived.getConformanceContext ();
207
+ Type defaultActorQueueType = getDefaultActorQueueType (
208
+ parentDC, derived.ConformanceDecl ->getLoc ());
209
+ if (!defaultActorQueueType) {
210
+ derived.Nominal ->diagnose (
211
+ diag::concurrency_lib_missing, " _DefaultActorQueue" );
212
+ return nullptr ;
213
+ }
214
+
215
+ auto actorStorageCreateFn = getDefaultActorQueueCreate (
216
+ parentDC, derived.ConformanceDecl ->getLoc ());
217
+ if (!actorStorageCreateFn) {
218
+ derived.Nominal ->diagnose (
219
+ diag::concurrency_lib_missing, " _defaultActorQueueCreate" );
220
+ return nullptr ;
221
+ }
222
+
223
+ // Partial task parameter to enqueue(partialTask:).
73
224
auto partialTaskParamDecl = new (ctx) ParamDecl (
74
225
SourceLoc (), SourceLoc (), ctx.Id_partialTask ,
75
226
SourceLoc (), ctx.Id_partialTask , parentDC);
76
227
partialTaskParamDecl->setInterfaceType (partialTaskType);
77
228
partialTaskParamDecl->setSpecifier (ParamSpecifier::Default);
78
229
230
+ // enqueue(partialTask:) method.
79
231
ParameterList *params = ParameterList::createWithoutLoc (partialTaskParamDecl);
80
232
auto func = FuncDecl::createImplicit (
81
233
ctx, StaticSpellingKind::None, getEnqueuePartialTaskName (ctx),
82
234
SourceLoc (), /* Async=*/ false , /* Throws=*/ false , /* GenericParams=*/ nullptr ,
83
235
params, TupleType::getEmpty (ctx), parentDC);
84
236
func->copyFormalAccessFrom (derived.Nominal );
85
237
func->setBodySynthesizer (deriveBodyActor_enqueuePartialTask);
238
+ func->setSynthesized ();
86
239
87
240
// FIXME: This function should be "actor-unsafe", not "actor-independent", but
88
241
// the latter is all we have at the moment.
89
242
func->getAttrs ().add (new (ctx) ActorIndependentAttr (/* IsImplicit=*/ true ));
90
243
91
- derived.addMembersToConformanceContext ({func});
244
+ // Actor storage property and its initialization.
245
+ auto actorStorage = new (ctx) VarDecl (
246
+ /* isStatic=*/ false , VarDecl::Introducer::Var, SourceLoc (),
247
+ ctx.Id_actorStorage , parentDC);
248
+ actorStorage->setInterfaceType (defaultActorQueueType);
249
+ actorStorage->setImplicit ();
250
+ actorStorage->setAccess (AccessLevel::Private);
251
+ actorStorage->getAttrs ().add (new (ctx) FinalAttr (/* Implicit=*/ true ));
252
+
253
+ // Pattern binding to initialize the actor storage.
254
+ Pattern *actorStoragePattern = NamedPattern::createImplicit (
255
+ ctx, actorStorage);
256
+ actorStoragePattern = TypedPattern::createImplicit (
257
+ ctx, actorStoragePattern, defaultActorQueueType);
258
+
259
+ // Initialization expression.
260
+ // FIXME: We want the equivalent of type(of: self) here, but we cannot refer
261
+ // to self, so for now we use the static type instead.
262
+ Type nominalType = derived.Nominal ->getDeclaredTypeInContext ();
263
+ Expr *metatypeArg = TypeExpr::createImplicit (nominalType, ctx);
264
+ Type anyObjectMetatype = ExistentialMetatypeType::get (ctx.getAnyObjectType ());
265
+ metatypeArg = ErasureExpr::create (ctx, metatypeArg, anyObjectMetatype, { });
266
+ Expr *actorStorageCreateFnRef = new (ctx) DeclRefExpr (
267
+ actorStorageCreateFn, DeclNameLoc (), /* Implicit=*/ true );
268
+ actorStorageCreateFnRef->setType (actorStorageCreateFn->getInterfaceType ());
269
+
270
+ auto actorStorageInit = CallExpr::createImplicit (
271
+ ctx, actorStorageCreateFnRef, { metatypeArg}, { Identifier () });
272
+ actorStorageInit->setType (actorStorageCreateFn->getResultInterfaceType ());
273
+ actorStorageInit->setThrows (false );
274
+
275
+ auto actorStoragePatternBinding = PatternBindingDecl::createImplicit (
276
+ ctx, StaticSpellingKind::None, actorStoragePattern, actorStorageInit,
277
+ parentDC);
278
+ actorStoragePatternBinding->setInitializerChecked (0 );
279
+
280
+ derived.addMembersToConformanceContext (
281
+ { func, actorStorage, actorStoragePatternBinding });
92
282
return func;
93
283
}
94
284
@@ -97,7 +287,7 @@ ValueDecl *DerivedConformance::deriveActor(ValueDecl *requirement) {
97
287
if (!func)
98
288
return nullptr ;
99
289
100
- if (func->getName () == getEnqueuePartialTaskName (Context ))
290
+ if (isEnqueuePartialTask (Context, func->getName ()))
101
291
return deriveActor_enqueuePartialTask (*this );
102
292
103
293
return nullptr ;
0 commit comments