1515// ===----------------------------------------------------------------------===//
1616#include " DerivedConformances.h"
1717#include " TypeChecker.h"
18+ #include " TypeCheckConcurrency.h"
19+ #include " swift/AST/NameLookupRequests.h"
1820#include " swift/AST/ParameterList.h"
1921
2022using namespace swift ;
@@ -46,49 +48,237 @@ static Type getPartialAsyncTaskType(ASTContext &ctx) {
4648 return Type ();
4749}
4850
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+
49102static std::pair<BraceStmt *, bool >
50103deriveBodyActor_enqueuePartialTask (
51104 AbstractFunctionDecl *enqueuePartialTask, void *) {
105+ // func enqueue(partialTask: PartialAsyncTask) {
106+ // _defaultActorQueueEnqueuePartialTask(
107+ // actor: self, queue: &self.$__actor_storage, partialTask: partialTask)
108+ // }
52109 ASTContext &ctx = enqueuePartialTask->getASTContext ();
53110
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 );
56188
57189 auto body = BraceStmt::create (
58- ctx, SourceLoc (), { }, SourceLoc (), /* implicit=*/ true );
190+ ctx, SourceLoc (), { call }, SourceLoc (), /* implicit=*/ true );
59191 return { body, /* isTypeChecked=*/ true };
60192}
61193
62194// / Derive the declaration of Actor's enqueue(partialTask:).
63195static ValueDecl *deriveActor_enqueuePartialTask (DerivedConformance &derived) {
64196 ASTContext &ctx = derived.Context ;
65197
198+ // Retrieve the types and declarations we'll need to form this operation.
66199 Type partialTaskType = getPartialAsyncTaskType (ctx);
67200 if (!partialTaskType) {
68- derived.Nominal ->diagnose (diag::partial_task_type_missing);
201+ derived.Nominal ->diagnose (
202+ diag::concurrency_lib_missing, ctx.Id_PartialAsyncTask .str ());
69203 return nullptr ;
70204 }
71205
72206 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:).
73224 auto partialTaskParamDecl = new (ctx) ParamDecl (
74225 SourceLoc (), SourceLoc (), ctx.Id_partialTask ,
75226 SourceLoc (), ctx.Id_partialTask , parentDC);
76227 partialTaskParamDecl->setInterfaceType (partialTaskType);
77228 partialTaskParamDecl->setSpecifier (ParamSpecifier::Default);
78229
230+ // enqueue(partialTask:) method.
79231 ParameterList *params = ParameterList::createWithoutLoc (partialTaskParamDecl);
80232 auto func = FuncDecl::createImplicit (
81233 ctx, StaticSpellingKind::None, getEnqueuePartialTaskName (ctx),
82234 SourceLoc (), /* Async=*/ false , /* Throws=*/ false , /* GenericParams=*/ nullptr ,
83235 params, TupleType::getEmpty (ctx), parentDC);
84236 func->copyFormalAccessFrom (derived.Nominal );
85237 func->setBodySynthesizer (deriveBodyActor_enqueuePartialTask);
238+ func->setSynthesized ();
86239
87240 // FIXME: This function should be "actor-unsafe", not "actor-independent", but
88241 // the latter is all we have at the moment.
89242 func->getAttrs ().add (new (ctx) ActorIndependentAttr (/* IsImplicit=*/ true ));
90243
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 });
92282 return func;
93283}
94284
@@ -97,7 +287,7 @@ ValueDecl *DerivedConformance::deriveActor(ValueDecl *requirement) {
97287 if (!func)
98288 return nullptr ;
99289
100- if (func->getName () == getEnqueuePartialTaskName (Context ))
290+ if (isEnqueuePartialTask (Context, func->getName ()))
101291 return deriveActor_enqueuePartialTask (*this );
102292
103293 return nullptr ;
0 commit comments