@@ -584,6 +584,7 @@ namespace {
584584 class ActorIsolationChecker : public ASTWalker {
585585 ASTContext &ctx;
586586 SmallVector<const DeclContext *, 4 > contextStack;
587+ SmallVector<ApplyExpr*, 4 > applyStack;
587588
588589 const DeclContext *getDeclContext () const {
589590 return contextStack.back ();
@@ -625,27 +626,45 @@ namespace {
625626 }
626627
627628 if (auto apply = dyn_cast<ApplyExpr>(expr)) {
629+ applyStack.push_back (apply); // record this encounter
630+
628631 // If this is a call to a partial apply thunk, decompose it to check it
629632 // like based on the original written syntax, e.g., "self.method".
630633 if (auto partialApply = decomposePartialApplyThunk (
631634 apply, Parent.getAsExpr ())) {
632635 if (auto memberRef = findMemberReference (partialApply->fn )) {
636+ // NOTE: partially-applied thunks are never annotated as
637+ // implicitly async, regardless of whether they are escaping.
638+ // So, we do not pass the ApplyExpr along to checkMemberReference.
633639 checkMemberReference (
634640 partialApply->base , memberRef->first , memberRef->second ,
635641 partialApply->isEscaping );
636642
637643 partialApply->base ->walk (*this );
644+
645+ // manual clean-up since normal traversal is skipped
646+ assert (applyStack.back () == apply);
647+ applyStack.pop_back ();
648+
638649 return { false , expr };
639650 }
640651 }
641652 }
642653
654+ // NOTE: SelfApplyExpr is a subtype of ApplyExpr
643655 if (auto call = dyn_cast<SelfApplyExpr>(expr)) {
644656 Expr *fn = call->getFn ()->getValueProvidingExpr ();
645657 if (auto memberRef = findMemberReference (fn)) {
646658 checkMemberReference (
647- call->getArg (), memberRef->first , memberRef->second );
659+ call->getArg (), memberRef->first , memberRef->second ,
660+ /* isEscapingPartialApply=*/ false , call);
661+
648662 call->getArg ()->walk (*this );
663+
664+ // manual clean-up since normal traversal is skipped
665+ assert (applyStack.back () == dyn_cast<ApplyExpr>(expr));
666+ applyStack.pop_back ();
667+
649668 return { false , expr };
650669 }
651670 }
@@ -659,6 +678,11 @@ namespace {
659678 contextStack.pop_back ();
660679 }
661680
681+ if (auto *apply = dyn_cast<ApplyExpr>(expr)) {
682+ assert (applyStack.back () == apply);
683+ applyStack.pop_back ();
684+ }
685+
662686 return expr;
663687 }
664688
@@ -835,9 +859,39 @@ namespace {
835859 // / Check a reference to an entity within a global actor.
836860 bool checkGlobalActorReference (
837861 ValueDecl *value, SourceLoc loc, Type globalActor) {
862+
863+ // / Returns true if this global actor reference is the callee of an Apply.
864+ // / NOTE: This check mutates the identified ApplyExpr if it returns true!
865+ auto inspectForImplicitlyAsync = [&] () -> bool {
866+
867+ // Is this global actor reference outside of an ApplyExpr?
868+ if (applyStack.size () == 0 )
869+ return false ;
870+
871+ // Check our applyStack metadata from the traversal.
872+ // Our goal is to identify whether this global actor reference appears
873+ // as the called value of the enclosing ApplyExpr. We cannot simply
874+ // inspect Parent here because of expressions like (callee)()
875+ ApplyExpr *apply = applyStack.back ();
876+ Expr *fn = apply->getFn ()->getValueProvidingExpr ();
877+ if (auto memberRef = findMemberReference (fn)) {
878+ auto concDecl = memberRef->first ;
879+ if (value == concDecl.getDecl () && !apply->implicitlyAsync ()) {
880+ // then this ValueDecl appears as the called value of the ApplyExpr.
881+ apply->setImplicitlyAsync (true );
882+ return true ;
883+ }
884+ }
885+
886+ return false ;
887+ };
888+
838889 switch (auto contextIsolation =
839890 getInnermostIsolatedContext (getDeclContext ())) {
840891 case ActorIsolation::ActorInstance:
892+ if (inspectForImplicitlyAsync ())
893+ return false ;
894+
841895 ctx.Diags .diagnose (
842896 loc, diag::global_actor_from_instance_actor_context,
843897 value->getDescriptiveKind (), value->getName (), globalActor,
@@ -850,6 +904,12 @@ namespace {
850904 if (contextIsolation.getGlobalActor ()->isEqual (globalActor))
851905 return false ;
852906
907+ // Otherwise, we check if this decl reference is the callee of the
908+ // enclosing Apply, making it OK as an implicitly async call.
909+ if (inspectForImplicitlyAsync ())
910+ return false ;
911+
912+ // Otherwise, this is a problematic global actor decl reference.
853913 ctx.Diags .diagnose (
854914 loc, diag::global_actor_from_other_global_actor_context,
855915 value->getDescriptiveKind (), value->getName (), globalActor,
@@ -860,14 +920,18 @@ namespace {
860920
861921 case ActorIsolation::Independent:
862922 case ActorIsolation::IndependentUnsafe:
923+ if (inspectForImplicitlyAsync ())
924+ return false ;
925+
863926 ctx.Diags .diagnose (
864927 loc, diag::global_actor_from_independent_context,
865928 value->getDescriptiveKind (), value->getName (), globalActor);
866929 noteIsolatedActorMember (value);
867930 return true ;
868931
869932 case ActorIsolation::Unspecified:
870- // Okay.
933+ // Okay no matter what, but still must inspect for implicitly async.
934+ inspectForImplicitlyAsync ();
871935 return false ;
872936 }
873937 llvm_unreachable (" unhandled actor isolation kind!" );
@@ -918,9 +982,12 @@ namespace {
918982 }
919983
920984 // / Check a reference with the given base expression to the given member.
985+ // / Returns true iff the member reference refers to actor-isolated state
986+ // / in an invalid or unsafe way such that a diagnostic was emitted.
921987 bool checkMemberReference (
922988 Expr *base, ConcreteDeclRef memberRef, SourceLoc memberLoc,
923- bool isEscapingPartialApply = false ) {
989+ bool isEscapingPartialApply = false ,
990+ ApplyExpr *maybeImplicitAsync = nullptr ) {
924991 if (!base || !memberRef)
925992 return false ;
926993
@@ -934,6 +1001,11 @@ namespace {
9341001 // Must reference actor-isolated state on 'self'.
9351002 auto selfVar = getSelfReference (base);
9361003 if (!selfVar) {
1004+ // actor-isolated non-self calls are implicitly async and thus OK.
1005+ if (maybeImplicitAsync && isa<AbstractFunctionDecl>(member)) {
1006+ maybeImplicitAsync->setImplicitlyAsync (true );
1007+ return false ;
1008+ }
9371009 ctx.Diags .diagnose (
9381010 memberLoc, diag::actor_isolated_non_self_reference,
9391011 member->getDescriptiveKind (),
0 commit comments