Skip to content

Commit ef79042

Browse files
authored
Merge pull request #73781 from ktoso/da-as-a-conformance-fix-cross-module
2 parents 5828b8b + 168bc7b commit ef79042

14 files changed

+399
-135
lines changed

include/swift/AST/DistributedDecl.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,29 @@ Type getDistributedActorSystemResultHandlerType(NominalTypeDecl *system);
102102
/// Get the 'ActorID' type of a specific distributed actor system.
103103
Type getDistributedActorSystemActorIDType(NominalTypeDecl *system);
104104

105+
/// Retrieve a protocol conformance to the `Actor` protocol for a
106+
/// distributed actor type that is described via a substitution map for
107+
/// the generic signature `<T: DistributedActor>`.
108+
///
109+
/// The protocol conformance is a special one that is currently
110+
/// only used by the `distributedActorAsAnyActor` builtin.
111+
NormalProtocolConformance *
112+
getDistributedActorAsActorConformance(ASTContext &C);
113+
114+
ProtocolConformanceRef
115+
getDistributedActorAsActorConformanceRef(ASTContext &C);
116+
117+
/// Find the extension that defines the methods necessary for creating the
118+
/// the DistributedActor-as-Actor conformance.
119+
ExtensionDecl *
120+
findDistributedActorAsActorExtension(
121+
ProtocolDecl *distributedActorProto, ModuleDecl *module);
122+
123+
bool isDistributedActorAsLocalActorComputedProperty(VarDecl *var);
124+
125+
/// Get the ``DistributedActor/asLocalActor`` computed property.
126+
VarDecl *getDistributedActorAsLocalActorComputedProperty(ModuleDecl *module);
127+
105128
/// Check if the `allRequirements` represent *exactly* the
106129
/// `Encodable & Decodable` (also known as `Codable`) requirement.
107130
///

include/swift/AST/TypeCheckRequests.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,25 @@ class CanSynthesizeDistributedActorCodableConformanceRequest :
11381138
bool isCached() const { return true; }
11391139
};
11401140

1141+
/// Get a special conformance of the DistributedActor protocol to the Actor protocol.
1142+
class GetDistributedActorAsActorConformanceRequest
1143+
: public SimpleRequest<GetDistributedActorAsActorConformanceRequest,
1144+
NormalProtocolConformance *(ProtocolDecl *),
1145+
RequestFlags::Cached> {
1146+
public:
1147+
using SimpleRequest::SimpleRequest;
1148+
1149+
private:
1150+
friend SimpleRequest;
1151+
1152+
NormalProtocolConformance *
1153+
evaluate(Evaluator &evaluator, ProtocolDecl *distributedActorProto) const;
1154+
1155+
public:
1156+
// Caching
1157+
bool isCached() const { return true; }
1158+
};
1159+
11411160
/// Retrieve the implicit conformance for the given distributed actor type to
11421161
/// the Codable protocol protocol.
11431162
///

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,14 @@ SWIFT_REQUEST(TypeChecker, CheckDistributedFunctionRequest,
118118
SWIFT_REQUEST(TypeChecker, IsDistributedActorRequest, bool(NominalTypeDecl *),
119119
Cached, NoLocationInfo)
120120
SWIFT_REQUEST(TypeChecker, GetDistributedActorImplicitCodableRequest,
121-
NormalProtocolConformance *(NominalTypeDecl *, KnownProtocolKind),
122-
Cached, NoLocationInfo)
121+
NormalProtocolConformance *(NominalTypeDecl *, KnownProtocolKind),
122+
Cached, NoLocationInfo)
123123
SWIFT_REQUEST(TypeChecker, CanSynthesizeDistributedActorCodableConformanceRequest,
124-
bool (NominalTypeDecl *),
125-
Cached, NoLocationInfo)
124+
bool (NominalTypeDecl *),
125+
Cached, NoLocationInfo)
126+
SWIFT_REQUEST(TypeChecker, GetDistributedActorAsActorConformanceRequest,
127+
NormalProtocolConformance *(ProtocolDecl *),
128+
Cached, NoLocationInfo)
126129
SWIFT_REQUEST(TypeChecker, GetDistributedActorSystemRemoteCallFunctionRequest,
127130
AbstractFunctionDecl *(NominalTypeDecl *, bool),
128131
Cached, NoLocationInfo)

