@@ -204,6 +204,129 @@ bool IsActorRequest::evaluate(
204
204
return actorAttr != nullptr ;
205
205
}
206
206
207
+ static bool isDeclNotAsAccessibleAsParent (ValueDecl *decl,
208
+ NominalTypeDecl *parent) {
209
+ return decl->getFormalAccess () <
210
+ std::min (parent->getFormalAccess (), AccessLevel::Public);
211
+ }
212
+
213
+ VarDecl *GlobalActorInstanceRequest::evaluate (
214
+ Evaluator &evaluator, NominalTypeDecl *nominal) const {
215
+ auto globalActorAttr = nominal->getAttrs ().getAttribute <GlobalActorAttr>();
216
+ if (!globalActorAttr)
217
+ return nullptr ;
218
+
219
+ // Ensure that the actor protocol has been loaded.
220
+ ASTContext &ctx = nominal->getASTContext ();
221
+ auto actorProto = ctx.getProtocol (KnownProtocolKind::Actor);
222
+ if (!actorProto) {
223
+ nominal->diagnose (diag::concurrency_lib_missing, " Actor" );
224
+ return nullptr ;
225
+ }
226
+
227
+ // Global actors have a static property "shared" that provides an actor
228
+ // instance. The value must
229
+ SmallVector<ValueDecl *, 4 > decls;
230
+ nominal->lookupQualified (
231
+ nominal, DeclNameRef (ctx.Id_shared ), NL_QualifiedDefault, decls);
232
+ VarDecl *sharedVar = nullptr ;
233
+ llvm::TinyPtrVector<VarDecl *> candidates;
234
+ for (auto decl : decls) {
235
+ auto var = dyn_cast<VarDecl>(decl);
236
+ if (!var)
237
+ continue ;
238
+
239
+ auto varDC = var->getDeclContext ();
240
+ if (var->isStatic () &&
241
+ !isDeclNotAsAccessibleAsParent (var, nominal) &&
242
+ !(isa<ExtensionDecl>(varDC) &&
243
+ cast<ExtensionDecl>(varDC)->isConstrainedExtension ()) &&
244
+ TypeChecker::conformsToProtocol (
245
+ varDC->mapTypeIntoContext (var->getValueInterfaceType ()),
246
+ actorProto, nominal)) {
247
+ sharedVar = var;
248
+ break ;
249
+ }
250
+
251
+ candidates.push_back (var);
252
+ }
253
+
254
+ // If we found a suitable candidate, we're done.
255
+ if (sharedVar)
256
+ return sharedVar;
257
+
258
+ // Complain about the lack of a suitable 'shared' property.
259
+ {
260
+ auto primaryDiag = nominal->diagnose (
261
+ diag::global_actor_missing_shared, nominal->getName ());
262
+
263
+ // If there were no candidates, provide a Fix-It with a prototype.
264
+ if (candidates.empty () && nominal->getBraces ().Start .isValid ()) {
265
+ // Figure out the indentation we need.
266
+ SourceLoc sharedInsertionLoc = Lexer::getLocForEndOfToken (
267
+ ctx.SourceMgr , nominal->getBraces ().Start );
268
+
269
+ StringRef extraIndent;
270
+ StringRef currentIndent = Lexer::getIndentationForLine (
271
+ ctx.SourceMgr , sharedInsertionLoc, &extraIndent);
272
+ std::string stubIndent = (currentIndent + extraIndent).str ();
273
+
274
+ // From the string to add the declaration.
275
+ std::string sharedDeclString = " \n " + stubIndent;
276
+ if (nominal->getFormalAccess () >= AccessLevel::Public)
277
+ sharedDeclString += " public " ;
278
+
279
+ sharedDeclString += " static let shared = <#actor instance#>" ;
280
+
281
+ primaryDiag.fixItInsert (sharedInsertionLoc, sharedDeclString);
282
+ }
283
+ }
284
+
285
+ // Remark about all of the candidates that failed (and why).
286
+ for (auto candidate : candidates) {
287
+ if (!candidate->isStatic ()) {
288
+ candidate->diagnose (diag::global_actor_shared_not_static)
289
+ .fixItInsert (candidate->getAttributeInsertionLoc (true ), " static " );
290
+ continue ;
291
+ }
292
+
293
+ if (isDeclNotAsAccessibleAsParent (candidate, nominal)) {
294
+ AccessLevel needAccessLevel = std::min (
295
+ nominal->getFormalAccess (), AccessLevel::Public);
296
+ auto diag = candidate->diagnose (
297
+ diag::global_actor_shared_inaccessible,
298
+ getAccessLevelSpelling (candidate->getFormalAccess ()),
299
+ getAccessLevelSpelling (needAccessLevel));
300
+ if (auto attr = candidate->getAttrs ().getAttribute <AccessControlAttr>()) {
301
+ if (needAccessLevel == AccessLevel::Internal) {
302
+ diag.fixItRemove (attr->getRange ());
303
+ } else {
304
+ diag.fixItReplace (
305
+ attr->getRange (), getAccessLevelSpelling (needAccessLevel));
306
+ }
307
+ } else {
308
+ diag.fixItInsert (
309
+ candidate->getAttributeInsertionLoc (true ),
310
+ getAccessLevelSpelling (needAccessLevel));
311
+ }
312
+ continue ;
313
+ }
314
+
315
+ if (auto ext = dyn_cast<ExtensionDecl>(candidate->getDeclContext ())) {
316
+ if (ext->isConstrainedExtension ()) {
317
+ candidate->diagnose (diag::global_actor_shared_constrained_extension);
318
+ continue ;
319
+ }
320
+ }
321
+
322
+ Type varType = candidate->getDeclContext ()->mapTypeIntoContext (
323
+ candidate->getValueInterfaceType ());
324
+ candidate->diagnose (diag::global_actor_shared_non_actor_type, varType);
325
+ }
326
+
327
+ return nullptr ;
328
+ }
329
+
207
330
namespace {
208
331
209
332
// / The isolation restriction in effect for a given declaration that is
0 commit comments