Skip to content

Commit 3b4ace1

Browse files
authored
Merge pull request #40549 from DougGregor/isolation-fixes-5.6
2 parents e13580f + a0f506a commit 3b4ace1

20 files changed

+399
-146
lines changed

include/swift/AST/CaptureInfo.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ namespace swift {
3636
class ValueDecl;
3737
class FuncDecl;
3838
class OpaqueValueExpr;
39+
class VarDecl;
3940

4041
/// CapturedValue includes both the declaration being captured, along with flags
4142
/// that indicate how it is captured.
@@ -219,6 +220,11 @@ class CaptureInfo {
219220
return StorageAndFlags.getPointer()->getOpaqueValue();
220221
}
221222

223+
/// Retrieve the variable corresponding to an isolated parameter that has
224+
/// been captured, if there is one. This might be a capture variable
225+
/// that was initialized with an isolated parameter.
226+
VarDecl *getIsolatedParamCapture() const;
227+
222228
SWIFT_DEBUG_DUMP;
223229
void print(raw_ostream &OS) const;
224230
};

include/swift/AST/Decl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5162,6 +5162,9 @@ class VarDecl : public AbstractStorageDecl {
51625162
Bits.VarDecl.IsSelfParamCapture = IsSelfParamCapture;
51635163
}
51645164

5165+
/// Check whether this capture of the self param is actor-isolated.
5166+
bool isSelfParamCaptureIsolated() const;
5167+
51655168
/// Determines if this var has an initializer expression that should be
51665169
/// exposed to clients.
51675170
///

include/swift/AST/Expr.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3623,6 +3623,9 @@ class AbstractClosureExpr : public DeclContext, public Expr {
36233623
/// \brief Return whether this closure is async when fully applied.
36243624
bool isBodyAsync() const;
36253625

3626+
/// Whether this closure is Sendable.
3627+
bool isSendable() const;
3628+
36263629
/// Whether this closure consists of a single expression.
36273630
bool hasSingleExpressionBody() const;
36283631

include/swift/AST/TypeCheckRequests.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3173,6 +3173,23 @@ class RenamedDeclRequest
31733173
bool isCached() const { return true; }
31743174
};
31753175

