Skip to content

Commit 3f7d1b1

Browse files
authored
Merge pull request #59736 from ktoso/pick-dist-protocols-fixes
🍒[5.7][Distributed] Fixes to distributed funcs and protocols
2 parents 2d21d6d + 40f3295 commit 3f7d1b1

18 files changed

+412
-35
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4817,6 +4817,9 @@ ERROR(distributed_actor_func_static,none,
48174817
ERROR(distributed_actor_func_not_in_distributed_actor,none,
48184818
"'distributed' method can only be declared within 'distributed actor'",
48194819
())
4820+
ERROR(distributed_method_requirement_must_be_async_throws,none, // FIXME(distributed): this is an implementation limitation we should lift
4821+
"'distributed' protocol requirement %0 must currently be declared explicitly 'async throws'",
4822+
(DeclName))
48204823
ERROR(distributed_actor_user_defined_special_property,none,
48214824
"property %0 cannot be defined explicitly, as it conflicts with "
48224825
"distributed actor synthesized stored property",

include/swift/AST/DistributedDecl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ Type getDistributedActorSystemType(NominalTypeDecl *actor);
5050
/// Determine the `ID` type for the given actor.
5151
Type getDistributedActorIDType(NominalTypeDecl *actor);
5252

53+
/// Similar to `getDistributedSerializationRequirementType`, however, from the
54+
/// perspective of a concrete function. This way we're able to get the
55+
/// serialization requirement for specific members, also in protocols.
56+
Type getConcreteReplacementForMemberSerializationRequirement(ValueDecl *member);
57+
5358
/// Get specific 'SerializationRequirement' as defined in 'nominal'
5459
/// type, which must conform to the passed 'protocol' which is expected
5560
/// to require the 'SerializationRequirement'.

include/swift/SIL/SILDeclRef.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,8 +414,7 @@ struct SILDeclRef {
414414
defaultArgIndex,
415415
pointer.get<AutoDiffDerivativeFunctionIdentifier *>());
416416
}
417-
/// Returns the distributed entry point corresponding to the same
418-
/// decl.
417+
/// Returns the distributed entry point corresponding to the same decl.
419418
SILDeclRef asDistributed(bool distributed = true) const {
420419
return SILDeclRef(loc.getOpaqueValue(), kind,
421420
/*foreign=*/false,

lib/AST/DistributedDecl.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,37 @@ Type swift::getConcreteReplacementForProtocolActorSystemType(ValueDecl *member)
136136
llvm_unreachable("Unable to fetch ActorSystem type!");
137137
}
138138

139+
Type swift::getConcreteReplacementForMemberSerializationRequirement(
140+
ValueDecl *member) {
141+
auto &C = member->getASTContext();
142+
auto *DC = member->getDeclContext();
143+
auto DA = C.getDistributedActorDecl();
144+
145+
// === When declared inside an actor, we can get the type directly
146+
if (auto classDecl = DC->getSelfClassDecl()) {
147+
return getDistributedSerializationRequirementType(classDecl, C.getDistributedActorDecl());
148+
}
149+
150+
/// === Maybe the value is declared in a protocol?
151+
if (auto protocol = DC->getSelfProtocolDecl()) {
152+
GenericSignature signature;
153+
if (auto *genericContext = member->getAsGenericContext()) {
154+
signature = genericContext->getGenericSignature();
155+
} else {
156+
signature = DC->getGenericSignatureOfContext();
157+
}
158+
159+
auto SerReqAssocType = DA->getAssociatedType(C.Id_SerializationRequirement)
160+
->getDeclaredInterfaceType();
161+
162+
// Note that this may be null, e.g. if we're a distributed func inside
163+
// a protocol that did not declare a specific actor system requirement.
164+
return signature->getConcreteType(SerReqAssocType);
165+
}
166+
167+
llvm_unreachable("Unable to fetch ActorSystem type!");
168+
}
169+
139170
Type swift::getDistributedActorSystemType(NominalTypeDecl *actor) {
140171
assert(!dyn_cast<ProtocolDecl>(actor) &&
141172
"Use getConcreteReplacementForProtocolActorSystemType instead to get"

lib/SILGen/SILGenPoly.cpp

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4435,15 +4435,22 @@ void SILGenFunction::emitProtocolWitness(
44354435
SmallVector<ManagedValue, 8> origParams;
44364436
collectThunkParams(loc, origParams);
44374437

4438-
// If the witness is isolated to a distributed actor, but the requirement is
4439-
// not, go through the distributed thunk.
44404438
if (witness.hasDecl() &&
4441-
getActorIsolation(witness.getDecl()).isDistributedActor() &&
4442-
requirement.hasDecl() &&
4443-
!getActorIsolation(requirement.getDecl()).isDistributedActor()) {
4444-
witness = SILDeclRef(
4445-
cast<AbstractFunctionDecl>(witness.getDecl())->getDistributedThunk())
4446-
.asDistributed();
4439+
getActorIsolation(witness.getDecl()).isDistributedActor()) {
4440+
// We witness protocol requirements using the distributed thunk, when:
4441+
// - the witness is isolated to a distributed actor, but the requirement is not
4442+
// - the requirement is a distributed func, and therefore can only be witnessed
4443+
// by a distributed func; we handle this by witnessing the requirement with the thunk
4444+
// FIXME(distributed): this limits us to only allow distributed explicitly throwing async requirements... we need to fix this somehow.
4445+
if (requirement.hasDecl()) {
4446+
if ((!getActorIsolation(requirement.getDecl()).isDistributedActor()) ||
4447+
(isa<FuncDecl>(requirement.getDecl()) &&
4448+
requirement.getFuncDecl()->isDistributed())) {
4449+
auto thunk = cast<AbstractFunctionDecl>(witness.getDecl())
4450+
->getDistributedThunk();
4451+
witness = SILDeclRef(thunk).asDistributed();
4452+
}
4453+
}
44474454
} else if (enterIsolation) {
44484455
// If we are supposed to enter the actor, do so now by hopping to the
44494456
// actor.

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -613,8 +613,13 @@ static FuncDecl *createDistributedThunkFunction(FuncDecl *func) {
613613
auto &C = func->getASTContext();
614614
auto DC = func->getDeclContext();
615615

616-
auto systemTy = getConcreteReplacementForProtocolActorSystemType(func);
617-
assert(systemTy &&
616+
// NOTE: So we don't need a thunk in the protocol, we should call the underlying
617+
// thing instead, which MUST have a thunk, since it must be a distributed func as well...
618+
if (dyn_cast<ProtocolDecl>(DC)) {
619+
return nullptr;
620+
}
621+
622+
assert(getConcreteReplacementForProtocolActorSystemType(func) &&
618623
"Thunk synthesis must have concrete actor system type available");
619624

620625
DeclName thunkName = func->getName();
@@ -753,7 +758,6 @@ FuncDecl *GetDistributedThunkRequest::evaluate(
753758
return nullptr;
754759

755760
auto &C = distributedTarget->getASTContext();
756-
auto DC = distributedTarget->getDeclContext();
757761

758762
if (!getConcreteReplacementForProtocolActorSystemType(distributedTarget)) {
759763
// Don't synthesize thunks, unless there is a *concrete* ActorSystem.
@@ -777,9 +781,6 @@ FuncDecl *GetDistributedThunkRequest::evaluate(
777781
if (!C.getLoadedModule(C.Id_Distributed))
778782
return nullptr;
779783

780-
auto nominal = DC->getSelfNominalTypeDecl(); // NOTE: Always from DC
781-
assert(nominal);
782-
783784
// --- Prepare the "distributed thunk" which does the "maybe remote" dance:
784785
return createDistributedThunkFunction(func);
785786
}

lib/Sema/TypeCheckAttr.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5793,6 +5793,24 @@ void AttributeChecker::visitDistributedActorAttr(DistributedActorAttr *attr) {
57935793
}
57945794
return;
57955795
}
5796+
5797+
// Diagnose for the limitation that we currently have to require distributed
5798+
// actor constrained protocols to declare the distributed requirements as
5799+
// 'async throws'
5800+
// FIXME: rdar://95949498 allow requirements to not declare explicit async/throws in protocols; those effects are implicit in any case
5801+
if (isa<ProtocolDecl>(dc)) {
5802+
if (!funcDecl->hasAsync() || !funcDecl->hasThrows()) {
5803+
auto diag = funcDecl->diagnose(diag::distributed_method_requirement_must_be_async_throws,
5804+
funcDecl->getName());
5805+
if (!funcDecl->hasAsync()) {
5806+
diag.fixItInsertAfter(funcDecl->getThrowsLoc(), " async");
5807+
}
5808+
if (!funcDecl->hasThrows()) {
5809+
diag.fixItInsertAfter(funcDecl->getThrowsLoc(), " throws");
5810+
}
5811+
return;
5812+
}
5813+
}
57965814
}
57975815
}
57985816

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2880,6 +2880,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
28802880
}
28812881

28822882
TypeChecker::checkDeclAttributes(FD);
2883+
TypeChecker::checkDistributedFunc(FD);
28832884

28842885
if (!checkOverrides(FD)) {
28852886
// If a method has an 'override' keyword but does not

lib/Sema/TypeCheckDistributed.cpp

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -502,9 +502,25 @@ bool CheckDistributedFunctionRequest::evaluate(
502502
serializationRequirements = getDistributedSerializationRequirementProtocols(
503503
getDistributedActorSystemType(actor)->getAnyNominal(),
504504
C.getProtocol(KnownProtocolKind::DistributedActorSystem));
505+
} else if (isa<ProtocolDecl>(DC)) {
506+
if (auto seqReqTy =
507+
getConcreteReplacementForMemberSerializationRequirement(func)) {
508+
auto seqReqTyDes = seqReqTy->castTo<ExistentialType>()->getConstraintType()->getDesugaredType();
509+
for (auto req : flattenDistributedSerializationTypeToRequiredProtocols(seqReqTyDes)) {
510+
serializationRequirements.insert(req);
511+
}
512+
}
513+
514+
// The distributed actor constrained protocol has no serialization requirements
515+
// or actor system defined, so these will only be enforced, by implementations
516+
// of DAs conforming to it, skip checks here.
517+
if (serializationRequirements.empty()) {
518+
return false;
519+
}
505520
} else {
506-
llvm_unreachable("Cannot handle types other than extensions and actor "
507-
"declarations in distributed function checking.");
521+
llvm_unreachable("Distributed function detected in type other than extension, "
522+
"distributed actor, or protocol! This should not be possible "
523+
", please file a bug.");
508524
}
509525

510526
// If the requirement is exactly `Codable` we diagnose it ia bit nicer.
@@ -652,12 +668,23 @@ void TypeChecker::checkDistributedActor(SourceFile *SF, NominalTypeDecl *nominal
652668
// If applicable, this will create the default 'init(transport:)' initializer
653669
(void)nominal->getDefaultInitializer();
654670

671+
655672
for (auto member : nominal->getMembers()) {
656673
// --- Ensure all thunks
657674
if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
658675
if (!func->isDistributed())
659676
continue;
660677

678+
if (!isa<ProtocolDecl>(nominal)) {
679+
auto systemTy = getConcreteReplacementForProtocolActorSystemType(func);
680+
if (!systemTy || systemTy->hasError()) {
681+
nominal->diagnose(
682+
diag::distributed_actor_conformance_missing_system_type,
683+
nominal->getName());
684+
return;
685+
}
686+
}
687+
661688
if (auto thunk = func->getDistributedThunk()) {
662689
SF->DelayedFunctions.push_back(thunk);
663690
}
@@ -675,6 +702,13 @@ void TypeChecker::checkDistributedActor(SourceFile *SF, NominalTypeDecl *nominal
675702
(void)nominal->getDistributedActorIDProperty();
676703
}
677704

705+
void TypeChecker::checkDistributedFunc(FuncDecl *func) {
706+
if (!func->isDistributed())
707+
return;
708+
709+
swift::checkDistributedFunction(func);
710+
}
711+
678712
llvm::SmallPtrSet<ProtocolDecl *, 2>
679713
swift::getDistributedSerializationRequirementProtocols(
680714
NominalTypeDecl *nominal, ProtocolDecl *protocol) {

lib/Sema/TypeChecker.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,9 @@ diagnosePotentialOpaqueTypeUnavailability(SourceRange ReferenceRange,
11041104
/// Type check a 'distributed actor' declaration.
11051105
void checkDistributedActor(SourceFile *SF, NominalTypeDecl *decl);
11061106

1107+
/// Type check a single 'distributed func' declaration.
1108+
void checkDistributedFunc(FuncDecl *func);
1109+
11071110
void checkConcurrencyAvailability(SourceRange ReferenceRange,
11081111
const DeclContext *ReferenceDC);
11091112

0 commit comments

Comments
 (0)