Skip to content

Commit ba311e5

Browse files
committed
[Distributed] Guard ID synthesis from synthesizing the property multiple times; e.g. during multi module builds
1 parent 70738dd commit ba311e5

File tree

6 files changed

+114
-22
lines changed

6 files changed

+114
-22
lines changed

include/swift/AST/DistributedDecl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ class DeclContext;
3131
class FuncDecl;
3232
class NominalTypeDecl;
3333

34+
/// Obtain a distributed actor's well-known property by name.
35+
VarDecl* lookupDistributedActorProperty(NominalTypeDecl *decl, DeclName name);
36+
3437
/// Determine the concrete type of 'ActorSystem' as seen from the member.
3538
/// E.g. when in a protocol, and trying to determine what the actor system was
3639
/// constrained to.

lib/AST/DistributedDecl.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,45 @@
6161

6262
using namespace swift;
6363

64+
/******************************************************************************/
65+
/********************** Distributed Actor Properties **************************/
66+
/******************************************************************************/
67+
68+
VarDecl* swift::lookupDistributedActorProperty(NominalTypeDecl *decl, DeclName name) {
69+
assert(decl && "decl was null");
70+
auto &C = decl->getASTContext();
71+
72+
auto clazz = dyn_cast<ClassDecl>(decl);
73+
if (!clazz)
74+
return nullptr;
75+
76+
auto refs = decl->lookupDirect(name);
77+
if (refs.size() != 1)
78+
return nullptr;
79+
80+
auto var = dyn_cast<VarDecl>(refs.front());
81+
if (!var)
82+
return nullptr;
83+
84+
Type expectedType = Type();
85+
if (name == C.Id_id) {
86+
expectedType = getDistributedActorIDType(decl);
87+
} else if (name == C.Id_actorSystem) {
88+
expectedType = getDistributedActorSystemType(decl);
89+
} else {
90+
llvm_unreachable("Unexpected distributed actor property lookup!");
91+
}
92+
if (!expectedType)
93+
return nullptr;
94+
95+
if (!var->getInterfaceType()->isEqual(expectedType))
96+
return nullptr;
97+
98+
assert(var->isSynthesized() && "Expected compiler synthesized property");
99+
return var;
100+
}
101+
102+
64103
/******************************************************************************/
65104
/************** Distributed Actor System Associated Types *********************/
66105
/******************************************************************************/

lib/SILGen/SILGenDistributed.cpp

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,6 @@ using namespace Lowering;
3838

3939
// MARK: utility functions
4040

