@@ -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
@@ -696,10 +720,9 @@ namespace {
696720 // FIXME: Make this diagnostic more sensitive to the isolation context
697721 // of the declaration.
698722 if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
699- // FIXME: We'd like to insert 'async' at the appropriate place, but
700- // FuncDecl/AbstractFunctionDecl doesn't have the right source-location
701- // information to do so.
702- func->diagnose (diag::actor_isolated_method);
723+ func->diagnose (diag::actor_isolated_sync_func,
724+ decl->getDescriptiveKind (),
725+ decl->getName ());
703726 } else if (isa<VarDecl>(decl)) {
704727 decl->diagnose (diag::actor_mutable_state);
705728 } else {
@@ -835,9 +858,39 @@ namespace {
835858 // / Check a reference to an entity within a global actor.
836859 bool checkGlobalActorReference (
837860 ValueDecl *value, SourceLoc loc, Type globalActor) {
861+
862+ // / Returns true if this global actor reference is the callee of an Apply.
863+ // / NOTE: This check mutates the identified ApplyExpr if it returns true!
864+ auto inspectForImplicitlyAsync = [&] () -> bool {
865+
866+ // Is this global actor reference outside of an ApplyExpr?
867+ if (applyStack.size () == 0 )
868+ return false ;
869+
870+ // Check our applyStack metadata from the traversal.
871+ // Our goal is to identify whether this global actor reference appears
872+ // as the called value of the enclosing ApplyExpr. We cannot simply
873+ // inspect Parent here because of expressions like (callee)()
874+ ApplyExpr *apply = applyStack.back ();
875+ Expr *fn = apply->getFn ()->getValueProvidingExpr ();
876+ if (auto memberRef = findMemberReference (fn)) {
877+ auto concDecl = memberRef->first ;
878+ if (value == concDecl.getDecl () && !apply->implicitlyAsync ()) {
879+ // then this ValueDecl appears as the called value of the ApplyExpr.
880+ apply->setImplicitlyAsync (true );
881+ return true ;
882+ }
883+ }
884+
885+ return false ;
886+ };
887+
838888 switch (auto contextIsolation =
839889 getInnermostIsolatedContext (getDeclContext ())) {
840890 case ActorIsolation::ActorInstance:
891+ if (inspectForImplicitlyAsync ())
892+ return false ;
893+
841894 ctx.Diags .diagnose (
842895 loc, diag::global_actor_from_instance_actor_context,
843896 value->getDescriptiveKind (), value->getName (), globalActor,
@@ -850,6 +903,12 @@ namespace {
850903 if (contextIsolation.getGlobalActor ()->isEqual (globalActor))
851904 return false ;
852905
906+ // Otherwise, we check if this decl reference is the callee of the
907+ // enclosing Apply, making it OK as an implicitly async call.
908+ if (inspectForImplicitlyAsync ())
909+ return false ;
910+
911+ // Otherwise, this is a problematic global actor decl reference.
853912 ctx.Diags .diagnose (
854913 loc, diag::global_actor_from_other_global_actor_context,
855914 value->getDescriptiveKind (), value->getName (), globalActor,
@@ -860,14 +919,18 @@ namespace {
860919
861920 case ActorIsolation::Independent:
862921 case ActorIsolation::IndependentUnsafe:
922+ if (inspectForImplicitlyAsync ())
923+ return false ;
924+
863925 ctx.Diags .diagnose (
864926 loc, diag::global_actor_from_independent_context,
865927 value->getDescriptiveKind (), value->getName (), globalActor);
866928 noteIsolatedActorMember (value);
867929 return true ;
868930
869931 case ActorIsolation::Unspecified:
870- // Okay.
932+ // Okay no matter what, but still must inspect for implicitly async.
933+ inspectForImplicitlyAsync ();
871934 return false ;
872935 }
873936 llvm_unreachable (" unhandled actor isolation kind!" );
@@ -918,9 +981,12 @@ namespace {
918981 }
919982
920983 // / Check a reference with the given base expression to the given member.
984+ // / Returns true iff the member reference refers to actor-isolated state
985+ // / in an invalid or unsafe way such that a diagnostic was emitted.
921986 bool checkMemberReference (
922987 Expr *base, ConcreteDeclRef memberRef, SourceLoc memberLoc,
923- bool isEscapingPartialApply = false ) {
988+ bool isEscapingPartialApply = false ,
989+ ApplyExpr *maybeImplicitAsync = nullptr ) {
924990 if (!base || !memberRef)
925991 return false ;
926992
@@ -934,6 +1000,11 @@ namespace {
9341000 // Must reference actor-isolated state on 'self'.
9351001 auto selfVar = getSelfReference (base);
9361002 if (!selfVar) {
1003+ // actor-isolated non-self calls are implicitly async and thus OK.
1004+ if (maybeImplicitAsync && isa<AbstractFunctionDecl>(member)) {
1005+ maybeImplicitAsync->setImplicitlyAsync (true );
1006+ return false ;
1007+ }
9371008 ctx.Diags .diagnose (
9381009 memberLoc, diag::actor_isolated_non_self_reference,
9391010 member->getDescriptiveKind (),
0 commit comments