@@ -3651,15 +3651,15 @@ class CallEmission {
3651
3651
3652
3652
Callee callee;
3653
3653
FormalEvaluationScope initialWritebackScope;
3654
- bool implicitlyAsync ;
3654
+ Optional<ActorIsolation> implicitAsyncIsolation ;
3655
3655
3656
3656
public:
3657
3657
// / Create an emission for a call of the given callee.
3658
3658
CallEmission (SILGenFunction &SGF, Callee &&callee,
3659
3659
FormalEvaluationScope &&writebackScope)
3660
3660
: SGF(SGF), callee(std::move(callee)),
3661
3661
initialWritebackScope (std::move(writebackScope)),
3662
- implicitlyAsync( false ) {}
3662
+ implicitAsyncIsolation(None ) {}
3663
3663
3664
3664
// / A factory method for decomposing the apply expr \p e into a call
3665
3665
// / emission.
@@ -3699,7 +3699,9 @@ class CallEmission {
3699
3699
// / Sets a flag that indicates whether this call be treated as being
3700
3700
// / implicitly async, i.e., it requires a hop_to_executor prior to
3701
3701
// / invoking the sync callee, etc.
3702
- void setImplicitlyAsync (bool flag) { implicitlyAsync = flag; }
3702
+ void setImplicitlyAsync (Optional<ActorIsolation> implicitAsyncIsolation) {
3703
+ this ->implicitAsyncIsolation = implicitAsyncIsolation;
3704
+ }
3703
3705
3704
3706
CleanupHandle applyCoroutine (SmallVectorImpl<ManagedValue> &yields);
3705
3707
@@ -3920,15 +3922,11 @@ RValue CallEmission::applyNormalCall(SGFContext C) {
3920
3922
3921
3923
auto mv = callee.getFnValue (SGF, borrowedSelf);
3922
3924
3923
- Optional<ValueDecl*> calleeDeclInfo;
3924
- if (implicitlyAsync)
3925
- calleeDeclInfo = callee.getDecl ();
3926
-
3927
3925
// Emit the uncurried call.
3928
3926
return SGF.emitApply (
3929
3927
std::move (resultPlan), std::move (argScope), uncurriedLoc.getValue (), mv,
3930
3928
callee.getSubstitutions (), uncurriedArgs, calleeTypeInfo, options,
3931
- uncurriedContext, calleeDeclInfo );
3929
+ uncurriedContext, implicitAsyncIsolation );
3932
3930
}
3933
3931
3934
3932
static void emitPseudoFunctionArguments (SILGenFunction &SGF,
@@ -4243,7 +4241,28 @@ CallEmission CallEmission::forApplyExpr(SILGenFunction &SGF, ApplyExpr *e) {
4243
4241
apply.callSite ->isNoThrows (),
4244
4242
apply.callSite ->isNoAsync ());
4245
4243
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
+ }
4247
4266
}
4248
4267
4249
4268
return emission;
@@ -4302,7 +4321,7 @@ RValue SILGenFunction::emitApply(ResultPlanPtr &&resultPlan,
4302
4321
ArrayRef<ManagedValue> args,
4303
4322
const CalleeTypeInfo &calleeTypeInfo,
4304
4323
ApplyOptions options, SGFContext evalContext,
4305
- Optional<ValueDecl *> implicitlyAsyncApply ) {
4324
+ Optional<ActorIsolation> implicitAsyncIsolation ) {
4306
4325
auto substFnType = calleeTypeInfo.substFnType ;
4307
4326
auto substResultType = calleeTypeInfo.substResultType ;
4308
4327
@@ -4390,22 +4409,27 @@ RValue SILGenFunction::emitApply(ResultPlanPtr &&resultPlan,
4390
4409
4391
4410
ExecutorBreadcrumb breadcrumb;
4392
4411
4393
- // The presence of `implicitlyAsyncApply ` indicates that the callee is a
4412
+ // The presence of `implicitAsyncIsolation ` indicates that the callee is a
4394
4413
// synchronous function isolated to an actor other than our own.
4395
4414
// Such functions require the caller to hop to the callee's executor
4396
4415
// prior to invoking the callee.
4397
- if (implicitlyAsyncApply. hasValue () ) {
4416
+ if (implicitAsyncIsolation ) {
4398
4417
assert (F.isAsync () && " cannot hop_to_executor in a non-async func!" );
4399
4418
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 ;
4403
4424
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 ;
4406
4429
4407
- breadcrumb = emitHopToTargetActor (loc, getActorIsolation (funcDecl),
4408
- actorSelf);
4430
+ case ActorIsolation::Independent:
4431
+ case ActorIsolation::Unspecified:
4432
+ llvm_unreachable (" Not actor-isolated" );
4409
4433
}
4410
4434
} else if (ExpectedExecutor && substFnType->isAsync ()) {
4411
4435
// Otherwise, if we're in an actor method ourselves, and we're calling into
0 commit comments