lib/AST/DistributedDecl.cpp

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
using namespace swift;
6262

6363
/******************************************************************************/
64-
/************* Implicit Distributed Actor Codable Conformance *****************/
64+
/******************* Distributed Actor Conformances ***************************/
6565
/******************************************************************************/
6666

6767
bool swift::canSynthesizeDistributedActorCodableConformance(NominalTypeDecl *actor) {
@@ -76,6 +76,68 @@ bool swift::canSynthesizeDistributedActorCodableConformance(NominalTypeDecl *act
7676
false);
7777
}
7878

79+
ExtensionDecl *
80+
swift::findDistributedActorAsActorExtension(
81+
ProtocolDecl *distributedActorProto, ModuleDecl *module) {
82+
ASTContext &C = distributedActorProto->getASTContext();
83+
auto name = C.getIdentifier("__actorUnownedExecutor");
84+
auto results = distributedActorProto->lookupDirect(
85+
name, SourceLoc(),
86+
NominalTypeDecl::LookupDirectFlags::IncludeAttrImplements);
87+
for (auto result : results) {
88+
if (auto var = dyn_cast<VarDecl>(result)) {
89+
return dyn_cast<ExtensionDecl>(var->getDeclContext());
90+
}
91+
}
92+
93+
return nullptr;
94+
}
95+
96+
bool swift::isDistributedActorAsLocalActorComputedProperty(VarDecl *var) {
97+
auto &C = var->getASTContext();
98+
return var->getName() == C.Id_asLocalActor &&
99+
var->getDeclContext()->getSelfProtocolDecl() &&
100+
var->getDeclContext()->getSelfProtocolDecl()->isSpecificProtocol(
101+
KnownProtocolKind::DistributedActor);
102+
}
103+
104+
VarDecl *
105+
swift::getDistributedActorAsLocalActorComputedProperty(ModuleDecl *module) {
106+
auto &C = module->getASTContext();
107+
auto DA = C.getDistributedActorDecl();
108+
auto extension = findDistributedActorAsActorExtension(DA, module);
109+
110+
if (!extension)
111+
return nullptr;
112+
113+
for (auto decl : extension->getMembers()) {
114+
if (auto var = dyn_cast<VarDecl>(decl)) {
115+
if (isDistributedActorAsLocalActorComputedProperty(var)) {
116+
return var;
117+
}
118+
}
119+
}
120+
121+
return nullptr;
122+
}
123+
124+
ProtocolConformanceRef
125+
swift::getDistributedActorAsActorConformanceRef(ASTContext &C) {
126+
auto distributedActorAsActorConformance =
127+
getDistributedActorAsActorConformance(C);
128+
129+
auto actorProto = C.getProtocol(KnownProtocolKind::Actor);
130+
return ProtocolConformanceRef(actorProto, distributedActorAsActorConformance);
131+
}
132+
NormalProtocolConformance *
133+
swift::getDistributedActorAsActorConformance(ASTContext &C) {
134+
auto distributedActorProtocol = C.getProtocol(KnownProtocolKind::DistributedActor);
135+
136+
return evaluateOrDefault(
137+
C.evaluator,
138+
GetDistributedActorAsActorConformanceRequest{distributedActorProtocol},
139+
nullptr);
140+
}
79141

80142
/******************************************************************************/
81143
/************** Distributed Actor System Associated Types *********************/

lib/AST/ProtocolConformance.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1142,9 +1142,40 @@ void NominalTypeDecl::prepareConformanceTable() const {
11421142
}
11431143
}
11441144

