Skip to content

Commit 59b9794

Browse files
authored
Merge pull request #41727 from ktoso/wip-implicit-codable
[Distributed] Implicit Codable conformance for distributed actors
2 parents d3702ba + fab0463 commit 59b9794

20 files changed

+435
-43
lines changed

include/swift/AST/DistributedDecl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ getDistributedSerializationRequirements(
106106
llvm::SmallPtrSet<ProtocolDecl *, 2>
107107
extractDistributedSerializationRequirements(
108108
ASTContext &C, ArrayRef<Requirement> allRequirements);
109+
109110
}
110111

111112
#endif /* SWIFT_DECL_TYPECHECKDISTRIBUTED_H */

include/swift/AST/TypeCheckRequests.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,6 +1039,30 @@ class IsDistributedActorRequest :
10391039
bool isCached() const { return true; }
10401040
};
10411041

1042+
/// Retrieve the implicit conformance for the given distributed actor type to
1043+
/// the Codable protocol protocol.
1044+
///
1045+
/// Similar to 'GetImplicitSendableRequest'.
1046+
class GetDistributedActorImplicitCodableRequest :
1047+
public SimpleRequest<GetDistributedActorImplicitCodableRequest,
1048+
NormalProtocolConformance *(NominalTypeDecl *, KnownProtocolKind),
1049+
RequestFlags::Cached> {
1050+
public:
1051+
using SimpleRequest::SimpleRequest;
1052+
1053+
private:
1054+
friend SimpleRequest;
1055+
1056+
NormalProtocolConformance *evaluate(
1057+
Evaluator &evaluator,
1058+
NominalTypeDecl *nominal,
1059+
KnownProtocolKind protoKind) const;
1060+
1061+
public:
1062+
// Caching
1063+
bool isCached() const { return true; }
1064+
};
1065+
10421066
/// Obtain the 'remoteCall' function of a 'DistributedActorSystem'.
10431067
class GetDistributedActorSystemRemoteCallFunctionRequest :
10441068
public SimpleRequest<GetDistributedActorSystemRemoteCallFunctionRequest,

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ SWIFT_REQUEST(TypeChecker, IsDefaultActorRequest,
107107
Cached, NoLocationInfo)
108108
SWIFT_REQUEST(TypeChecker, IsDistributedActorRequest, bool(NominalTypeDecl *),
109109
Cached, NoLocationInfo)
110+
SWIFT_REQUEST(TypeChecker, GetDistributedActorImplicitCodableRequest,
111+
NormalProtocolConformance *(NominalTypeDecl *, KnownProtocolKind),
112+
Cached, NoLocationInfo)
110113
SWIFT_REQUEST(TypeChecker, GetDistributedActorSystemRemoteCallFunctionRequest,
111114
AbstractFunctionDecl *(NominalTypeDecl *, bool),
112115
Cached, NoLocationInfo)

