@@ -621,10 +621,13 @@ static Expr *constructDistributedUnownedSerialExecutor(ASTContext &ctx,
621621}
622622
623623static std::pair<BraceStmt *, bool >
624- deriveBodyDistributedActor_unownedExecutor (AbstractFunctionDecl *getter, void *) {
625- // var unownedExecutor : UnownedSerialExecutor {
624+ deriveBodyDistributedActor_localUnownedExecutor (AbstractFunctionDecl *getter, void *) {
625+ // var localUnownedExecutor : UnownedSerialExecutor? {
626626 // get {
627- // return Builtin.buildDefaultActorExecutorRef(self)
627+ // guard __isLocalActor(self) else {
628+ // return nil
629+ // }
630+ // return Optional(Builtin.buildDefaultActorExecutorRef(self))
628631 // }
629632 // }
630633 ASTContext &ctx = getter->getASTContext ();
@@ -641,33 +644,53 @@ deriveBodyDistributedActor_unownedExecutor(AbstractFunctionDecl *getter, void *)
641644 Expr *selfArg = DerivedConformance::createSelfDeclRef (getter);
642645 selfArg->setType (selfType);
643646
647+ // Prepare the builtin call, we'll use it after the guard, but want to take the type
648+ // of its return type earlier, so we prepare it here.
649+
644650 // The builtin call gives us a Builtin.Executor.
645651 auto builtinCall =
646652 DerivedConformance::createBuiltinCall (ctx,
647653 BuiltinValueKind::BuildDefaultActorExecutorRef,
648654 {selfType}, {}, {selfArg});
649-
650655 // Turn that into an UnownedSerialExecutor.
651656 auto initCall = constructDistributedUnownedSerialExecutor (ctx, builtinCall);
652657 if (!initCall) return failure ();
653658
654- auto ret = new (ctx) ReturnStmt (SourceLoc (), initCall, /* implicit*/ true );
659+ // guard __isLocalActor(self) else {
660+ // return nil
661+ // }
662+ auto isLocalActorDecl = ctx.getIsLocalDistributedActor ();
663+ DeclRefExpr *isLocalActorExpr =
664+ new (ctx) DeclRefExpr (ConcreteDeclRef (isLocalActorDecl), DeclNameLoc (), /* implicit=*/ true ,
665+ AccessSemantics::Ordinary,
666+ FunctionType::get ({AnyFunctionType::Param (ctx.getAnyObjectType ())},
667+ ctx.getBoolType ()));
668+ Expr *selfForIsLocalArg = DerivedConformance::createSelfDeclRef (getter);
669+ selfForIsLocalArg->setType (selfType);
670+ auto *argListForIsLocal =
671+ ArgumentList::forImplicitSingle (ctx, Identifier (),
672+ ErasureExpr::create (ctx, selfForIsLocalArg, ctx.getAnyObjectType (), {}, {}));
673+ CallExpr *isLocalActorCall = CallExpr::createImplicit (ctx, isLocalActorExpr, argListForIsLocal);
674+ isLocalActorCall->setType (ctx.getBoolType ());
675+ isLocalActorCall->setThrows (false );
676+ auto returnNilIfRemoteStmt = DerivedConformance::returnNilIfFalseGuardTypeChecked (
677+ ctx, isLocalActorCall, /* optionalWrappedType=*/ initCall->getType ());
678+
679+
680+ // Finalize preparing the unowned executor for returning.
681+ auto wrappedCall = new (ctx) InjectIntoOptionalExpr (initCall, initCall->getType ()->wrapInOptionalType ());
682+
683+ auto ret = new (ctx) ReturnStmt (SourceLoc (), wrappedCall, /* implicit*/ true );
655684
656685 auto body = BraceStmt::create (
657- ctx, SourceLoc (), { ret }, SourceLoc (), /* implicit=*/ true );
686+ ctx, SourceLoc (), { returnNilIfRemoteStmt, ret }, SourceLoc (), /* implicit=*/ true );
658687 return { body, /* isTypeChecked=*/ true };
659688}
660689
661- // / Derive the declaration of DistributedActor's unownedExecutor property.
662- static ValueDecl *deriveDistributedActor_unownedExecutor (DerivedConformance &derived) {
690+ // / Derive the declaration of DistributedActor's localUnownedExecutor property.
691+ static ValueDecl *deriveDistributedActor_localUnownedExecutor (DerivedConformance &derived) {
663692 ASTContext &ctx = derived.Context ;
664693
665- if (auto classDecl = dyn_cast<ClassDecl>(derived.Nominal )) {
666- if (auto existing = classDecl->getUnownedExecutorProperty ()) {
667- return const_cast <VarDecl*>(existing);
668- }
669- }
670-
671694 // Retrieve the types and declarations we'll need to form this operation.
672695 auto executorDecl = ctx.getUnownedSerialExecutorDecl ();
673696 if (!executorDecl) {
@@ -676,16 +699,28 @@ static ValueDecl *deriveDistributedActor_unownedExecutor(DerivedConformance &der
676699 return nullptr ;
677700 }
678701 Type executorType = executorDecl->getDeclaredInterfaceType ();
702+ Type optionalExecutorType = executorType->wrapInOptionalType ();
703+
704+ if (auto classDecl = dyn_cast<ClassDecl>(derived.Nominal )) {
705+ if (auto existing = classDecl->getLocalUnownedExecutorProperty ()) {
706+ if (existing->getInterfaceType ()->isEqual (optionalExecutorType)) {
707+ return const_cast <VarDecl *>(existing);
708+ } else {
709+ // bad type, should be diagnosed elsewhere
710+ return nullptr ;
711+ }
712+ }
713+ }
679714
680715 auto propertyPair = derived.declareDerivedProperty (
681- DerivedConformance::SynthesizedIntroducer::Var, ctx.Id_unownedExecutor ,
682- executorType, executorType ,
716+ DerivedConformance::SynthesizedIntroducer::Var, ctx.Id_localUnownedExecutor ,
717+ optionalExecutorType, optionalExecutorType ,
683718 /* static*/ false , /* final*/ false );
684719 auto property = propertyPair.first ;
685720 property->setSynthesized (true );
686721 property->getAttrs ().add (new (ctx) SemanticsAttr (SEMANTICS_DEFAULT_ACTOR,
687722 SourceLoc (), SourceRange (),
688- /* implicit*/ true ));
723+ /* implicit*/ true ));
689724 property->getAttrs ().add (new (ctx) NonisolatedAttr (/* IsImplicit=*/ true ));
690725
691726 // Make the property implicitly final.
@@ -703,8 +738,8 @@ static ValueDecl *deriveDistributedActor_unownedExecutor(DerivedConformance &der
703738 property, asAvailableAs, ctx);
704739
705740 auto getter =
706- derived.addGetterToReadOnlyDerivedProperty (property, executorType );
707- getter->setBodySynthesizer (deriveBodyDistributedActor_unownedExecutor );
741+ derived.addGetterToReadOnlyDerivedProperty (property, optionalExecutorType );
742+ getter->setBodySynthesizer (deriveBodyDistributedActor_localUnownedExecutor );
708743
709744 // IMPORTANT: MUST BE AFTER [id, actorSystem].
710745 if (auto id = derived.Nominal ->getDistributedActorIDProperty ()) {
@@ -747,24 +782,24 @@ static void assertRequiredSynthesizedPropertyOrder(DerivedConformance &derived,
747782 if (auto id = Nominal->getDistributedActorIDProperty ()) {
748783 if (auto system = Nominal->getDistributedActorSystemProperty ()) {
749784 if (auto classDecl = dyn_cast<ClassDecl>(derived.Nominal )) {
750- if (auto unownedExecutor = classDecl->getUnownedExecutorProperty ()) {
751- int idIdx, actorSystemIdx, unownedExecutorIdx = 0 ;
785+ if (auto localUnownedExecutor = classDecl->getLocalUnownedExecutorProperty ()) {
786+ int idIdx, actorSystemIdx, localUnownedExecutorIdx = 0 ;
752787 int idx = 0 ;
753788 for (auto member: Nominal->getMembers ()) {
754789 if (auto binding = dyn_cast<PatternBindingDecl>(member)) {
755790 if (binding->getSingleVar ()->getName () == Context.Id_id ) {
756791 idIdx = idx;
757792 } else if (binding->getSingleVar ()->getName () == Context.Id_actorSystem ) {
758793 actorSystemIdx = idx;
759- } else if (binding->getSingleVar ()->getName () == Context.Id_unownedExecutor ) {
760- unownedExecutorIdx = idx;
794+ } else if (binding->getSingleVar ()->getName () == Context.Id_localUnownedExecutor ) {
795+ localUnownedExecutorIdx = idx;
761796 }
762797 idx += 1 ;
763798 }
764799 }
765- if (idIdx + actorSystemIdx + unownedExecutorIdx >= 0 + 1 + 2 ) {
800+ if (idIdx + actorSystemIdx + localUnownedExecutorIdx >= 0 + 1 + 2 ) {
766801 // we have found all the necessary fields, let's assert their order
767- assert (idIdx < actorSystemIdx < unownedExecutorIdx && " order of fields MUST be exact." );
802+ assert (idIdx < actorSystemIdx < localUnownedExecutorIdx && " order of fields MUST be exact." );
768803 }
769804 }
770805 }
@@ -786,8 +821,8 @@ ValueDecl *DerivedConformance::deriveDistributedActor(ValueDecl *requirement) {
786821 derivedValue = deriveDistributedActor_id (*this );
787822 } else if (var->getName () == Context.Id_actorSystem ) {
788823 derivedValue = deriveDistributedActor_actorSystem (*this );
789- } else if (var->getName () == Context.Id_unownedExecutor ) {
790- derivedValue = deriveDistributedActor_unownedExecutor (*this );
824+ } else if (var->getName () == Context.Id_localUnownedExecutor ) {
825+ derivedValue = deriveDistributedActor_localUnownedExecutor (*this );
791826 }
792827
793828 assertRequiredSynthesizedPropertyOrder (*this , derivedValue);
0 commit comments