Skip to content

Commit cbfa4b7

Browse files
authored
Merge pull request swiftlang#59722 from ktoso/wip-fix-witnesses-distributed
[3/3][Distributed] Remove dist requirement explicit async throws limitation
2 parents 149e2d4 + 728c007 commit cbfa4b7

23 files changed

+510
-220
lines changed

include/swift/AST/ActorIsolation.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ ActorIsolation getActorIsolation(ValueDecl *value);
193193
/// Determine how the given declaration context is isolated.
194194
ActorIsolation getActorIsolationOfContext(DeclContext *dc);
195195

196+
/// Check if both the value, and context are isolated to the same actor.
197+
bool isSameActorIsolated(ValueDecl *value, DeclContext *dc);
198+
196199
/// Determines whether this function's body uses flow-sensitive isolation.
197200
bool usesFlowSensitiveIsolation(AbstractFunctionDecl const *fn);
198201

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4794,9 +4794,6 @@ ERROR(distributed_actor_func_static,none,
47944794
ERROR(distributed_actor_func_not_in_distributed_actor,none,
47954795
"'distributed' method can only be declared within 'distributed actor'",
47964796
())
4797-
ERROR(distributed_method_requirement_must_be_async_throws,none, // FIXME(distributed): this is an implementation limitation we should lift
4798-
"'distributed' protocol requirement %0 must currently be declared explicitly 'async throws'",
4799-
(DeclName))
48004797
ERROR(distributed_actor_user_defined_special_property,none,
48014798
"property %0 cannot be defined explicitly, as it conflicts with "
48024799
"distributed actor synthesized stored property",

include/swift/AST/DistributedDecl.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
//
1616
//===----------------------------------------------------------------------===//
1717

18-
#ifndef SWIFT_DECL_TYPECHECKDISTRIBUTED_H
19-
#define SWIFT_DECL_TYPECHECKDISTRIBUTED_H
18+
#ifndef SWIFT_DECL_DISTRIBUTEDDECL_H
19+
#define SWIFT_DECL_DISTRIBUTEDDECL_H
2020

2121
#include "swift/AST/ConcreteDeclRef.h"
2222
#include "swift/AST/DiagnosticEngine.h"
@@ -129,4 +129,6 @@ extractDistributedSerializationRequirements(
129129

130130
}
131131

132-
#endif /* SWIFT_DECL_TYPECHECKDISTRIBUTED_H */
132+
// ==== ------------------------------------------------------------------------
133+
134+
#endif /* SWIFT_DECL_DISTRIBUTEDDECL_H */

include/swift/SIL/SILWitnessVisitor.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include "swift/AST/ASTVisitor.h"
2323
#include "swift/AST/Decl.h"
24+
#include "swift/AST/DistributedDecl.h"
2425
#include "swift/AST/ProtocolAssociations.h"
2526
#include "swift/AST/Types.h"
2627
#include "swift/SIL/TypeLowering.h"
@@ -145,6 +146,7 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {
145146
if (SILDeclRef::requiresNewWitnessTableEntry(func)) {
146147
asDerived().addMethod(SILDeclRef(func, SILDeclRef::Kind::Func));
147148
addAutoDiffDerivativeMethodsIfRequired(func, SILDeclRef::Kind::Func);
149+
addDistributedWitnessMethodsIfRequired(func, SILDeclRef::Kind::Func);
148150
}
149151
}
150152

@@ -192,6 +194,16 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {
192194
AFD->getASTContext())));
193195
}
194196
}
197+
198+
void addDistributedWitnessMethodsIfRequired(AbstractFunctionDecl *AFD,
199+
SILDeclRef::Kind kind) {
200+
if (!AFD->isDistributed())
201+
return;
202+
203+
// Add another which will be witnessed by the 'distributed thunk'
204+
SILDeclRef declRef(AFD, kind);
205+
asDerived().addMethod(declRef.asDistributed());
206+
}
195207
};
196208

197209
} // end namespace swift

lib/AST/ASTMangler.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ std::string ASTMangler::mangleWitnessThunk(
243243
appendOperator("TW");
244244
}
245245
}
246+
246247
return finalize();
247248
}
248249

lib/AST/Decl.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9254,6 +9254,13 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
92549254
return ActorIsolation::forUnspecified();
92559255
}
92569256

