Skip to content

Commit 05cc422

Browse files
xedinktoso
authored andcommitted
[CSApply] Distributed: Inject distributed thunk when necessary
Replace distributed member references with distributed thunks when access happens outside of distributed actor context. This significantly simplifies distributed compute properties implementation.
1 parent 0e49d41 commit 05cc422

File tree

5 files changed

+111
-18
lines changed

5 files changed

+111
-18
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,9 +1123,7 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
11231123

11241124
/// Some special handling may be necessary for thunks:
11251125
if (callSite && callSite->shouldApplyDistributedThunk()) {
1126-
if (auto distributedThunk = cast<AbstractFunctionDecl>(e->getDecl())->getDistributedThunk()) {
1127-
constant = SILDeclRef(distributedThunk).asDistributed();
1128-
}
1126+
constant = SILDeclRef(e->getDecl()).asDistributed();
11291127
} else if (afd->isBackDeployed()) {
11301128
// If we're calling a back deployed function then we need to call a
11311129
// thunk instead that will handle the fallback when the original

lib/SILGen/SILGenType.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,12 @@ class SILGenType : public TypeMemberVisitor<SILGenType> {
11611161
SGM.emitPropertyWrapperBackingInitializer(vd);
11621162
}
11631163

1164+
if (auto *thunk = vd->getDistributedThunk()) {
1165+
auto thunkRef = SILDeclRef(thunk).asDistributed();
1166+
SGM.emitFunctionDefinition(thunkRef,
1167+
SGM.getFunction(thunkRef, ForDefinition));
1168+
}
1169+
11641170
visitAbstractStorageDecl(vd);
11651171
}
11661172

@@ -1287,6 +1293,13 @@ class SILGenExtension : public TypeMemberVisitor<SILGenExtension> {
12871293
return;
12881294
}
12891295
}
1296+
1297+
if (auto *thunk = vd->getDistributedThunk()) {
1298+
auto thunkRef = SILDeclRef(thunk).asDistributed();
1299+
SGM.emitFunctionDefinition(thunkRef,
1300+
SGM.getFunction(thunkRef, ForDefinition));
1301+
}
1302+
12901303
visitAbstractStorageDecl(vd);
12911304
}
12921305

lib/Sema/CSApply.cpp

