Skip to content

Commit 9fc683a

Browse files
committed
[Distributed] Force the order of properties in AST
fix messed up rebase
1 parent 9a240e8 commit 9fc683a

File tree

7 files changed

+74
-46
lines changed

7 files changed

+74
-46
lines changed

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,17 @@ static VarDecl *addImplicitDistributedActorIDProperty(
117117
propDecl->getAttrs().add(
118118
new (C) CompilerInitializedAttr(/*IsImplicit=*/true));
119119

120-
nominal->addMember(propDecl);
121-
nominal->addMember(pbDecl);
122-
120+
// IMPORTANT: The `id` MUST be the first field of any distributed actor,
121+
// because when we allocate remote proxy instances, we don't allocate memory
122+
// for anything except the first two fields: id and actorSystem, so they
123+
// MUST be those fields.
124+
//
125+
// Their specific order also matters, because it is enforced this way in IRGen
126+
// and how we emit them in AST MUST match what IRGen expects or cross-module
127+
// things could be using wrong offsets and manifest as reading trash memory on
128+
// id or system accesses.
129+
nominal->addMember(propDecl, /*hint=*/nullptr, /*insertAtHead=*/true);
130+
nominal->addMember(pbDecl, /*hint=*/nullptr, /*insertAtHead=*/true);
123131
return propDecl;
124132
}
125133

