@@ -3651,15 +3651,15 @@ class CallEmission {
36513651
36523652 Callee callee;
36533653 FormalEvaluationScope initialWritebackScope;
3654- bool implicitlyAsync ;
3654+ Optional<ActorIsolation> implicitAsyncIsolation ;
36553655
36563656public:
36573657 // / Create an emission for a call of the given callee.
36583658 CallEmission (SILGenFunction &SGF, Callee &&callee,
36593659 FormalEvaluationScope &&writebackScope)
36603660 : SGF(SGF), callee(std::move(callee)),
36613661 initialWritebackScope (std::move(writebackScope)),
3662- implicitlyAsync( false ) {}
3662+ implicitAsyncIsolation(None ) {}
36633663
36643664 // / A factory method for decomposing the apply expr \p e into a call
36653665 // / emission.
@@ -3699,7 +3699,9 @@ class CallEmission {
36993699 // / Sets a flag that indicates whether this call be treated as being
37003700 // / implicitly async, i.e., it requires a hop_to_executor prior to
37013701 // / invoking the sync callee, etc.
3702- void setImplicitlyAsync (bool flag) { implicitlyAsync = flag; }
3702+ void setImplicitlyAsync (Optional<ActorIsolation> implicitAsyncIsolation) {
3703+ this ->implicitAsyncIsolation = implicitAsyncIsolation;
3704+ }
37033705
37043706 CleanupHandle applyCoroutine (SmallVectorImpl<ManagedValue> &yields);
37053707
@@ -3920,15 +3922,11 @@ RValue CallEmission::applyNormalCall(SGFContext C) {
39203922
39213923 auto mv = callee.getFnValue (SGF, borrowedSelf);
39223924
3923- Optional<ValueDecl*> calleeDeclInfo;
3924- if (implicitlyAsync)
3925- calleeDeclInfo = callee.getDecl ();
3926-
39273925 // Emit the uncurried call.
39283926 return SGF.emitApply (
39293927 std::move (resultPlan), std::move (argScope), uncurriedLoc.getValue (), mv,
39303928 callee.getSubstitutions (), uncurriedArgs, calleeTypeInfo, options,
3931- uncurriedContext, calleeDeclInfo );
3929+ uncurriedContext, implicitAsyncIsolation );
39323930}
39333931
39343932static void emitPseudoFunctionArguments (SILGenFunction &SGF,
@@ -4243,7 +4241,28 @@ CallEmission CallEmission::forApplyExpr(SILGenFunction &SGF, ApplyExpr *e) {
42434241 apply.callSite ->isNoThrows (),
42444242 apply.callSite ->isNoAsync ());
42454243
4246- emission.setImplicitlyAsync (apply.callSite ->implicitlyAsync ());
4244+ // For an implicitly-async call, determine the actor isolation.
4245+ if (apply.callSite ->implicitlyAsync ()) {
4246+ Optional<ActorIsolation> isolation;
4247+
4248+ // Check for global-actor isolation on the function type.
4249+ if (auto fnType = apply.callSite ->getFn ()->getType ()
4250+ ->castTo <FunctionType>()) {
4251+ if (Type globalActor = fnType->getGlobalActor ()) {
4252+ isolation = ActorIsolation::forGlobalActor (globalActor, false );
4253+ }
4254+ }
4255+
4256+ // If there was no global-actor isolation on the function type, find
4257+ // the callee declaration and retrieve the isolation from it.
4258+ if (!isolation) {
4259+ if (auto decl = emission.callee .getDecl ())
4260+ isolation = getActorIsolation (decl);
4261+ }
4262+
4263+ assert (isolation && " Implicitly asynchronous call without isolation" );
4264+ emission.setImplicitlyAsync (isolation);
4265+ }
42474266 }
42484267
42494268 return emission;
@@ -4302,7 +4321,7 @@ RValue SILGenFunction::emitApply(ResultPlanPtr &&resultPlan,
43024321 ArrayRef<ManagedValue> args,
43034322 const CalleeTypeInfo &calleeTypeInfo,
43044323 ApplyOptions options, SGFContext evalContext,
4305- Optional<ValueDecl *> implicitlyAsyncApply ) {
4324+ Optional<ActorIsolation> implicitAsyncIsolation ) {
43064325 auto substFnType = calleeTypeInfo.substFnType ;
43074326 auto substResultType = calleeTypeInfo.substResultType ;
43084327
@@ -4390,22 +4409,27 @@ RValue SILGenFunction::emitApply(ResultPlanPtr &&resultPlan,
43904409
43914410 ExecutorBreadcrumb breadcrumb;
43924411
4393- // The presence of `implicitlyAsyncApply ` indicates that the callee is a
4412+ // The presence of `implicitAsyncIsolation ` indicates that the callee is a
43944413 // synchronous function isolated to an actor other than our own.
43954414 // Such functions require the caller to hop to the callee's executor
43964415 // prior to invoking the callee.
4397- if (implicitlyAsyncApply. hasValue () ) {
4416+ if (implicitAsyncIsolation ) {
43984417 assert (F.isAsync () && " cannot hop_to_executor in a non-async func!" );
43994418
4400- auto calleeVD = implicitlyAsyncApply.getValue ();
4401- if (auto *funcDecl = dyn_cast_or_null<AbstractFunctionDecl>(calleeVD)) {
4402- Optional<ManagedValue> actorSelf;
4419+ switch (*implicitAsyncIsolation) {
4420+ case ActorIsolation::ActorInstance:
4421+ breadcrumb = emitHopToTargetActor (loc, *implicitAsyncIsolation,
4422+ args.back ());
4423+ break ;
44034424
4404- if (args.size () > 0 )
4405- actorSelf = args.back ();
4425+ case ActorIsolation::GlobalActor:
4426+ case ActorIsolation::GlobalActorUnsafe:
4427+ breadcrumb = emitHopToTargetActor (loc, *implicitAsyncIsolation, None);
4428+ break ;
44064429
4407- breadcrumb = emitHopToTargetActor (loc, getActorIsolation (funcDecl),
4408- actorSelf);
4430+ case ActorIsolation::Independent:
4431+ case ActorIsolation::Unspecified:
4432+ llvm_unreachable (" Not actor-isolated" );
44094433 }
44104434 } else if (ExpectedExecutor && substFnType->isAsync ()) {
44114435 // Otherwise, if we're in an actor method ourselves, and we're calling into
0 commit comments