9257+
bool swift::isSameActorIsolated(ValueDecl *value, DeclContext *dc) {
9258+
auto valueIsolation = getActorIsolation(value);
9259+
auto dcIsolation = getActorIsolationOfContext(dc);
9260+
return valueIsolation.isActorIsolated() && dcIsolation.isActorIsolated() &&
9261+
valueIsolation.getActor() == dcIsolation.getActor();
9262+
}
9263+
92579264
ClangNode Decl::getClangNodeImpl() const {
92589265
assert(Bits.Decl.FromClang);
92599266
void * const *ptr = nullptr;

lib/AST/TypeCheckRequests.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1559,7 +1559,11 @@ void swift::simple_display(
15591559
llvm::raw_ostream &out, const ActorIsolation &state) {
15601560
switch (state) {
15611561
case ActorIsolation::ActorInstance:
1562-
out << "actor-isolated to instance of " << state.getActor()->getName();
1562+
out << "actor-isolated to instance of ";
1563+
if (state.isDistributedActor()) {
1564+
out << "distributed ";
1565+
}
1566+
out << "actor " << state.getActor()->getName();
15631567
break;
15641568

15651569
case ActorIsolation::Independent:

lib/Parse/ParseDecl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7172,7 +7172,7 @@ Parser::parseDeclVar(ParseDeclOptions Flags,
71727172
///
71737173
/// \verbatim
71747174
/// decl-func:
7175-
/// attribute-list? ('static' | 'class')? 'mutating'? 'func'
7175+
/// attribute-list? ('static' | 'class' | 'distributed')? 'mutating'? 'func'
71767176
/// any-identifier generic-params? func-signature where-clause?
71777177
/// stmt-brace?
71787178
/// \endverbatim
@@ -7256,7 +7256,7 @@ ParserResult<FuncDecl> Parser::parseDeclFunc(SourceLoc StaticLoc,
72567256
}
72577257

72587258
DebuggerContextChange DCC(*this, SimpleName, DeclKind::Func);
7259-
7259+
72607260
// Parse the generic-params, if present.
72617261
GenericParamList *GenericParams;
72627262
auto GenericParamResult = maybeParseGenericParams();

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2112,7 +2112,7 @@ static CanSILFunctionType getSILFunctionType(
21122112
.withConcurrent(isSendable)
21132113
.withAsync(isAsync)
21142114
.build();
2115-
2115+
21162116
return SILFunctionType::get(genericSig, silExtInfo, coroutineKind,
21172117
calleeConvention, inputs, yields,
21182118
results, errorResult,

lib/SILGen/SILGenApply.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "swift/AST/ForeignAsyncConvention.h"
3030
#include "swift/AST/ForeignErrorConvention.h"
3131
#include "swift/AST/GenericEnvironment.h"
32+
#include "swift/AST/DistributedDecl.h"
3233
#include "swift/AST/GenericSignature.h"
3334
#include "swift/AST/Module.h"
3435
#include "swift/AST/ModuleLoader.h"
@@ -627,6 +628,16 @@ class Callee {
627628
return fn;
628629
}
629630
case Kind::WitnessMethod: {
631+
if (auto func = constant->getFuncDecl()) {
632+
if (func->isDistributed() && isa<ProtocolDecl>(func->getDeclContext())) {
633+
// If we're calling cross-actor, we must always use a distributed thunk
634+
if (!isSameActorIsolated(func, SGF.FunctionDC)) {
635+
// We must adjust the constant to use a distributed thunk.
636+
constant = constant->asDistributed();
637+
}
638+
}
639+
}
640+
630641
auto constantInfo =
631642
SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant);
632643

@@ -700,6 +711,16 @@ class Callee {
700711
return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType());
701712
}
702713
case Kind::WitnessMethod: {
714+
if (auto func = constant->getFuncDecl()) {
715+
if (func->isDistributed() && isa<ProtocolDecl>(func->getDeclContext())) {
716+
// If we're calling cross-actor, we must always use a distributed thunk
717+
if (!isSameActorIsolated(func, SGF.FunctionDC)) {
718+
/// We must adjust the constant to use a distributed thunk.
719+
constant = constant->asDistributed();
720+
}
721+
}
722+
}
723+
703724
auto constantInfo =
704725
SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant);
705726
return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType());

lib/SILGen/SILGenPoly.cpp

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4352,7 +4352,7 @@ getWitnessFunctionRef(SILGenFunction &SGF,
43524352
SILLocation loc) {
43534353
switch (witnessKind) {
43544354
case WitnessDispatchKind::Static:
4355-
if (auto *derivativeId = witness.getDerivativeFunctionIdentifier()) {
4355+
if (auto *derivativeId = witness.getDerivativeFunctionIdentifier()) { // TODO Maybe we need check here too
43564356
auto originalFn =
43574357
SGF.emitGlobalFunctionRef(loc, witness.asAutoDiffOriginalFunction());
43584358
auto *loweredParamIndices = autodiff::getLoweredParameterIndices(
@@ -4439,23 +4439,7 @@ void SILGenFunction::emitProtocolWitness(
44394439
SmallVector<ManagedValue, 8> origParams;
44404440
collectThunkParams(loc, origParams);
44414441

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

lib/SILGen/SILGenType.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ template<typename T> class SILGenWitnessTable : public SILWitnessVisitor<T> {
483483
witness.getDerivativeGenericSignature(), witnessRef.getASTContext());
484484
witnessRef = witnessRef.asAutoDiffDerivativeFunction(witnessDerivativeId);
485485
}
486+
486487
return witnessRef;
487488
}
488489
};
@@ -694,6 +695,29 @@ SILFunction *SILGenModule::emitProtocolWitness(
694695
auto requirementInfo =
695696
Types.getConstantInfo(TypeExpansionContext::minimal(), requirement);
696697

698+
auto shouldUseDistributedThunkWitness =
699+
// always use a distributed thunk for distributed requirements:
700+
requirement.isDistributedThunk() ||
701+
// for non-distributed requirements, which are however async/throws,
702+
// and have a proper witness (passed typechecking), we can still invoke
703+
// them on the distributed actor; but must do so through the distributed
704+
// thunk as the call "through an existential" we never statically know
705+
// if the actor is local or not.
706+
(requirement.hasDecl() && requirement.getFuncDecl() && requirement.hasAsync() &&
707+
!requirement.getFuncDecl()->isDistributed() &&
708+
witnessRef.hasDecl() && witnessRef.getFuncDecl() &&
709+
witnessRef.getFuncDecl()->isDistributed());
710+
// We only need to use thunks when we go cross-actor:
711+
shouldUseDistributedThunkWitness = shouldUseDistributedThunkWitness &&
712+
getActorIsolation(requirement.getDecl()) !=
713+
getActorIsolation(witness.getDecl());
714+
if (shouldUseDistributedThunkWitness) {
715+
auto thunkDeclRef = SILDeclRef(
716+
witnessRef.getFuncDecl()->getDistributedThunk(),
717+
SILDeclRef::Kind::Func);
718+
witnessRef = thunkDeclRef.asDistributed();
719+
}
720+
697721
// Work out the lowered function type of the SIL witness thunk.
698722
auto reqtOrigTy = cast<GenericFunctionType>(requirementInfo.LoweredType);
699723

@@ -781,6 +805,10 @@ SILFunction *SILGenModule::emitProtocolWitness(
781805
derivativeId->getParameterIndices()->getString();
782806
}
783807

808+
if (requirement.isDistributedThunk()) {
809+
nameBuffer = nameBuffer + "TE";
810+
}
811+
784812
// If the thunked-to function is set to be always inlined, do the
785813
// same with the witness, on the theory that the user wants all
786814
// calls removed if possible, e.g. when we're able to devirtualize

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ static FuncDecl *createDistributedThunkFunction(FuncDecl *func) {
672672

673673
// NOTE: So we don't need a thunk in the protocol, we should call the underlying
674674
// thing instead, which MUST have a thunk, since it must be a distributed func as well...
675-
if (dyn_cast<ProtocolDecl>(DC)) {
675+
if (isa<ProtocolDecl>(DC)) {
676676
return nullptr;
677677
}
678678

lib/Sema/TypeCheckAttr.cpp

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5910,24 +5910,6 @@ void AttributeChecker::visitDistributedActorAttr(DistributedActorAttr *attr) {
59105910
}
59115911
return;
59125912
}
5913-
5914-
// Diagnose for the limitation that we currently have to require distributed
5915-
// actor constrained protocols to declare the distributed requirements as
5916-
// 'async throws'
5917-
// FIXME: rdar://95949498 allow requirements to not declare explicit async/throws in protocols; those effects are implicit in any case
5918-
if (isa<ProtocolDecl>(dc)) {
5919-
if (!funcDecl->hasAsync() || !funcDecl->hasThrows()) {
5920-
auto diag = funcDecl->diagnose(diag::distributed_method_requirement_must_be_async_throws,
5921-
funcDecl->getName());
5922-
if (!funcDecl->hasAsync()) {
5923-
diag.fixItInsertAfter(funcDecl->getThrowsLoc(), " async");
5924-
}
5925-
if (!funcDecl->hasThrows()) {
5926-
diag.fixItInsertAfter(funcDecl->getThrowsLoc(), " throws");
5927-
}
5928-
return;
5929-
}
5930-
}
59315913
}
59325914
}
59335915

0 commit comments

Comments
 (0)