3176+
class ClosureEffectsRequest
3177+
: public SimpleRequest<ClosureEffectsRequest,
3178+
FunctionType::ExtInfo(ClosureExpr *),
3179+
RequestFlags::Cached> {
3180+
public:
3181+
using SimpleRequest::SimpleRequest;
3182+
3183+
private:
3184+
friend SimpleRequest;
3185+
3186+
FunctionType::ExtInfo evaluate(
3187+
Evaluator &evaluator, ClosureExpr *closure) const;
3188+
3189+
public:
3190+
bool isCached() const { return true; }
3191+
};
3192+
31763193
void simple_display(llvm::raw_ostream &out, Type value);
31773194
void simple_display(llvm::raw_ostream &out, const TypeRepr *TyR);
31783195
void simple_display(llvm::raw_ostream &out, ImplicitMemberAction action);

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,3 +361,6 @@ SWIFT_REQUEST(TypeChecker, GetImplicitSendableRequest,
361361
SWIFT_REQUEST(TypeChecker, RenamedDeclRequest,
362362
ValueDecl *(const ValueDecl *),
363363
Cached, NoLocationInfo)
364+
SWIFT_REQUEST(TypeChecker, ClosureEffectsRequest,
365+
FunctionType::ExtInfo(ClosureExpr *),
366+
Cached, NoLocationInfo)

include/swift/Sema/ConstraintSystem.h

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2217,6 +2217,13 @@ enum class SolutionApplicationToFunctionResult {
22172217
Delay,
22182218
};
22192219

2220+
/// Retrieve the closure type from the constraint system.
2221+
struct GetClosureType {
2222+
ConstraintSystem &cs;
2223+
2224+
Type operator()(const AbstractClosureExpr *expr) const;
2225+
};
2226+
22202227
/// Describes a system of constraints on type variables, the
22212228
/// solution of which assigns concrete types to each of the type variables.
22222229
/// Constraint systems are typically generated given an (untyped) expression.
@@ -2443,9 +2450,6 @@ class ConstraintSystem {
24432450
llvm::MapVector<AnyFunctionRef, AppliedBuilderTransform>
24442451
resultBuilderTransformed;
24452452

2446-
/// Cache of the effects any closures visited.
2447-
llvm::SmallDenseMap<ClosureExpr *, FunctionType::ExtInfo, 4> closureEffectsCache;
2448-
24492453
/// A mapping from the constraint locators for references to various
24502454
/// names (e.g., member references, normal name references, possible
24512455
/// constructions) to the argument lists for the call to that locator.
@@ -3099,9 +3103,16 @@ class ConstraintSystem {
30993103
}
31003104

31013105
FunctionType *getClosureType(const ClosureExpr *closure) const {
3106+
auto result = getClosureTypeIfAvailable(closure);
3107+
assert(result);
3108+
return result;
3109+
}
3110+
3111+
FunctionType *getClosureTypeIfAvailable(const ClosureExpr *closure) const {
31023112
auto result = ClosureTypes.find(closure);
3103-
assert(result != ClosureTypes.end());
3104-
return result->second;
3113+
if (result != ClosureTypes.end())
3114+
return result->second;
3115+
return nullptr;
31053116
}
31063117

31073118
TypeBase* getFavoredType(Expr *E) {
@@ -4119,6 +4130,12 @@ class ConstraintSystem {
41194130
ConstraintLocatorBuilder locator,
41204131
const OpenedTypeMap &replacements);
41214132

4133+
/// Wrapper over swift::adjustFunctionTypeForConcurrency that passes along
4134+
/// the appropriate closure-type extraction function.
4135+
AnyFunctionType *adjustFunctionTypeForConcurrency(
4136+
AnyFunctionType *fnType, ValueDecl *decl, DeclContext *dc,
4137+
unsigned numApplies, bool isMainDispatchQueue);
4138+
41224139
/// Retrieve the type of a reference to the given value declaration.
41234140
///
41244141
/// For references to polymorphic function types, this routine "opens up"
@@ -4167,10 +4184,15 @@ class ConstraintSystem {
41674184
///
41684185
/// \param getType Optional callback to extract a type for given declaration.
41694186
static Type
4170-
getUnopenedTypeOfReference(VarDecl *value, Type baseType, DeclContext *UseDC,
4171-
llvm::function_ref<Type(VarDecl *)> getType,
4172-
ConstraintLocator *memberLocator = nullptr,
4173-
bool wantInterfaceType = false);
4187+
getUnopenedTypeOfReference(
4188+
VarDecl *value, Type baseType, DeclContext *UseDC,
4189+
llvm::function_ref<Type(VarDecl *)> getType,
4190+
ConstraintLocator *memberLocator = nullptr,
4191+
bool wantInterfaceType = false,
4192+
llvm::function_ref<Type(const AbstractClosureExpr *)> getClosureType =
4193+
[](const AbstractClosureExpr *) {
4194+
return Type();
4195+
});
41744196

41754197
/// Retrieve the type of a reference to the given value declaration,
41764198
/// as a member with a base of the given type.

lib/AST/CaptureInfo.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,34 @@ getLocalCaptures(SmallVectorImpl<CapturedValue> &Result) const {
7878
}
7979
}
8080

81+
VarDecl *CaptureInfo::getIsolatedParamCapture() const {
82+
if (!hasLocalCaptures())
83+
return nullptr;
84+
85+
for (const auto &capture : getCaptures()) {
86+
if (!capture.getDecl()->isLocalCapture())
87+
continue;
88+
89+
if (capture.isDynamicSelfMetadata())
90+
continue;
91+
92+
// If we captured an isolated parameter, return it.
93+
if (auto param = dyn_cast_or_null<ParamDecl>(capture.getDecl())) {
94+
// If we have captured an isolated parameter, return it.
95+
if (param->isIsolated())
96+
return param;
97+
}
98+
99+
// If we captured 'self', check whether it is (still) isolated.
100+
if (auto var = dyn_cast_or_null<VarDecl>(capture.getDecl())) {
101+
if (var->isSelfParamCapture() && var->isSelfParamCaptureIsolated())
102+
return var;
103+
}
104+
}
105+
106+
return nullptr;
107+
}
108+
81109
LLVM_ATTRIBUTE_USED void CaptureInfo::dump() const {
82110
print(llvm::errs());
83111
llvm::errs() << '\n';

lib/AST/Decl.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/ASTContext.h"
2121
#include "swift/AST/ASTWalker.h"
2222
#include "swift/AST/ASTMangler.h"
23+
#include "swift/AST/CaptureInfo.h"
2324
#include "swift/AST/DiagnosticEngine.h"
2425
#include "swift/AST/DiagnosticsSema.h"
2526
#include "swift/AST/ExistentialLayout.h"
@@ -8614,6 +8615,41 @@ void ClassDecl::setSuperclass(Type superclass) {
86148615
true);
86158616
}
86168617

8618+
bool VarDecl::isSelfParamCaptureIsolated() const {
8619+
assert(isSelfParamCapture());
8620+
8621+
// Find the "self" parameter that we captured and determine whether
8622+
// it is potentially isolated.
8623+
for (auto dc = getDeclContext(); dc; dc = dc->getParent()) {
8624+
if (auto func = dyn_cast<AbstractFunctionDecl>(dc)) {
8625+
if (auto selfDecl = func->getImplicitSelfDecl()) {
8626+
return selfDecl->isIsolated();
8627+
}
8628+
8629+
if (auto capture = func->getCaptureInfo().getIsolatedParamCapture())
8630+
return capture->isSelfParameter() || capture->isSelfParamCapture();
8631+
}
8632+
8633+
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
8634+
switch (auto isolation = closure->getActorIsolation()) {
8635+
case ClosureActorIsolation::Independent:
8636+
case ClosureActorIsolation::GlobalActor:
8637+
return false;
8638+
8639+
case ClosureActorIsolation::ActorInstance:
8640+
auto isolatedVar = isolation.getActorInstance();
8641+
return isolatedVar->isSelfParameter() ||
8642+
isolatedVar-isSelfParamCapture();
8643+
}
8644+
}
8645+
8646+
if (dc->isModuleScopeContext() || dc->isTypeContext())
8647+
break;
8648+
}
8649+
8650+
return false;
8651+
}
8652+
86178653
ActorIsolation swift::getActorIsolation(ValueDecl *value) {
86188654
auto &ctx = value->getASTContext();
86198655
return evaluateOrDefault(
@@ -8643,7 +8679,7 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
86438679

86448680
case ClosureActorIsolation::ActorInstance: {
86458681
auto selfDecl = isolation.getActorInstance();
8646-
auto actorClass = selfDecl->getType()->getRValueType()
8682+
auto actorClass = selfDecl->getType()->getReferenceStorageReferent()
86478683
->getClassOrBoundGenericClass();
86488684
// FIXME: Doesn't work properly with generics
86498685
assert(actorClass && "Bad closure actor isolation?");

lib/AST/Expr.cpp

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,15 +1708,49 @@ Type AbstractClosureExpr::getResultType(
17081708
}
17091709

17101710
bool AbstractClosureExpr::isBodyThrowing() const {
1711-
if (getType()->hasError())
1711+
if (!getType() || getType()->hasError()) {
1712+
// Scan the closure body to infer effects.
1713+
if (auto closure = dyn_cast<ClosureExpr>(this)) {
1714+
return evaluateOrDefault(
1715+
getASTContext().evaluator,
1716+
ClosureEffectsRequest{const_cast<ClosureExpr *>(closure)},
1717+
FunctionType::ExtInfo()).isThrowing();
1718+
}
1719+
17121720
return false;
1721+
}
17131722

17141723
return getType()->castTo<FunctionType>()->getExtInfo().isThrowing();
17151724
}
17161725

1726+
bool AbstractClosureExpr::isSendable() const {
1727+
if (!getType() || getType()->hasError()) {
1728+
// Scan the closure body to infer effects.
1729+
if (auto closure = dyn_cast<ClosureExpr>(this)) {
1730+
return evaluateOrDefault(
1731+
getASTContext().evaluator,
1732+
ClosureEffectsRequest{const_cast<ClosureExpr *>(closure)},
1733+
FunctionType::ExtInfo()).isSendable();
1734+
}
1735+
1736+
return false;
1737+
}
1738+
1739+
return getType()->castTo<FunctionType>()->getExtInfo().isSendable();
1740+
}
1741+
17171742
bool AbstractClosureExpr::isBodyAsync() const {
1718-
if (getType()->hasError())
1743+
if (!getType() || getType()->hasError()) {
1744+
// Scan the closure body to infer effects.
1745+
if (auto closure = dyn_cast<ClosureExpr>(this)) {
1746+
return evaluateOrDefault(
1747+
getASTContext().evaluator,
1748+
ClosureEffectsRequest{const_cast<ClosureExpr *>(closure)},
1749+
FunctionType::ExtInfo()).isAsync();
1750+
}
1751+
17191752
return false;
1753+
}
17201754

17211755
return getType()->castTo<FunctionType>()->getExtInfo().isAsync();
17221756
}

lib/SILGen/SILGenProlog.cpp

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,17 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
558558
!F.isAsync() &&
559559
!isInActorDestructor(FunctionDC);
560560

561+
// Local function to load the expected executor from a local actor
562+
auto loadExpectedExecutorForLocalVar = [&](VarDecl *var) {
563+
auto loc = RegularLocation::getAutoGeneratedLocation(F.getLocation());
564+
Type actorType = var->getType();
565+
RValue actorInstanceRV = emitRValueForDecl(
566+
loc, var, actorType, AccessSemantics::Ordinary);
567+
ManagedValue actorInstance =
568+
std::move(actorInstanceRV).getScalarValue();
569+
ExpectedExecutor = emitLoadActorExecutor(loc, actorInstance);
570+
};
571+
561572
if (auto *funcDecl =
562573
dyn_cast_or_null<AbstractFunctionDecl>(FunctionDC->getAsDecl())) {
563574
auto actorIsolation = getActorIsolation(funcDecl);
@@ -569,13 +580,7 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
569580
if (F.isAsync()) {
570581
for (auto param : *funcDecl->getParameters()) {
571582
if (param->isIsolated()) {
572-
auto loc = RegularLocation::getAutoGeneratedLocation(F.getLocation());
573-
Type actorType = param->getType();
574-
RValue actorInstanceRV = emitRValueForDecl(
575-
loc, param, actorType, AccessSemantics::Ordinary);
576-
ManagedValue actorInstance =
577-
std::move(actorInstanceRV).getScalarValue();
578-
ExpectedExecutor = emitLoadActorExecutor(loc, actorInstance);
583+
loadExpectedExecutorForLocalVar(param);
579584
break;
580585
}
581586
}
@@ -588,16 +593,21 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
588593
}
589594

590595
case ActorIsolation::ActorInstance: {
591-
assert(selfParam && "no self parameter for ActorInstance isolation");
592596
// Only produce an executor for actor-isolated functions that are async
593597
// or are local functions. The former require a hop, while the latter
594598
// are prone to dynamic data races in code that does not enforce Sendable
595599
// completely.
596600
if (F.isAsync() ||
597601
(wantDataRaceChecks && funcDecl->isLocalCapture())) {
598-
auto loc = RegularLocation::getAutoGeneratedLocation(F.getLocation());
599-
ManagedValue selfArg = ManagedValue::forUnmanaged(F.getSelfArgument());
600-
ExpectedExecutor = emitLoadActorExecutor(loc, selfArg);
602+
if (auto isolatedParam = funcDecl->getCaptureInfo()
603+
.getIsolatedParamCapture()) {
604+
loadExpectedExecutorForLocalVar(isolatedParam);
605+
} else {
606+
assert(selfParam && "no self parameter for ActorInstance isolation");
607+
auto loc = RegularLocation::getAutoGeneratedLocation(F.getLocation());
608+
ManagedValue selfArg = ManagedValue::forUnmanaged(F.getSelfArgument());
609+
ExpectedExecutor = emitLoadActorExecutor(loc, selfArg);
610+
}
601611
}
602612
break;
603613
}
@@ -619,14 +629,7 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
619629

620630
case ClosureActorIsolation::ActorInstance: {
621631
if (wantExecutor) {
622-
auto loc = RegularLocation::getAutoGeneratedLocation(F.getLocation());
623-
auto actorDecl = actorIsolation.getActorInstance();
624-
Type actorType = actorDecl->getType();
625-
RValue actorInstanceRV = emitRValueForDecl(loc,
626-
actorDecl, actorType, AccessSemantics::Ordinary);
627-
ManagedValue actorInstance =
628-
std::move(actorInstanceRV).getScalarValue();
629-
ExpectedExecutor = emitLoadActorExecutor(loc, actorInstance);
632+
loadExpectedExecutorForLocalVar(actorIsolation.getActorInstance());
630633
}
631634
break;
632635
}

0 commit comments

Comments
 (0)