Skip to content

Commit 048e41e

Browse files
authored
Merge pull request #41747 from ktoso/wip-generic-return
[Distributed] Fix generic actors and distributed funcs returning those generics
2 parents eb6f9e0 + 466c633 commit 048e41e

8 files changed

+105
-38
lines changed

lib/AST/DistributedDecl.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,23 @@ Type ASTContext::getAssociatedTypeOfDistributedSystemOfActor(
207207
return Type();
208208

209209
auto module = actor->getParentModule();
210+
211+
// In case of protocol, let's find a concrete `ActorSystem`
212+
if (auto *protocol = dyn_cast<ProtocolDecl>(actor)) {
213+
auto signature = protocol->getGenericSignatureOfContext();
214+
215+
auto systemTy =
216+
signature->getConcreteType(actorSystemDecl->getDeclaredInterfaceType());
217+
if (!systemTy)
218+
return Type();
219+
220+
auto conformance = module->lookupConformance(systemTy, actorSystemProtocol);
221+
if (conformance.isInvalid())
222+
return Type();
223+
224+
return conformance.getTypeWitnessByName(systemTy, member);
225+
}
226+
210227
Type selfType = actor->getSelfInterfaceType();
211228
auto conformance = module->lookupConformance(selfType, actorProtocol);
212229
Type dependentType = actorProtocol->getSelfInterfaceType();

lib/SILGen/SILGenDistributed.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,9 @@ static void emitDistributedIfRemoteBranch(SILGenFunction &SGF, SILLocation Loc,
118118
"'Distributed' module available?");
119119

120120
ManagedValue selfAnyObject = B.createInitExistentialRef(
121-
Loc, SGF.getLoweredType(ctx.getAnyObjectType()), CanType(selfTy),
121+
Loc,
122+
/*existentialType=*/SGF.getLoweredType(ctx.getAnyObjectType()),
123+
/*formalConcreteType=*/selfValue.getType().getASTType(),
122124
selfValue, {});
123125
auto result = SGF.emitApplyOfLibraryIntrinsic(
124126
Loc, isRemoteFn, SubstitutionMap(), {selfAnyObject}, SGFContext());
@@ -379,6 +381,7 @@ void SILGenFunction::emitDistributedActorFactory(FuncDecl *fd) { // TODO(distrib
379381
/// having at least one call to the resolve function.
380382

381383
auto &C = getASTContext();
384+
auto DC = fd->getDeclContext();
382385
SILLocation loc = fd;
383386

384387
// ==== Prepare argument references
@@ -392,12 +395,12 @@ void SILGenFunction::emitDistributedActorFactory(FuncDecl *fd) { // TODO(distrib
392395
ManagedValue selfArg = ManagedValue::forUnmanaged(selfArgValue);
393396

394397
// type: SpecificDistributedActor.Type
395-
auto selfArgType = F.mapTypeIntoContext(selfArg.getType().getASTType());
398+
auto selfArgType = selfArg.getType().getASTType();
396399
auto selfMetatype = getLoweredType(selfArgType);
397400
SILValue selfMetatypeValue = B.createMetatype(loc, selfMetatype);
398401

399402
// type: SpecificDistributedActor
400-
auto *selfTyDecl = fd->getParent()->getSelfNominalTypeDecl();
403+
auto *selfTyDecl = DC->getSelfClassDecl();
401404
assert(selfTyDecl->isDistributedActor());
402405
auto selfTy = F.mapTypeIntoContext(selfTyDecl->getDeclaredInterfaceType());
403406
auto returnTy = getLoweredType(selfTy);
@@ -533,8 +536,8 @@ SILGenFunction::emitConditionalResignIdentityCall(SILLocation loc,
533536
assert(actorDecl->isDistributedActor() &&
534537
"only distributed actors have actorSystem lifecycle hooks in deinit");
535538

536-
auto selfTy = actorDecl->getDeclaredInterfaceType();
537-
539+
auto selfTy = F.mapTypeIntoContext(actorDecl->getDeclaredInterfaceType());
540+
538541
// we only system.resignID if we are a local actor,
539542
// and thus the address was created by system.assignID.
540543
auto isRemoteBB = createBasicBlock("isRemoteBB");

lib/SILOptimizer/Utils/DistributedActor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ void emitActorReadyCall(SILBuilder &B, SILLocation loc, SILValue actor,
183183
auto &C = F.getASTContext();
184184
emitDistributedActorSystemWitnessCall(
185185
B, loc, C.Id_actorReady, actorSystem,
186-
F.mapTypeIntoContext(actor->getType()), { actor });
186+
actor->getType(), { actor });
187187
}
188188

189189
void emitResignIdentityCall(SILBuilder &B, SILLocation loc,

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ static VarDecl *addImplicitDistributedActorIDProperty(
5555
// ==== Synthesize and add 'id' property to the actor decl
5656
Type propertyType = getDistributedActorIDType(nominal);
5757

58-
VarDecl *propDecl = new (C)
58+
auto *propDecl = new (C)
5959
VarDecl(/*IsStatic*/false, VarDecl::Introducer::Let,
6060
SourceLoc(), C.Id_id, nominal);
6161
propDecl->setImplicit();
@@ -230,20 +230,21 @@ deriveBodyDistributed_thunk(AbstractFunctionDecl *thunk, void *context) {
230230

231231
// --- Recording invocation details
232232
// -- recordGenericSubstitution(s)
233-
if (func->isGeneric() || nominal->isGeneric()) {
233+
if (thunk->isGeneric() || nominal->isGeneric()) {
234234
auto recordGenericSubstitutionDecl =
235235
C.getRecordGenericSubstitutionOnDistributedInvocationEncoder(invocationEncoderDecl);
236236
assert(recordGenericSubstitutionDecl);
237237
auto recordGenericSubstitutionDeclRef =
238238
UnresolvedDeclRefExpr::createImplicit(
239239
C, recordGenericSubstitutionDecl->getName());
240240

241-
auto sig = func->getGenericSignature();
242-
for (auto genParamType : sig.getGenericParams()) {
241+
auto signature = thunk->getGenericSignature();
242+
for (auto genParamType : signature.getGenericParams()) {
243243

244+
auto tyExpr = TypeExpr::createImplicit(thunk->mapTypeIntoContext(genParamType), C);
244245
auto subTypeExpr = new (C) DotSelfExpr(
245-
TypeExpr::createImplicit(thunk->mapTypeIntoContext(genParamType), C),
246-
sloc, sloc, thunk->mapTypeIntoContext(genParamType));
246+
tyExpr,
247+
sloc, sloc, tyExpr->getType());
247248

248249
auto recordGenericSubArgsList =
249250
ArgumentList::forImplicitCallTo(
@@ -378,7 +379,8 @@ deriveBodyDistributed_thunk(AbstractFunctionDecl *thunk, void *context) {
378379
// -- recordReturnType
379380
if (!isVoidReturn) {
380381
// Result.self
381-
auto resultType = func->getResultInterfaceType();
382+
// Watch out and always map into thunk context
383+
auto resultType = thunk->mapTypeIntoContext(func->getResultInterfaceType());
382384
auto *metaTypeRef = TypeExpr::createImplicit(resultType, C);
383385
auto *resultTypeExpr =
384386
new (C) DotSelfExpr(metaTypeRef, sloc, sloc, resultType);
@@ -426,9 +428,8 @@ deriveBodyDistributed_thunk(AbstractFunctionDecl *thunk, void *context) {
426428
}
427429

428430
// === Prepare the 'RemoteCallTarget'
429-
VarDecl *targetVar =
430-
new (C) VarDecl(/*isStatic=*/false, VarDecl::Introducer::Let, sloc,
431-
C.Id_target, thunk);
431+
auto *targetVar = new (C) VarDecl(
432+
/*isStatic=*/false, VarDecl::Introducer::Let, sloc, C.Id_target, thunk);
432433

433434
{
434435
// --- Mangle the thunk name
@@ -510,7 +511,8 @@ deriveBodyDistributed_thunk(AbstractFunctionDecl *thunk, void *context) {
510511
// -- returning: Res.Type
511512
if (!isVoidReturn) {
512513
// Result.self
513-
auto resultType = func->getResultInterfaceType();
514+
auto resultType =
515+
func->mapTypeIntoContext(func->getResultInterfaceType());
514516
auto *metaTypeRef = TypeExpr::createImplicit(resultType, C);
515517
auto *resultTypeExpr =
516518
new (C) DotSelfExpr(metaTypeRef, sloc, sloc, resultType);
@@ -561,7 +563,7 @@ static FuncDecl *createDistributedThunkFunction(FuncDecl *func) {
561563
genericParamList = genericParams->clone(DC);
562564
}
563565

564-
GenericSignature thunkGenSig =
566+
GenericSignature baseSignature =
565567
buildGenericSignature(C, func->getGenericSignature(),
566568
/*addedParameters=*/{},
567569
/*addedRequirements=*/{});
@@ -581,9 +583,9 @@ static FuncDecl *createDistributedThunkFunction(FuncDecl *func) {
581583
}
582584

583585
auto paramDecl = new (C)
584-
ParamDecl(SourceLoc(),
585-
/*argumentNameLoc=*/SourceLoc(), funcParam->getArgumentName(),
586-
/*parameterNameLoc=*/SourceLoc(), paramName, DC);
586+
ParamDecl(SourceLoc(),
587+
/*argumentNameLoc=*/SourceLoc(), funcParam->getArgumentName(),
588+
/*parameterNameLoc=*/SourceLoc(), paramName, DC);
587589

588590
paramDecl->setImplicit(true);
589591
paramDecl->setSpecifier(funcParam->getSpecifier());
@@ -593,16 +595,14 @@ static FuncDecl *createDistributedThunkFunction(FuncDecl *func) {
593595
}
594596
ParameterList *params = ParameterList::create(C, paramDecls); // = funcParams->clone(C);
595597

596-
auto thunk = FuncDecl::createImplicit(C, swift::StaticSpellingKind::None,
597-
thunkName, SourceLoc(),
598-
/*async=*/true, /*throws=*/true,
599-
genericParamList,
600-
params,
601-
func->getResultInterfaceType(),
602-
DC);
598+
auto thunk = FuncDecl::createImplicit(
599+
C, swift::StaticSpellingKind::None, thunkName, SourceLoc(),
600+
/*async=*/true, /*throws=*/true,
601+
genericParamList, params,
602+
func->getResultInterfaceType(), DC);
603603
thunk->setSynthesized(true);
604-
thunk->getAttrs().add(new (C) NonisolatedAttr(/*implicit=*/true));
605-
thunk->setGenericSignature(thunkGenSig);
604+
thunk->getAttrs().add(new (C) NonisolatedAttr(/*isImplicit=*/true));
605+
thunk->setGenericSignature(baseSignature);
606606
thunk->copyFormalAccessFrom(func, /*sourceIsParentContext=*/false);
607607
thunk->setBodySynthesizer(deriveBodyDistributed_thunk, func);
608608

test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_genericFunc.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ distributed actor Greeter {
3232

3333
}
3434

35+
distributed actor GenericGreeter<Greeting: Sendable & Codable> {
36+
distributed func echo(greeting: Greeting) -> Greeting {
37+
greeting
38+
}
39+
}
40+
3541
func test() async throws {
3642
let system = DefaultDistributedActorSystem()
3743

@@ -62,6 +68,18 @@ func test() async throws {
6268
// CHECK: >> remoteCall: on:main.Greeter, target:main.Greeter.generic2(strict:_:_:), invocation:FakeInvocationEncoder(genericSubs: [Swift.String, Swift.Int], arguments: [2.0, "Caplin", [1, 2, 3]], returnType: Optional(Swift.String), errorType: nil), throwing:Swift.Never, returning:Swift.String
6369
print("reply: \(r2)")
6470
// CHECK: reply: Caplin
71+
72+
let gen = GenericGreeter<String>(actorSystem: system)
73+
let r3 = try await gen.echo(greeting: "Hello generics!")
74+
print("reply: \(r3)")
75+
// CHECK: reply: Hello generics!
76+
77+
let genRef = try GenericGreeter<String>.resolve(id: gen.id, using: system)
78+
let r32 = try await genRef.echo(greeting: "Hello generics!")
79+
// CHECK: > encode generic sub: Swift.String
80+
// CHECK: > encode return type: Swift.String
81+
print("reply: \(r32)")
82+
// CHECK: reply: Hello generics!
6583
}
6684

6785
@main struct Main {

test/Distributed/Runtime/distributed_actor_hop_to.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ protocol LifecycleWatch: DistributedActor where ActorSystem == FakeRoundtripActo
2424
}
2525

2626
extension LifecycleWatch {
27-
func watch() async throws {
27+
func watch<T: Codable>(x: Int, _ y: T) async throws {
2828
// nothing here
29-
print("executed: \(#function)")
29+
print("executed: \(#function) - x = \(x), y = \(y)")
3030
}
3131

32-
distributed func test() async throws {
32+
distributed func test<T: Codable>(x: Int, _ y: T) async throws {
3333
print("executed: \(#function)")
34-
try await self.watch()
34+
try await self.watch(x: x, y)
3535
print("done executed: \(#function)")
3636
}
3737
}
@@ -42,11 +42,11 @@ distributed actor Worker: LifecycleWatch {
4242
@main struct Main {
4343
static func main() async {
4444
let worker: any LifecycleWatch = Worker(actorSystem: DefaultDistributedActorSystem())
45-
try! await worker.test()
45+
try! await worker.test(x: 42, "on protocol")
4646

47-
// CHECK: executed: test()
48-
// CHECK: executed: watch()
49-
// CHECK: done executed: test()
47+
// CHECK: executed: test(x:_:)
48+
// CHECK: executed: watch(x:_:) - x = 42, y = on protocol
49+
// CHECK: done executed: test(x:_:)
5050

5151
print("OK") // CHECK: OK
5252
}

test/Distributed/Runtime/distributed_actor_remote_retains_system.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ public struct FakeResultHandler: DistributedTargetInvocationResultHandler {
130130
fatalError("Not implemented: \(#function)")
131131
}
132132
}
133+
133134
typealias DefaultDistributedActorSystem = FakeActorSystem
134135

135136
// ==== Execute ----------------------------------------------------------------
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/Inputs/FakeDistributedActorSystems.swift
3+
// RUN: %target-swift-frontend -typecheck -verify -enable-experimental-distributed -disable-availability-checking -I %t 2>&1 %s
4+
// REQUIRES: concurrency
5+
// REQUIRES: distributed
6+
7+
import Distributed
8+
import FakeDistributedActorSystems
9+
10+
distributed actor Worker<Work: Sendable & Codable> {
11+
typealias ActorSystem = FakeActorSystem
12+
13+
distributed func echo(item: Work) -> Work {
14+
item
15+
}
16+
17+
distributed func echo(items: [Work]) -> [Work] {
18+
items
19+
}
20+
21+
distributed func other<Other: Codable & Sendable>(other: Other) -> Other {
22+
other
23+
}
24+
25+
distributed func others<Other: Codable & Sendable>(other: Other) -> [Other] {
26+
[other]
27+
}
28+
}

0 commit comments

Comments
 (0)