41-
/// Obtain a nominal type's member by name, as a VarDecl.
42-
/// \returns nullptr if the name lookup doesn't resolve to exactly one member,
43-
/// or the subsequent cast to VarDecl failed.
44-
static VarDecl* lookupProperty(NominalTypeDecl *decl, DeclName name) {
45-
assert(decl && "decl was null");
46-
if (auto clazz = dyn_cast<ClassDecl>(decl)) {
47-
auto refs = decl->lookupDirect(name);
48-
if (refs.size() != 1)
49-
return nullptr;
50-
return dyn_cast<VarDecl>(refs.front());
51-
}
52-
53-
return nullptr;
54-
}
55-
5641
/// Emit a reference to a specific stored property of the actor.
5742
static SILValue emitActorPropertyReference(
5843
SILGenFunction &SGF, SILLocation loc, SILValue actorSelf,
@@ -186,7 +171,7 @@ static void emitActorSystemInit(SILGenFunction &SGF,
186171
// By construction, automatically generated distributed actor ctors have
187172
// exactly one ActorSystem-conforming argument to the constructor,
188173
// so we grab the first one from the params.
189-
VarDecl *var = lookupProperty(classDecl, C.Id_actorSystem);
174+
VarDecl *var = lookupDistributedActorProperty(classDecl, C.Id_actorSystem);
190175
assert(var);
191176

192177
initializeProperty(SGF, loc, actorSelf.getValue(), var, systemValue);
@@ -219,7 +204,7 @@ void SILGenFunction::emitDistActorIdentityInit(ConstructorDecl *ctor,
219204

220205
// --- create a temporary storage for the result of the call
221206
// it will be deallocated automatically as we exit this scope
222-
VarDecl *var = lookupProperty(classDecl, C.Id_id);
207+
VarDecl *var = lookupDistributedActorProperty(classDecl, C.Id_id);
223208
auto resultTy = getLoweredType(F.mapTypeIntoContext(var->getInterfaceType()));
224209
auto temp = emitTemporaryAllocation(loc, resultTy);
225210

@@ -332,7 +317,7 @@ void SILGenFunction::emitDistributedActorReady(
332317
ManagedValue actorSystem;
333318
SGFContext sgfCxt;
334319
{
335-
VarDecl *property = lookupProperty(classDecl, C.Id_actorSystem);
320+
VarDecl *property = lookupDistributedActorProperty(classDecl, C.Id_actorSystem);
336321
Type formalType = F.mapTypeIntoContext(property->getInterfaceType());
337322
SILType loweredType = getLoweredType(formalType).getAddressType();
338323
SILValue actorSystemRef = emitActorPropertyReference(
@@ -466,11 +451,11 @@ void SILGenFunction::emitDistributedActorFactory(FuncDecl *fd) { // TODO(distrib
466451
auto classDecl = dc->getSelfClassDecl();
467452

468453
initializeProperty(*this, loc, remote,
469-
lookupProperty(classDecl, C.Id_id),
454+
lookupDistributedActorProperty(classDecl, C.Id_id),
470455
idArg);
471456

472457
initializeProperty(*this, loc, remote,
473-
lookupProperty(classDecl, C.Id_actorSystem),
458+
lookupDistributedActorProperty(classDecl, C.Id_actorSystem),
474459
actorSystemArg);
475460

476461
// ==== Branch to return the fully initialized remote instance
@@ -513,12 +498,12 @@ void SILGenFunction::emitDistributedActorSystemResignIDCall(
513498

514499
// ==== locate: self.id
515500
auto idRef = emitActorPropertyReference(
516-
*this, loc, actorSelf.getValue(), lookupProperty(actorDecl, ctx.Id_id));
501+
*this, loc, actorSelf.getValue(), lookupDistributedActorProperty(actorDecl, ctx.Id_id));
517502

518503
// ==== locate: self.actorSystem
519504
auto systemRef = emitActorPropertyReference(
520505
*this, loc, actorSelf.getValue(),
521-
lookupProperty(actorDecl, ctx.Id_actorSystem));
506+
lookupDistributedActorProperty(actorDecl, ctx.Id_actorSystem));
522507

523508
// Perform the call.
524509
emitDistributedActorSystemWitnessCall(

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,13 @@ VarDecl *GetDistributedActorIDPropertyRequest::evaluate(
737737
if (!classDecl)
738738
return nullptr;
739739

740+
// We may enter this request multiple times, e.g. in multi-file projects,
741+
// so in order to avoid synthesizing a property many times, first perform
742+
// a lookup and return if it already exists.
743+
if (auto existingProp = lookupDistributedActorProperty(classDecl, C.Id_id)) {
744+
return existingProp;
745+
}
746+
740747
return addImplicitDistributedActorIDProperty(classDecl);
741748
}
742749

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import Distributed
16+
17+
distributed actor Echo /* in the mirror */{
18+
typealias ActorSystem = LocalTestingDistributedActorSystem
19+
20+
distributed func echo(_ input: String) -> String {
21+
return "echo: \(input)"
22+
}
23+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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-emit-module -emit-module-path %t/EchoActorModule.swiftmodule -module-name EchoActorModule -disable-availability-checking %S/../Inputs/EchoActor.swift
4+
// RUN: %target-build-swift -module-name main -Xfrontend -enable-experimental-distributed -Xfrontend -disable-availability-checking -j2 -parse-as-library -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift %S/../Inputs/EchoActor.swift -o %t/a.out
5+
// RUN: %target-run %t/a.out | %FileCheck %s --color
6+
7+
// REQUIRES: executable_test
8+
// REQUIRES: concurrency
9+
// REQUIRES: distributed
10+
11+
12+
// UNSUPPORTED: use_os_stdlib
13+
// UNSUPPORTED: back_deployment_runtime
14+
15+
// FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574
16+
// UNSUPPORTED: windows
17+
18+
import Distributed
19+
import EchoActorModule
20+
import FakeDistributedActorSystems
21+
22+
func test() async {
23+
let system = LocalTestingDistributedActorSystem()
24+
25+
let echo = Echo(actorSystem: system)
26+
let reply = try! await echo.echo("in the mirror")
27+
// CHECK: reply: echo: in the mirror
28+
print("reply: \(reply)")
29+
}
30+
31+
@main struct Main {
32+
static func main() async {
33+
await test()
34+
}
35+
}

0 commit comments

Comments
 (0)