1145+
/// Handle special cased protocol-to-protocol conformances, such as e.g.
1146+
/// DistributedActor-to-Actor.
1147+
///
1148+
/// \returns true when the conformance lookup was handled successfully
1149+
static bool lookupSpecialProtocolToProtocolConformance(
1150+
const ProtocolDecl *thisProtocol, ProtocolDecl *toProtocol,
1151+
SmallVectorImpl<ProtocolConformance *> &conformances) {
1152+
auto &C = toProtocol->getASTContext();
1153+
1154+
// DistributedActor-to-Actor
1155+
if (thisProtocol->isSpecificProtocol(KnownProtocolKind::DistributedActor) &&
1156+
toProtocol->isSpecificProtocol(KnownProtocolKind::Actor)) {
1157+
if (auto conformance = getDistributedActorAsActorConformance(C)) {
1158+
conformances.push_back(conformance);
1159+
return true;
1160+
}
1161+
}
1162+
1163+
return false;
1164+
}
1165+
11451166
bool NominalTypeDecl::lookupConformance(
11461167
ProtocolDecl *protocol,
11471168
SmallVectorImpl<ProtocolConformance *> &conformances) const {
1169+
1170+
// In general, protocols cannot conform to other protocols, however there are
1171+
// exceptions, special handle those.
1172+
if (auto thisProtocol = dyn_cast<ProtocolDecl>(this)) {
1173+
if (lookupSpecialProtocolToProtocolConformance(thisProtocol, protocol,
1174+
conformances)) {
1175+
return true;
1176+
}
1177+
}
1178+
11481179
assert(!isa<ProtocolDecl>(this) &&
11491180
"Self-conformances are only found by the higher-level "
11501181
"ModuleDecl::lookupConformance() entry point");
@@ -1187,7 +1218,7 @@ void NominalTypeDecl::getImplicitProtocols(
11871218
}
11881219

11891220
void NominalTypeDecl::registerProtocolConformance(
1190-
NormalProtocolConformance *conformance, bool synthesized) {
1221+
NormalProtocolConformance *conformance, bool synthesized) {
11911222
prepareConformanceTable();
11921223
auto *dc = conformance->getDeclContext();
11931224
ConformanceTable->registerProtocolConformance(dc, conformance, synthesized);

lib/SILGen/SILGen.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
8383
/// Set of delayed conformances that have already been forced.
8484
llvm::DenseSet<NormalProtocolConformance *> forcedConformances;
8585

86-
/// The conformance for any DistributedActor to the Actor protocol,
87-
/// used only by the `distributedActorAsAnyActor` builtin.
88-
NormalProtocolConformance *distributedActorAsActorConformance = nullptr;
89-
9086
size_t anonymousSymbolCounter = 0;
9187

9288
std::optional<SILDeclRef> StringToNSStringFn;
@@ -601,15 +597,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
601597
/// mentioned by the given type.
602598
void useConformancesFromObjectiveCType(CanType type);
603599

604-
/// Retrieve a protocol conformance to the `Actor` protocol for a
605-
/// distributed actor type that is described via a substitution map for
606-
/// the generic signature `<T: DistributedActor>`.
607-
///
608-
/// The protocol conformance is a special one that is currently
609-
/// only used by the `distributedActorAsAnyActor` builtin.
610-
ProtocolConformanceRef
611-
getDistributedActorAsActorConformance(SubstitutionMap subs);
612-
613600
/// Make a note of a member reference expression, which allows us
614601
/// to ensure that the conformance above is emitted wherever it
615602
/// needs to be.

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/AST/ASTContext.h"
2424
#include "swift/AST/Builtins.h"
2525
#include "swift/AST/DiagnosticsSIL.h"
26+
#include "swift/AST/DistributedDecl.h"
2627
#include "swift/AST/FileUnit.h"
2728
#include "swift/AST/GenericEnvironment.h"
2829
#include "swift/AST/Module.h"
@@ -1994,16 +1995,9 @@ void SILGenModule::noteMemberRefExpr(MemberRefExpr *e) {
19941995
// distributed actors, make sure we have the conformance needed
19951996
// for a builtin.
19961997
ASTContext &ctx = var->getASTContext();
1997-
if (var->getName() == ctx.Id_asLocalActor &&
1998-
var->getDeclContext()->getSelfProtocolDecl() &&
1999-
var->getDeclContext()->getSelfProtocolDecl()
2000-
->isSpecificProtocol(KnownProtocolKind::DistributedActor)) {
2001-
auto conformance =
2002-
getDistributedActorAsActorConformance(
2003-
e->getMember().getSubstitutions());
2004-
useConformance(conformance);
1998+
if (isDistributedActorAsLocalActorComputedProperty(var)) {
1999+
useConformance(getDistributedActorAsActorConformanceRef(ctx));
20052000
}
2006-
20072001
}
20082002

20092003
static ManagedValue emitBuiltinDistributedActorAsAnyActor(

lib/SILGen/SILGenConcurrency.cpp

Lines changed: 18 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "Scope.h"
1717
#include "swift/AST/ASTContext.h"
1818
#include "swift/AST/Availability.h"
19+
#include "swift/AST/DistributedDecl.h"
1920
#include "swift/AST/ProtocolConformance.h"
2021
#include "swift/Basic/Range.h"
2122

@@ -661,75 +662,29 @@ SILValue SILGenFunction::emitGetCurrentExecutor(SILLocation loc) {
661662
return ExpectedExecutor;
662663
}
663664

664-
/// Find the extension on DistributedActor that defines __actorUnownedExecutor.
665-
static ExtensionDecl *findDistributedActorAsActorExtension(
666-
ProtocolDecl *distributedActorProto, ModuleDecl *module) {
667-
ASTContext &ctx = distributedActorProto->getASTContext();
668-
auto name = ctx.getIdentifier("__actorUnownedExecutor");
669-
auto results = distributedActorProto->lookupDirect(
670-
name, SourceLoc(),
671-
NominalTypeDecl::LookupDirectFlags::IncludeAttrImplements);
672-
for (auto result : results) {
673-
if (auto var = dyn_cast<VarDecl>(result)) {
674-
return dyn_cast<ExtensionDecl>(var->getDeclContext());
675-
}
676-
}
677-
678-
return nullptr;
679-
}
680-
681-
ProtocolConformanceRef
682-
SILGenModule::getDistributedActorAsActorConformance(SubstitutionMap subs) {
683-
ASTContext &ctx = M.getASTContext();
684-
auto actorProto = ctx.getProtocol(KnownProtocolKind::Actor);
685-
Type distributedActorType = subs.getReplacementTypes()[0];
686-
687-
if (!distributedActorAsActorConformance) {
688-
auto distributedActorProto = ctx.getProtocol(KnownProtocolKind::DistributedActor);
689-
if (!distributedActorProto)
690-
return ProtocolConformanceRef();
691-
692-
auto ext = findDistributedActorAsActorExtension(
693-
distributedActorProto, M.getSwiftModule());
694-
if (!ext)
695-
return ProtocolConformanceRef();
696-
697-
// Conformance of DistributedActor to Actor.
698-
auto genericParam = subs.getGenericSignature().getGenericParams()[0];
699-
distributedActorAsActorConformance = ctx.getNormalConformance(
700-
Type(genericParam), actorProto, SourceLoc(), ext,
701-
ProtocolConformanceState::Incomplete, /*isUnchecked=*/false,
702-
/*isPreconcurrency=*/false);
703-
}
704-
705-
return ProtocolConformanceRef(
706-
actorProto,
707-
ctx.getSpecializedConformance(distributedActorType,
708-
distributedActorAsActorConformance,
709-
subs));
710-
}
711-
712665
ManagedValue
713666
SILGenFunction::emitDistributedActorAsAnyActor(SILLocation loc,
714667
SubstitutionMap distributedActorSubs,
715668
ManagedValue actorValue) {
716-
ProtocolConformanceRef conformances[1] = {
717-
SGM.getDistributedActorAsActorConformance(distributedActorSubs)
718-
};
669+
auto &ctx = SGM.getASTContext();
670+
671+
auto distributedActorAsActorConformance =
672+
getDistributedActorAsActorConformance(ctx);
673+
auto actorProto = ctx.getProtocol(KnownProtocolKind::Actor);
674+
auto distributedActorType = distributedActorSubs.getReplacementTypes()[0];
675+
auto ref = ProtocolConformanceRef(
676+
actorProto, ctx.getSpecializedConformance(
677+
distributedActorType, distributedActorAsActorConformance,
678+
distributedActorSubs));
679+
ProtocolConformanceRef conformances[1] = {ref};
719680

720681
// Erase the distributed actor instance into an `any Actor` existential with
721682
// the special conformance.
722-
auto &ctx = SGM.getASTContext();
723-
CanType distributedActorType =
724-
distributedActorSubs.getReplacementTypes()[0]->getCanonicalType();
725-
auto &distributedActorTL = getTypeLowering(distributedActorType);
726-
auto actorProto = ctx.getProtocol(KnownProtocolKind::Actor);
683+
CanType distributedActorCanType = distributedActorType->getCanonicalType();
684+
auto &distributedActorTL = getTypeLowering(distributedActorCanType);
727685
auto &anyActorTL = getTypeLowering(actorProto->getDeclaredExistentialType());
728-
return emitExistentialErasure(loc, distributedActorType,
729-
distributedActorTL, anyActorTL,
730-
ctx.AllocateCopy(conformances),
731-
SGFContext(),
732-
[actorValue](SGFContext) {
733-
return actorValue;
734-
});
686+
return emitExistentialErasure(
687+
loc, distributedActorCanType, distributedActorTL, anyActorTL,
688+
ctx.AllocateCopy(conformances), SGFContext(),
689+
[actorValue](SGFContext) { return actorValue; });
735690
}

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
#include "CodeSynthesis.h"
1616
#include "DerivedConformances.h"
17-
#include "TypeCheckType.h"
1817
#include "TypeChecker.h"
1918
#include "swift/AST/ASTMangler.h"
2019
#include "swift/AST/ASTPrinter.h"
@@ -1066,3 +1065,30 @@ bool CanSynthesizeDistributedActorCodableConformanceRequest::evaluate(
10661065
TypeChecker::conformsToKnownProtocol(
10671066
idTy, KnownProtocolKind::Encodable, actor->getParentModule());
10681067
}
1068+
1069+
NormalProtocolConformance *
1070+
GetDistributedActorAsActorConformanceRequest::evaluate(
1071+
Evaluator &evaluator, ProtocolDecl *distributedActorProto) const {
1072+
auto &ctx = distributedActorProto->getASTContext();
1073+
auto swiftModule = ctx.getStdlibModule();
1074+
1075+
auto actorProto = ctx.getProtocol(KnownProtocolKind::Actor);
1076+
1077+
auto ext = findDistributedActorAsActorExtension(
1078+
distributedActorProto, swiftModule);
1079+
if (!ext)
1080+
return nullptr;
1081+
1082+
auto genericParam = GenericTypeParamType::get(/*isParameterPack=*/false,
1083+
/*depth=*/0, /*index=*/0, ctx);
1084+
1085+
auto distributedActorAsActorConformance = ctx.getNormalConformance(
1086+
Type(genericParam), actorProto, SourceLoc(), ext,
1087+
ProtocolConformanceState::Incomplete, /*isUnchecked=*/false,
1088+
/*isPreconcurrency=*/false);
1089+
// NOTE: Normally we "register" a conformance, but here we don't
1090+
// because we cannot (currently) register them in a protocol,
1091+
// since they do not have conformance tables.
1092+
1093+
return distributedActorAsActorConformance;
1094+
}

0 commit comments

Comments
 (0)