lib/Sema/DerivedConformanceDistributedActor.cpp

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -426,32 +426,6 @@ static FuncDecl *deriveDistributedActorSystem_invokeHandlerOnReturn(
426426
/******************************* PROPERTIES ***********************************/
427427
/******************************************************************************/
428428

429-
// TODO(distributed): make use of this after all, but FORCE it?
430-
static ValueDecl *deriveDistributedActor_id(DerivedConformance &derived) {
431-
assert(derived.Nominal->isDistributedActor());
432-
auto &C = derived.Context;
433-
434-
// ```
435-
// nonisolated
436-
// let id: Self.ID // Self.ActorSystem.ActorID
437-
// ```
438-
auto propertyType = getDistributedActorIDType(derived.Nominal);
439-
440-
VarDecl *propDecl;
441-
PatternBindingDecl *pbDecl;
442-
std::tie(propDecl, pbDecl) = derived.declareDerivedProperty(
443-
DerivedConformance::SynthesizedIntroducer::Let, C.Id_id, propertyType,
444-
propertyType,
445-
/*isStatic=*/false, /*isFinal=*/true);
446-
447-
// mark as nonisolated, allowing access to it from everywhere
448-
propDecl->getAttrs().add(
449-
new (C) NonisolatedAttr(/*IsImplicit=*/true));
450-
451-
derived.addMembersToConformanceContext({ propDecl, pbDecl });
452-
return propDecl;
453-
}
454-
455429
static ValueDecl *deriveDistributedActor_actorSystem(
456430
DerivedConformance &derived) {
457431
auto &C = derived.Context;
@@ -460,8 +434,7 @@ static ValueDecl *deriveDistributedActor_actorSystem(
460434
assert(classDecl && derived.Nominal->isDistributedActor());
461435

462436
// ```
463-
// nonisolated
464-
// let actorSystem: ActorSystem
437+
// nonisolated let actorSystem: ActorSystem
465438
// ```
466439
// (no need for @actorIndependent because it is an immutable let)
467440
auto propertyType = getDistributedActorSystemType(classDecl);
@@ -477,7 +450,14 @@ static ValueDecl *deriveDistributedActor_actorSystem(
477450
propDecl->getAttrs().add(
478451
new (C) NonisolatedAttr(/*IsImplicit=*/true));
479452

480-
derived.addMembersToConformanceContext({ propDecl, pbDecl });
453+
// IMPORTANT: `id` MUST be the first field of a distributed actor, and
454+
// `actorSystem` MUST be the second field, because for a remote instance
455+
// we don't allocate memory after those two fields, so their order is very
456+
// important. The `hint` below makes sure the system is inserted right after.
457+
auto id = derived.Nominal->getDistributedActorIDProperty();
458+
derived.addMemberToConformanceContext(pbDecl, /*hint=*/id);
459+
derived.addMemberToConformanceContext(propDecl, /*hint=*/id);
460+
481461
return propDecl;
482462
}
483463

@@ -571,11 +551,14 @@ deriveDistributedActorType_SerializationRequirement(
571551

572552
ValueDecl *DerivedConformance::deriveDistributedActor(ValueDecl *requirement) {
573553
if (auto var = dyn_cast<VarDecl>(requirement)) {
574-
if (var->getName() == Context.Id_id)
575-
return deriveDistributedActor_id(*this);
576-
577554
if (var->getName() == Context.Id_actorSystem)
578555
return deriveDistributedActor_actorSystem(*this);
556+
557+
if (var->getName() == Context.Id_id)
558+
llvm_unreachable("DistributedActor.id MUST be synthesized earlier, "
559+
"because it is forced by the Identifiable conformance. "
560+
"If we attempted to do synthesis here, the earlier phase "
561+
"failed and something is wrong: please report a bug.");
579562
}
580563

581564
if (auto func = dyn_cast<FuncDecl>(requirement)) {

lib/Sema/DerivedConformances.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@ void DerivedConformance::addMembersToConformanceContext(
5151
IDC->addMember(child);
5252
}
5353

54+
void DerivedConformance::addMemberToConformanceContext(
55+
Decl *member, Decl *hint) {
56+
auto IDC = cast<IterableDeclContext>(ConformanceDecl);
57+
IDC->addMember(member, hint, /*insertAtHead=*/false);
58+
}
59+
60+
void DerivedConformance::addMemberToConformanceContext(
61+
Decl *member, bool insertAtHead) {
62+
auto IDC = cast<IterableDeclContext>(ConformanceDecl);
63+
IDC->addMember(member, /*hint=*/nullptr, insertAtHead);
64+
}
65+
5466
Type DerivedConformance::getProtocolType() const {
5567
return Protocol->getDeclaredInterfaceType();
5668
}
@@ -325,10 +337,6 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal,
325337
if (name.isSimpleName(ctx.Id_unownedExecutor))
326338
return getRequirement(KnownProtocolKind::Actor);
327339

328-
// DistributedActor.id
329-
if(name.isSimpleName(ctx.Id_id))
330-
return getRequirement(KnownProtocolKind::DistributedActor);
331-
332340
// DistributedActor.actorSystem
333341
if(name.isSimpleName(ctx.Id_actorSystem))
334342
return getRequirement(KnownProtocolKind::DistributedActor);

lib/Sema/DerivedConformances.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ class DerivedConformance {
7070

7171
/// Add \c children as members of the context that declares the conformance.
7272
void addMembersToConformanceContext(ArrayRef<Decl *> children);
73+
/// Add \c member right after the \c hint member which may be the tail
74+
void addMemberToConformanceContext(Decl *member, Decl* hint);
75+
/// Add \c member in front of any other existing members
76+
void addMemberToConformanceContext(Decl *member, bool insertAtHead);
7377

7478
/// Get the declared type of the protocol that this is conformance is for.
7579
Type getProtocolType() const;

stdlib/public/Distributed/LocalTestingDistributedActorSystem.swift

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,22 +125,34 @@ public final class LocalTestingDistributedActorSystem: DistributedActorSystem, @
125125
}
126126
}
127127

128+
@available(*, deprecated, renamed: "LocalTestingActorID")
129+
public typealias LocalTestingActorAddress = LocalTestingActorID
130+
128131
@available(SwiftStdlib 5.7, *)
129-
public struct LocalTestingActorAddress: Hashable, Sendable, Codable {
130-
public let address: String
132+
public struct LocalTestingActorID: Hashable, Sendable, Codable {
133+
@available(*, deprecated, renamed: "id")
134+
public var address: String {
135+
self.id
136+
}
137+
public let id: String
138+
139+
@available(*, deprecated, renamed: "init(id:)")
140+
public init(parse id: String) {
141+
self.id = id
142+
}
131143

132-
public init(parse address: String) {
133-
self.address = address
144+
public init(id: String) {
145+
self.id = id
134146
}
135147

136148
public init(from decoder: Decoder) throws {
137149
let container = try decoder.singleValueContainer()
138-
self.address = try container.decode(String.self)
150+
self.id = try container.decode(String.self)
139151
}
140152

141153
public func encode(to encoder: Encoder) throws {
142154
var container = encoder.singleValueContainer()
143-
try container.encode(self.address)
155+
try container.encode(self.id)
144156
}
145157
}
146158

test/Distributed/Runtime/distributed_actor_init_local.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@ distributed actor MaybeAfterAssign {
9090
}
9191
}
9292

93+
distributed actor LocalTestingDA_Int {
94+
typealias ActorSystem = LocalTestingDistributedActorSystem
95+
var int: Int
96+
init() {
97+
actorSystem = .init()
98+
int = 12
99+
}
100+
}
101+
93102
// ==== Fake Transport ---------------------------------------------------------
94103

95104
struct ActorAddress: Sendable, Hashable, Codable {
@@ -262,6 +271,10 @@ func test() async {
262271
// CHECK: assign type:MaybeAfterAssign, id:ActorAddress(address: "[[ID10:.*]]")
263272
// CHECK-NEXT: ready actor:main.MaybeAfterAssign, id:ActorAddress(address: "[[ID10]]")
264273

274+
let localDA = LocalTestingDA_Int()
275+
print("localDA = \(localDA.id)")
276+
// CHECK: localDA = LocalTestingActorID(id: "1")
277+
265278
// the following tests fail to initialize the actor's identity.
266279
print("-- start of no-assign tests --")
267280
test.append(MaybeSystem(nil))

test/IRGen/distributed_actor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import Distributed
77

88
// Type descriptor.
9-
// CHECK-LABEL: @"$s17distributed_actor7MyActorC2id11Distributed012LocalTestingD7AddressVvpWvd"
9+
// CHECK-LABEL: @"$s17distributed_actor7MyActorC2id11Distributed012LocalTestingD2IDVvpWvd"
1010
@available(SwiftStdlib 5.6, *)
1111
public distributed actor MyActor {
1212
public typealias ActorSystem = LocalTestingDistributedActorSystem

0 commit comments

Comments
 (0)