Lines changed: 89 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,11 @@ namespace {
520520
/// a remote distributed actor in the given context.
521521
bool isDistributedThunk(ConcreteDeclRef ref, Expr *context);
522522

523+
/// Determine whether the given reference on the given
524+
/// base has to be replaced with a distributed thunk instead.
525+
bool requiresDistributedThunk(Expr *base, SourceLoc memberLoc,
526+
ConcreteDeclRef memberRef);
527+
523528
public:
524529
/// Build a reference to the given declaration.
525530
Expr *buildDeclRef(SelectedOverload overload, DeclNameLoc loc,
@@ -1615,6 +1620,64 @@ namespace {
16151620
return forceUnwrapIfExpected(ref, memberLocator);
16161621
}
16171622

1623+
if (requiresDistributedThunk(base, memberLoc.getStartLoc(), memberRef)) {
1624+
auto *decl = memberRef.getDecl();
1625+
FuncDecl *thunkDecl = nullptr;
1626+
if (auto *FD = dyn_cast<FuncDecl>(decl)) {
1627+
thunkDecl = FD->getDistributedThunk();
1628+
} else {
1629+
thunkDecl = cast<VarDecl>(decl)->getDistributedThunk();
1630+
}
1631+
1632+
if (!thunkDecl)
1633+
return nullptr;
1634+
1635+
auto thunkType = refTy;
1636+
auto thunkOpenedType = openedType;
1637+
1638+
// If this is a reference to a computed property then we need to
1639+
// form a function type from it with unapplied Self so
1640+
// (Self) -> T becomes (Self) -> () -> T
1641+
if (isa<VarDecl>(decl)) {
1642+
auto extInfo = ASTExtInfoBuilder().withAsync().withThrows().build();
1643+
1644+
thunkOpenedType =
1645+
FunctionType::get(/*params=*/{}, thunkOpenedType, extInfo);
1646+
thunkType =
1647+
FunctionType::get({FunctionType::Param(selfTy)}, thunkOpenedType);
1648+
}
1649+
1650+
ConcreteDeclRef thunkRef{thunkDecl, memberRef.getSubstitutions()};
1651+
1652+
auto declRefExpr = new (context) DeclRefExpr(
1653+
thunkRef, memberLoc, Implicit, AccessSemantics::DirectToStorage);
1654+
1655+
declRefExpr->setFunctionRefKind(choice.getFunctionRefKind());
1656+
declRefExpr->setType(thunkType);
1657+
1658+
cs.cacheType(declRefExpr);
1659+
1660+
Expr *thunkApply =
1661+
DotSyntaxCallExpr::create(context, declRefExpr, dotLoc, base);
1662+
if (Implicit)
1663+
thunkApply->setImplicit();
1664+
1665+
thunkApply = finishApply(cast<ApplyExpr>(thunkApply), thunkOpenedType,
1666+
locator, memberLocator);
1667+
1668+
// If this is access to a computed property, that requires
1669+
// implicit call.
1670+
if (isa<VarDecl>(decl)) {
1671+
auto *thunkCall = CallExpr::createImplicitEmpty(context, thunkApply);
1672+
thunkCall->setType(solution.simplifyType(openedType));
1673+
thunkCall->setShouldApplyDistributedThunk(true);
1674+
cs.cacheType(thunkCall);
1675+
return thunkCall;
1676+
}
1677+
1678+
return thunkApply;
1679+
}
1680+
16181681
// For properties, build member references.
16191682
if (auto *varDecl = dyn_cast<VarDecl>(member)) {
16201683
if (isUnboundInstanceMember) {
@@ -1662,8 +1725,9 @@ namespace {
16621725
refTy = refTy->replaceCovariantResultType(containerTy, 2);
16631726

16641727
// Handle all other references.
1665-
auto declRefExpr = new (context) DeclRefExpr(memberRef, memberLoc,
1666-
Implicit, semantics);
1728+
auto declRefExpr =
1729+
new (context) DeclRefExpr(memberRef, memberLoc, Implicit, semantics);
1730+
16671731
declRefExpr->setFunctionRefKind(choice.getFunctionRefKind());
16681732
declRefExpr->setType(refTy);
16691733
cs.setType(declRefExpr, refTy);
@@ -7734,6 +7798,9 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
77347798
auto *FD = cast<AbstractFunctionDecl>(callee.getDecl());
77357799
if (!FD->hasThrows())
77367800
apply->setImplicitlyThrows(true);
7801+
if (!FD->hasAsync())
7802+
apply->setImplicitlyAsync(ImplicitActorHopTarget::forInstanceSelf());
7803+
apply->setShouldApplyDistributedThunk(true);
77377804
}
77387805

77397806
solution.setExprTypes(apply);
@@ -7853,16 +7920,29 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
78537920
}
78547921

78557922
bool ExprRewriter::isDistributedThunk(ConcreteDeclRef ref, Expr *context) {
7856-
auto *FD = dyn_cast_or_null<AbstractFunctionDecl>(ref.getDecl());
7857-
if (!(FD && FD->isInstanceMember() && FD->isDistributed()))
7858-
return false;
7859-
78607923
if (!isa<SelfApplyExpr>(context))
78617924
return false;
78627925

7926+
return requiresDistributedThunk(cast<SelfApplyExpr>(context)->getBase(),
7927+
context->getLoc(), ref);
7928+
}
7929+
7930+
bool ExprRewriter::requiresDistributedThunk(Expr *base, SourceLoc memberLoc,
7931+
ConcreteDeclRef memberRef) {
7932+
7933+
auto *memberDecl = memberRef.getDecl();
7934+
assert(memberDecl);
7935+
7936+
if (auto *FD = dyn_cast<AbstractFunctionDecl>(memberDecl)) {
7937+
if (!(FD->isInstanceMember() && FD->isDistributed()))
7938+
return false;
7939+
} else if (auto *VD = dyn_cast<VarDecl>(memberDecl)) {
7940+
if (!VD->isDistributed())
7941+
return false;
7942+
}
7943+
78637944
auto *actor = getReferencedParamOrCapture(
7864-
cast<SelfApplyExpr>(context)->getBase(),
7865-
[&](OpaqueValueExpr *opaqueValue) -> Expr * {
7945+
base, [&](OpaqueValueExpr *opaqueValue) -> Expr * {
78667946
for (const auto &existential : OpenedExistentials) {
78677947
if (existential.OpaqueValue == opaqueValue)
78687948
return existential.ExistentialValue;
@@ -7921,7 +8001,7 @@ bool ExprRewriter::isDistributedThunk(ConcreteDeclRef ref, Expr *context) {
79218001
ReferencedActor actorRef = ReferencedActor(
79228002
actor, isPotentiallyIsolated, ReferencedActor::NonIsolatedContext);
79238003
auto refResult = ActorReferenceResult::forReference(
7924-
ref, context->getLoc(), referenceDC, None, actorRef);
8004+
memberRef, memberLoc, referenceDC, None, actorRef);
79258005
switch (refResult) {
79268006
case ActorReferenceResult::ExitsActorToNonisolated:
79278007
case ActorReferenceResult::SameConcurrencyDomain:

test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_computedProperty.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem
2121

2222
distributed actor Greeter {
2323
distributed var theDistributedProperty: String {
24-
"Patrik the Seastar"
24+
"Patrick the Seastar"
2525
}
2626
}
2727

@@ -32,10 +32,10 @@ func test() async throws {
3232
let ref = try Greeter.resolve(id: local.id, using: system)
3333

3434
let reply = try await ref.theDistributedProperty
35-
// CHECK: >> remoteCall: on:main.Greeter, target:main.Greeter.name, invocation:FakeInvocationEncoder(genericSubs: [], arguments: [], returnType: Optional(Swift.String), errorType: nil), throwing:Swift.Never, returning:Swift.String
35+
// CHECK: >> remoteCall: on:main.Greeter, target:main.Greeter.theDistributedProperty(), invocation:FakeInvocationEncoder(genericSubs: [], arguments: [], returnType: Optional(Swift.String), errorType: nil), throwing:Swift.Never, returning:Swift.String
3636
// CHECK: << remoteCall return: Patrick the Seastar
3737
print("reply: \(reply)")
38-
// CHECK: reply: Echo: Caplin
38+
// CHECK: reply: Patrick the Seastar
3939
}
4040

4141
@main struct Main {

test/Distributed/distributed_actor_var_implicitly_async_throws.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,17 @@ distributed actor D {
3333
"dist"
3434
}
3535

36-
// OK:
36+
// FIXME: The following should be accepted.
37+
/*
3738
distributed var distGet: String {
3839
get distributed {
3940
"okey"
4041
}
4142
}
43+
*/
4244

43-
distributed var distSetGet: String {
44-
set distributed {
45+
distributed var distSetGet: String { // expected-error {{'distributed' computed property 'distSetGet' cannot have setter}}
46+
set distributed { // expected-error {{expected '{' to start setter definition}}
4547
_ = newValue
4648
}
4749
get distributed {

0 commit comments

Comments
 (0)