@@ -679,6 +679,10 @@ namespace {
679
679
LookUpConformanceInModule (cs.DC ->getParentModule ()));
680
680
}
681
681
682
+ // / Determine whether the given reference is to a method on
683
+ // / a remote distributed actor in the given context.
684
+ bool isDistributedThunk (ConcreteDeclRef ref, Expr *context);
685
+
682
686
public:
683
687
// / Build a reference to the given declaration.
684
688
Expr *buildDeclRef (SelectedOverload overload, DeclNameLoc loc,
@@ -7583,8 +7587,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
7583
7587
7584
7588
// If this is a call to a distributed method thunk, let's mark the
7585
7589
// call as implicitly throwing.
7586
- if (isDistributedThunk (callee, apply->getFn (), dc,
7587
- target && target->isAsyncLetInitializer ())) {
7590
+ if (isDistributedThunk (callee, apply->getFn ())) {
7588
7591
auto *FD = cast<AbstractFunctionDecl>(callee.getDecl ());
7589
7592
if (!FD->hasThrows ())
7590
7593
apply->setImplicitlyThrows (true );
@@ -7667,6 +7670,90 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
7667
7670
return finishApply (apply, openedType, locator, ctorLocator);
7668
7671
}
7669
7672
7673
+ // / Determine whether this closure should be treated as Sendable.
7674
+ static bool isSendableClosure (ConstraintSystem &cs,
7675
+ const AbstractClosureExpr *closure) {
7676
+ if (auto fnType = cs.getType (const_cast <AbstractClosureExpr *>(closure))
7677
+ ->getAs <FunctionType>()) {
7678
+ if (fnType->isSendable ())
7679
+ return true ;
7680
+ }
7681
+
7682
+ return false ;
7683
+ }
7684
+
7685
+ bool ExprRewriter::isDistributedThunk (ConcreteDeclRef ref, Expr *context) {
7686
+ auto *FD = dyn_cast_or_null<AbstractFunctionDecl>(ref.getDecl ());
7687
+ if (!(FD && FD->isInstanceMember () && FD->isDistributed ()))
7688
+ return false ;
7689
+
7690
+ if (!isa<SelfApplyExpr>(context))
7691
+ return false ;
7692
+
7693
+ auto *actor = getReferencedParamOrCapture (
7694
+ cast<SelfApplyExpr>(context)->getBase (),
7695
+ [&](OpaqueValueExpr *opaqueValue) -> Expr * {
7696
+ for (const auto &existential : OpenedExistentials) {
7697
+ if (existential.OpaqueValue == opaqueValue)
7698
+ return existential.ExistentialValue ;
7699
+ }
7700
+ return nullptr ;
7701
+ });
7702
+
7703
+ if (!actor)
7704
+ return false ;
7705
+
7706
+ // If this is a method reference on an potentially isolated
7707
+ // actor then it cannot be a remote thunk.
7708
+ if (isPotentiallyIsolatedActor (actor, [&](ParamDecl *P) {
7709
+ return P->isIsolated () ||
7710
+ llvm::is_contained (solution.isolatedParams , P);
7711
+ }))
7712
+ return false ;
7713
+
7714
+ bool isInAsyncLetInitializer = target && target->isAsyncLetInitializer ();
7715
+
7716
+ auto isActorInitOrDeInitContext = [&](const DeclContext *dc) {
7717
+ return ::isActorInitOrDeInitContext (
7718
+ dc, [&](const AbstractClosureExpr *closure) {
7719
+ return isSendableClosure (cs, closure);
7720
+ });
7721
+ };
7722
+
7723
+ switch (ActorIsolationRestriction::forDeclaration (ref, dc)) {
7724
+ case ActorIsolationRestriction::CrossActorSelf: {
7725
+ // Not a thunk if it's used in actor init or de-init.
7726
+ if (!isInAsyncLetInitializer && isActorInitOrDeInitContext (dc))
7727
+ return false ;
7728
+
7729
+ // Here we know that the method could be used across actors
7730
+ // and the actor it's used on is non-isolated, which means
7731
+ // that it could be a thunk, so we have to be conservative
7732
+ // about it.
7733
+ return true ;
7734
+ }
7735
+
7736
+ case ActorIsolationRestriction::ActorSelf: {
7737
+ // An instance member of an actor can be referenced from an actor's
7738
+ // designated initializer or deinitializer.
7739
+ if (actor->isActorSelf () && !isInAsyncLetInitializer) {
7740
+ if (auto *fn = isActorInitOrDeInitContext (dc)) {
7741
+ if (!(isa<ConstructorDecl>(fn) &&
7742
+ cast<ConstructorDecl>(fn)->isConvenienceInit ()))
7743
+ return false ;
7744
+ }
7745
+ }
7746
+
7747
+ // Call on a non-isolated actor in async context requires
7748
+ // implicit thunk.
7749
+ return isInAsyncLetInitializer || cs.isAsynchronousContext (dc);
7750
+ }
7751
+
7752
+ default :
7753
+ return false ;
7754
+ }
7755
+ }
7756
+
7670
7757
// Return the precedence-yielding parent of 'expr', along with the index of
7671
7758
// 'expr' as the child of that parent. The precedence-yielding parent is the
7672
7759
// nearest ancestor of 'expr' which imposes a minimum precedence on 'expr'.
0 commit comments