@@ -419,13 +419,26 @@ VarDecl *GlobalActorInstanceRequest::evaluate(
419
419
420
420
Optional<std::pair<CustomAttr *, NominalTypeDecl *>>
421
421
GlobalActorAttributeRequest::evaluate (
422
- Evaluator &evaluator, Decl *decl) const {
423
- ASTContext &ctx = decl->getASTContext ();
424
- auto dc = decl->getDeclContext ();
422
+ Evaluator &evaluator,
423
+ llvm::PointerUnion<Decl *, ClosureExpr *> subject) const {
424
+ DeclContext *dc;
425
+ DeclAttributes *declAttrs;
426
+ SourceLoc loc;
427
+ if (auto decl = subject.dyn_cast <Decl *>()) {
428
+ dc = decl->getDeclContext ();
429
+ declAttrs = &decl->getAttrs ();
430
+ loc = decl->getLoc ();
431
+ } else {
432
+ auto closure = subject.get <ClosureExpr *>();
433
+ dc = closure;
434
+ declAttrs = &closure->getAttrs ();
435
+ loc = closure->getLoc ();
436
+ }
437
+ ASTContext &ctx = dc->getASTContext ();
425
438
CustomAttr *globalActorAttr = nullptr ;
426
439
NominalTypeDecl *globalActorNominal = nullptr ;
427
440
428
- for (auto attr : decl-> getAttrs (). getAttributes <CustomAttr>()) {
441
+ for (auto attr : declAttrs-> getAttributes <CustomAttr>()) {
429
442
auto mutableAttr = const_cast <CustomAttr *>(attr);
430
443
// Figure out which nominal declaration this custom attribute refers to.
431
444
auto nominal = evaluateOrDefault (ctx.evaluator ,
@@ -440,10 +453,10 @@ GlobalActorAttributeRequest::evaluate(
440
453
if (!nominal->isGlobalActor ())
441
454
continue ;
442
455
443
- // Only a single global actor can be applied to a given declaration .
456
+ // Only a single global actor can be applied to a given entity .
444
457
if (globalActorAttr) {
445
- decl-> diagnose (
446
- diag::multiple_global_actors, globalActorNominal->getName (),
458
+ ctx. Diags . diagnose (
459
+ loc, diag::multiple_global_actors, globalActorNominal->getName (),
447
460
nominal->getName ());
448
461
continue ;
449
462
}
@@ -455,8 +468,14 @@ GlobalActorAttributeRequest::evaluate(
455
468
if (!globalActorAttr)
456
469
return None;
457
470
471
+ // Closures can always have a global actor attached.
472
+ if (auto closure = subject.dyn_cast <ClosureExpr *>()) {
473
+ return std::make_pair (globalActorAttr, globalActorNominal);
474
+ }
475
+
458
476
// Check that a global actor attribute makes sense on this kind of
459
477
// declaration.
478
+ auto decl = subject.get <Decl *>();
460
479
if (auto nominal = dyn_cast<NominalTypeDecl>(decl)) {
461
480
// Nominal types are okay...
462
481
if (auto classDecl = dyn_cast<ClassDecl>(nominal)){
@@ -1473,8 +1492,13 @@ namespace {
1473
1492
1474
1493
auto dc = const_cast <DeclContext *>(constDC);
1475
1494
while (!dc->isModuleScopeContext ()) {
1476
- // Look through non-escaping closures.
1477
1495
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
1496
+ // If this closure has specific isolation, use it.
1497
+ auto closureIsolation = getActorIsolationOfContext (dc);
1498
+ if (closureIsolation != ActorIsolation::Independent)
1499
+ return closureIsolation;
1500
+
1501
+ // Look through non-escaping closures.
1478
1502
if (auto type = closure->getType ()) {
1479
1503
if (auto fnType = type->getAs <AnyFunctionType>()) {
1480
1504
if (fnType->isNoEscape ()) {
@@ -2039,12 +2063,50 @@ namespace {
2039
2063
llvm_unreachable (" unhandled actor isolation kind!" );
2040
2064
}
2041
2065
2066
+ // Attempt to resolve the global actor type of a closure.
2067
+ Type resolveGlobalActorType (ClosureExpr *closure) {
2068
+ auto globalActorAttr = evaluateOrDefault (
2069
+ ctx.evaluator , GlobalActorAttributeRequest{closure}, None);
2070
+ if (!globalActorAttr)
2071
+ return Type ();
2072
+
2073
+ Type globalActor = evaluateOrDefault (
2074
+ ctx.evaluator ,
2075
+ CustomAttrTypeRequest{
2076
+ globalActorAttr->first , closure, CustomAttrTypeKind::GlobalActor},
2077
+ Type ());
2078
+ if (!globalActor || globalActor->hasError ())
2079
+ return Type ();
2080
+
2081
+ // Actor-isolated closures must be async.
2082
+ bool isAsync = false ;
2083
+ if (Type closureType = closure->getType ()) {
2084
+ if (auto closureFnType = closureType->getAs <FunctionType>())
2085
+ isAsync = closureFnType->isAsync ();
2086
+ }
2087
+
2088
+ if (!isAsync) {
2089
+ ctx.Diags .diagnose (
2090
+ closure->getLoc (), diag::global_actor_isolated_synchronous_closure,
2091
+ globalActor);
2092
+ return Type ();
2093
+ }
2094
+
2095
+ return globalActor;
2096
+ }
2097
+
2042
2098
// / Determine the isolation of a particular closure.
2043
2099
// /
2044
2100
// / This function assumes that enclosing closures have already had their
2045
2101
// / isolation checked.
2046
2102
ClosureActorIsolation determineClosureIsolation (
2047
2103
AbstractClosureExpr *closure) {
2104
+ // If the closure specifies a global actor, use it.
2105
+ if (auto explicitClosure = dyn_cast<ClosureExpr>(closure)) {
2106
+ if (Type globalActorType = resolveGlobalActorType (explicitClosure))
2107
+ return ClosureActorIsolation::forGlobalActor (globalActorType);
2108
+ }
2109
+
2048
2110
// Escaping and concurrent closures are always actor-independent.
2049
2111
if (isEscapingClosure (closure) || isConcurrentClosure (closure))
2050
2112
return ClosureActorIsolation::forIndependent ();
0 commit comments