lib/AST/DistributedDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ Type swift::getDistributedActorSystemType(NominalTypeDecl *actor) {
102102

103103
auto DA = C.getDistributedActorDecl();
104104
if (!DA)
105-
return ErrorType::get(C);
105+
return ErrorType::get(C); // FIXME(distributed): just use Type()
106106

107107
// Dig out the actor system type.
108108
auto module = actor->getParentModule();

lib/AST/Module.cpp

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,16 +1046,28 @@ ModuleDecl::lookupExistentialConformance(Type type, ProtocolDecl *protocol) {
10461046
}
10471047

10481048
/// Whether we should create missing conformances to the given protocol.
1049-
static bool shouldCreateMissingConformances(ProtocolDecl *proto) {
1050-
return proto->isSpecificProtocol(KnownProtocolKind::Sendable);
1049+
static bool shouldCreateMissingConformances(Type type, ProtocolDecl *proto) {
1050+
// Sendable may be able to be synthesized.
1051+
if (proto->isSpecificProtocol(KnownProtocolKind::Sendable)) {
1052+
return true;
1053+
}
1054+
1055+
// A 'distributed actor' may have to create missing Codable conformances.
1056+
if (auto nominal = dyn_cast_or_null<ClassDecl>(type->getAnyNominal())) {
1057+
return nominal->isDistributedActor() &&
1058+
(proto->isSpecificProtocol(swift::KnownProtocolKind::Decodable) ||
1059+
proto->isSpecificProtocol(swift::KnownProtocolKind::Encodable));
1060+
}
1061+
1062+
return false;
10511063
}
10521064

10531065
ProtocolConformanceRef ProtocolConformanceRef::forMissingOrInvalid(
10541066
Type type, ProtocolDecl *proto) {
10551067
// Introduce "missing" conformances when appropriate, so that type checking
10561068
// (and even code generation) can continue.
10571069
ASTContext &ctx = proto->getASTContext();
1058-
if (shouldCreateMissingConformances(proto)) {
1070+
if (shouldCreateMissingConformances(type, proto)) {
10591071
return ProtocolConformanceRef(
10601072
ctx.getBuiltinConformance(
10611073
type, proto, GenericSignature(), { },
@@ -1087,7 +1099,7 @@ ProtocolConformanceRef ModuleDecl::lookupConformance(Type type,
10871099
// If we aren't supposed to allow missing conformances through for this
10881100
// protocol, replace the result with an "invalid" result.
10891101
if (!allowMissing &&
1090-
shouldCreateMissingConformances(protocol) &&
1102+
shouldCreateMissingConformances(type, protocol) &&
10911103
result.hasMissingConformance(this))
10921104
return ProtocolConformanceRef::forInvalid();
10931105

@@ -1307,16 +1319,38 @@ LookupConformanceInModuleRequest::evaluate(
13071319
// Find the (unspecialized) conformance.
13081320
SmallVector<ProtocolConformance *, 2> conformances;
13091321
if (!nominal->lookupConformance(protocol, conformances)) {
1310-
if (!protocol->isSpecificProtocol(KnownProtocolKind::Sendable))
1311-
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
1312-
1313-
// Try to infer Sendable conformance.
1314-
GetImplicitSendableRequest cvRequest{nominal};
1315-
if (auto conformance = evaluateOrDefault(
1316-
ctx.evaluator, cvRequest, nullptr)) {
1317-
conformances.clear();
1318-
conformances.push_back(conformance);
1322+
if (protocol->isSpecificProtocol(KnownProtocolKind::Sendable)) {
1323+
// Try to infer Sendable conformance.
1324+
GetImplicitSendableRequest cvRequest{nominal};
1325+
if (auto conformance = evaluateOrDefault(
1326+
ctx.evaluator, cvRequest, nullptr)) {
1327+
conformances.clear();
1328+
conformances.push_back(conformance);
1329+
} else {
1330+
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
1331+
}
1332+
} else if (protocol->isSpecificProtocol(KnownProtocolKind::Encodable) ||
1333+
protocol->isSpecificProtocol(KnownProtocolKind::Decodable)) {
1334+
if (nominal->isDistributedActor()) {
1335+
auto protoKind =
1336+
protocol->isSpecificProtocol(KnownProtocolKind::Encodable)
1337+
? KnownProtocolKind::Encodable
1338+
: KnownProtocolKind::Decodable;
1339+
auto request = GetDistributedActorImplicitCodableRequest{
1340+
nominal, protoKind};
1341+
1342+
if (auto conformance =
1343+
evaluateOrDefault(ctx.evaluator, request, nullptr)) {
1344+
conformances.clear();
1345+
conformances.push_back(conformance);
1346+
} else {
1347+
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
1348+
}
1349+
} else {
1350+
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
1351+
}
13191352
} else {
1353+
// Was unable to infer the missing conformance.
13201354
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
13211355
}
13221356
}

lib/AST/ProtocolConformance.cpp

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/AST/ASTContext.h"
2020
#include "swift/AST/Availability.h"
2121
#include "swift/AST/Decl.h"
22+
#include "swift/AST/DistributedDecl.h"
2223
#include "swift/AST/FileUnit.h"
2324
#include "swift/AST/GenericEnvironment.h"
2425
#include "swift/AST/LazyResolver.h"
@@ -63,7 +64,12 @@ Witness::Witness(ValueDecl *decl, SubstitutionMap substitutions,
6364
void Witness::dump() const { dump(llvm::errs()); }
6465

6566
void Witness::dump(llvm::raw_ostream &out) const {
66-
// FIXME: Implement!
67+
out << "Witness: ";
68+
if (auto decl = this->getDecl()) {
69+
decl->print(out);
70+
} else {
71+
out << "<no decl>\n";
72+
}
6773
}
6874

6975
ProtocolConformanceRef::ProtocolConformanceRef(ProtocolDecl *protocol,
@@ -1293,10 +1299,11 @@ void NominalTypeDecl::prepareConformanceTable() const {
12931299

12941300
// Actor classes conform to the actor protocol.
12951301
if (auto classDecl = dyn_cast<ClassDecl>(mutableThis)) {
1296-
if (classDecl->isDistributedActor())
1302+
if (classDecl->isDistributedActor()) {
12971303
addSynthesized(KnownProtocolKind::DistributedActor);
1298-
else if (classDecl->isActor())
1304+
} else if (classDecl->isActor()) {
12991305
addSynthesized(KnownProtocolKind::Actor);
1306+
}
13001307
}
13011308

13021309
// Global actors conform to the GlobalActor protocol.
@@ -1367,26 +1374,29 @@ IterableDeclContext::getLocalProtocols(ConformanceLookupKind lookupKind) const {
13671374
return result;
13681375
}
13691376

1370-
/// Find a synthesized Sendable conformance in this declaration context,
1371-
/// if there is one.
1372-
static ProtocolConformance *findSynthesizedSendableConformance(
1373-
const DeclContext *dc) {
1377+
1378+
1379+
/// Find a synthesized conformance in this declaration context, if there is one.
1380+
static ProtocolConformance *
1381+
findSynthesizedConformance(
1382+
const DeclContext *dc,
1383+
KnownProtocolKind protoKind) {
13741384
auto nominal = dc->getSelfNominalTypeDecl();
1375-
if (!nominal)
1376-
return nullptr;
13771385

1378-
if (isa<ProtocolDecl>(nominal))
1386+
// Perform some common checks
1387+
if (!nominal)
13791388
return nullptr;
13801389

13811390
if (dc->getParentModule() != nominal->getParentModule())
13821391
return nullptr;
13831392

1384-
auto cvProto = nominal->getASTContext().getProtocol(
1385-
KnownProtocolKind::Sendable);
1393+
auto &C = nominal->getASTContext();
1394+
auto cvProto = C.getProtocol(protoKind);
13861395
if (!cvProto)
13871396
return nullptr;
13881397

1389-
auto conformance = dc->getParentModule()->lookupConformance(
1398+
auto module = dc->getParentModule();
1399+
auto conformance = module->lookupConformance(
13901400
nominal->getDeclaredInterfaceType(), cvProto);
13911401
if (!conformance || !conformance.isConcrete())
13921402
return nullptr;
@@ -1405,6 +1415,43 @@ static ProtocolConformance *findSynthesizedSendableConformance(
14051415
return normal;
14061416
}
14071417

1418+
/// Find any synthesized conformances for given decl context.
1419+
///
1420+
/// Some protocol conformances can be synthesized by the compiler,
1421+
/// for those, we need to add them to "local conformances" because otherwise
1422+
/// we'd get missing symbols while attempting to use these.
1423+
static SmallVector<ProtocolConformance *, 2> findSynthesizedConformances(
1424+
const DeclContext *dc) {
1425+
auto nominal = dc->getSelfNominalTypeDecl();
1426+
if (!nominal)
1427+
return {};
1428+
1429+
// Try to find specific conformances
1430+
SmallVector<ProtocolConformance *, 2> result;
1431+
1432+
// Sendable may be synthesized for concrete types
1433+
if (!isa<ProtocolDecl>(nominal)) {
1434+
if (auto sendable =
1435+
findSynthesizedConformance(dc, KnownProtocolKind::Sendable)) {
1436+
result.push_back(sendable);
1437+
}
1438+
}
1439+
1440+
/// Distributed actors can synthesize Encodable/Decodable, so look for those
1441+
if (nominal->isDistributedActor()) {
1442+
if (auto conformance =
1443+
findSynthesizedConformance(dc, KnownProtocolKind::Encodable)) {
1444+
result.push_back(conformance);
1445+
}
1446+
if (auto conformance =
1447+
findSynthesizedConformance(dc, KnownProtocolKind::Decodable)) {
1448+
result.push_back(conformance);
1449+
}
1450+
}
1451+
1452+
return result;
1453+
}
1454+
14081455
std::vector<ProtocolConformance *>
14091456
LookupAllConformancesInContextRequest::evaluate(
14101457
Evaluator &eval, const IterableDeclContext *IDC) const {
@@ -1485,8 +1532,9 @@ IterableDeclContext::getLocalConformances(ConformanceLookupKind lookupKind)
14851532
// Look for a Sendable conformance globally. If it is synthesized
14861533
// and matches this declaration context, use it.
14871534
auto dc = getAsGenericContext();
1488-
if (auto conformance = findSynthesizedSendableConformance(dc))
1535+
for (auto conformance : findSynthesizedConformances(dc)) {
14891536
result.push_back(conformance);
1537+
}
14901538
break;
14911539
}
14921540

lib/SILGen/SILGenConstructor.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -836,8 +836,9 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
836836
}
837837

838838
// Distributed actor initializers implicitly initialize their transport and id
839-
if (isDesignatedDistActorInit)
840-
emitDistActorImplicitPropertyInits(ctor, selfArg);
839+
if (isDesignatedDistActorInit) {
840+
emitDistributedActorImplicitPropertyInits(ctor, selfArg);
841+
}
841842

842843
// Prepare the end of initializer location.
843844
SILLocation endOfInitLoc = RegularLocation(ctor);

lib/SILGen/SILGenDistributed.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ class ResignIdentity : public Cleanup {
223223
};
224224
} // end anonymous namespace
225225

226-
void SILGenFunction::emitDistActorImplicitPropertyInits(
226+
void SILGenFunction::emitDistributedActorImplicitPropertyInits(
227227
ConstructorDecl *ctor, ManagedValue selfArg) {
228228
// Only designated initializers should perform this initialization.
229229
assert(ctor->isDesignatedInit());

lib/SILGen/SILGenFunction.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2048,7 +2048,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
20482048

20492049
/// Initializes the implicit stored properties of a distributed actor that correspond to
20502050
/// its transport and identity.
2051-
void emitDistActorImplicitPropertyInits(
2051+
void emitDistributedActorImplicitPropertyInits(
20522052
ConstructorDecl *ctor, ManagedValue selfArg);
20532053

20542054
/// Given a function representing a distributed actor factory, emits the

lib/Sema/CodeSynthesis.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,12 +300,13 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
300300
if (swift::ensureDistributedModuleLoaded(decl)) {
301301
// copy access level of distributed actor init from the nominal decl
302302
accessLevel = decl->getEffectiveAccess();
303+
auto systemTy = getDistributedActorSystemType(classDecl);
303304

304305
// Create the parameter.
305306
auto *arg = new (ctx) ParamDecl(SourceLoc(), Loc, ctx.Id_system, Loc,
306307
ctx.Id_system, decl);
307308
arg->setSpecifier(ParamSpecifier::Default);
308-
arg->setInterfaceType(getDistributedActorSystemType(classDecl));
309+
arg->setInterfaceType(systemTy);
309310
arg->setImplicit();
310311

311312
params.push_back(arg);

0 commit comments

Comments
 (0)