Skip to content

Commit c2ccb87

Browse files
committed
Soften actor isolation in closures passed to @preconcurrency
When a closure is not properly actor-isolated, but we know that we inferred its isolation from a `@preconcurrency` declaration, we now emit the errors as warnings in Swift 5 mode to avoid breaking source compatibility if the isolation was added retroactively.
1 parent 5330653 commit c2ccb87

File tree

7 files changed

+118
-48
lines changed

7 files changed

+118
-48
lines changed

include/swift/AST/ActorIsolation.h

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ bool isLetAccessibleAnywhere(const ModuleDecl *fromModule, VarDecl *let);
4747
/// the actors with which it can interact.
4848
class ActorIsolation {
4949
public:
50-
enum Kind {
50+
enum Kind : uint8_t {
5151
/// The actor isolation has not been specified. It is assumed to be
5252
/// unsafe to interact with this declaration from any actor.
5353
Unspecified = 0,
@@ -69,18 +69,19 @@ class ActorIsolation {
6969
};
7070

7171
private:
72-
Kind kind;
7372
union {
7473
NominalTypeDecl *actor;
7574
Type globalActor;
7675
void *pointer;
7776
};
77+
uint8_t kind : 3;
78+
uint8_t isolatedByPreconcurrency : 1;
7879

7980
ActorIsolation(Kind kind, NominalTypeDecl *actor)
80-
: kind(kind), actor(actor) { }
81+
: actor(actor), kind(kind), isolatedByPreconcurrency(false) { }
8182

8283
ActorIsolation(Kind kind, Type globalActor)
83-
: kind(kind), globalActor(globalActor) { }
84+
: globalActor(globalActor), kind(kind), isolatedByPreconcurrency(false) { }
8485

8586
public:
8687
static ActorIsolation forUnspecified() {
@@ -100,7 +101,7 @@ class ActorIsolation {
100101
unsafe ? GlobalActorUnsafe : GlobalActor, globalActor);
101102
}
102103

103-
Kind getKind() const { return kind; }
104+
Kind getKind() const { return (Kind)kind; }
104105

105106
operator Kind() const { return getKind(); }
106107

@@ -122,6 +123,16 @@ class ActorIsolation {
122123
return globalActor;
123124
}
124125

126+
bool preconcurrency() const {
127+
return isolatedByPreconcurrency;
128+
}
129+
130+
ActorIsolation withPreconcurrency(bool value) const {
131+
auto copy = *this;
132+
copy.isolatedByPreconcurrency = value;
133+
return copy;
134+
}
135+
125136
/// Determine whether this isolation will require substitution to be
126137
/// evaluated.
127138
bool requiresSubstitution() const;
@@ -134,10 +145,10 @@ class ActorIsolation {
134145
if (lhs.isGlobalActor() && rhs.isGlobalActor())
135146
return areTypesEqual(lhs.globalActor, rhs.globalActor);
136147

137-
if (lhs.kind != rhs.kind)
148+
if (lhs.getKind() != rhs.getKind())
138149
return false;
139150

140-
switch (lhs.kind) {
151+
switch (lhs.getKind()) {
141152
case Independent:
142153
case Unspecified:
143154
return true;

include/swift/AST/Expr.h

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
255255
Kind : 2
256256
);
257257

258-
SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1+1+1,
258+
SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1+1+1+1,
259259
/// True if closure parameters were synthesized from anonymous closure
260260
/// variables.
261261
HasAnonymousClosureVars : 1,
@@ -266,7 +266,11 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
266266

267267
/// True if this @Sendable async closure parameter should implicitly
268268
/// inherit the actor context from where it was formed.
269-
InheritActorContext : 1
269+
InheritActorContext : 1,
270+
271+
/// True if this closure's actor isolation behavior was determined by an
272+
/// \c \@preconcurrency declaration.
273+
IsolatedByPreconcurrency : 1
270274
);
271275

272276
SWIFT_INLINE_BITFIELD_FULL(BindOptionalExpr, Expr, 16,
@@ -3536,40 +3540,46 @@ class ClosureActorIsolation {
35363540
};
35373541

35383542
private:
3539-
/// The actor to which this closure is isolated.
3543+
/// The actor to which this closure is isolated, plus a bit indicating
3544+
/// whether the isolation was imposed by a preconcurrency declaration.
35403545
///
3541-
/// There are three possible states:
3546+
/// There are three possible states for the pointer:
35423547
/// - NULL: The closure is independent of any actor.
35433548
/// - VarDecl*: The 'self' variable for the actor instance to which
35443549
/// this closure is isolated. It will always have a type that conforms
35453550
/// to the \c Actor protocol.
35463551
/// - Type: The type of the global actor on which
3547-
llvm::PointerUnion<VarDecl *, Type> storage;
3552+
llvm::PointerIntPair<llvm::PointerUnion<VarDecl *, Type>, 1, bool> storage;
35483553

3549-
ClosureActorIsolation(VarDecl *selfDecl) : storage(selfDecl) { }
3550-
ClosureActorIsolation(Type globalActorType) : storage(globalActorType) { }
3554+
ClosureActorIsolation(VarDecl *selfDecl, bool preconcurrency)
3555+
: storage(selfDecl, preconcurrency) { }
3556+
ClosureActorIsolation(Type globalActorType, bool preconcurrency)
3557+
: storage(globalActorType, preconcurrency) { }
35513558

35523559
public:
3553-
ClosureActorIsolation() : storage() { }
3560+
ClosureActorIsolation(bool preconcurrency = false)
3561+
: storage(nullptr, preconcurrency) { }
35543562

3555-
static ClosureActorIsolation forIndependent() {
3556-
return ClosureActorIsolation();
3563+
static ClosureActorIsolation forIndependent(bool preconcurrency) {
3564+
return ClosureActorIsolation(preconcurrency);
35573565
}
35583566

3559-
static ClosureActorIsolation forActorInstance(VarDecl *selfDecl) {
3560-
return ClosureActorIsolation(selfDecl);
3567+
static ClosureActorIsolation forActorInstance(VarDecl *selfDecl,
3568+
bool preconcurrency) {
3569+
return ClosureActorIsolation(selfDecl, preconcurrency);
35613570
}
35623571

3563-
static ClosureActorIsolation forGlobalActor(Type globalActorType) {
3564-
return ClosureActorIsolation(globalActorType);
3572+
static ClosureActorIsolation forGlobalActor(Type globalActorType,
3573+
bool preconcurrency) {
3574+
return ClosureActorIsolation(globalActorType, preconcurrency);
35653575
}
35663576

35673577
/// Determine the kind of isolation.
35683578
Kind getKind() const {
3569-
if (storage.isNull())
3579+
if (storage.getPointer().isNull())
35703580
return Kind::Independent;
35713581

3572-
if (storage.is<VarDecl *>())
3582+
if (storage.getPointer().is<VarDecl *>())
35733583
return Kind::ActorInstance;
35743584

35753585
return Kind::GlobalActor;
@@ -3586,11 +3596,15 @@ class ClosureActorIsolation {
35863596
}
35873597

35883598
VarDecl *getActorInstance() const {
3589-
return storage.dyn_cast<VarDecl *>();
3599+
return storage.getPointer().dyn_cast<VarDecl *>();
35903600
}
35913601

35923602
Type getGlobalActor() const {
3593-
return storage.dyn_cast<Type>();
3603+
return storage.getPointer().dyn_cast<Type>();
3604+
}
3605+
3606+
bool preconcurrency() const {
3607+
return storage.getInt();
35943608
}
35953609
};
35963610

@@ -3863,6 +3877,16 @@ class ClosureExpr : public AbstractClosureExpr {
38633877
Bits.ClosureExpr.InheritActorContext = value;
38643878
}
38653879

3880+
/// Whether the closure's concurrency behavior was determined by an
3881+
/// \c \@preconcurrency declaration.
3882+
bool isIsolatedByPreconcurrency() const {
3883+
return Bits.ClosureExpr.IsolatedByPreconcurrency;
3884+
}
3885+
3886+
void setIsolatedByPreconcurrency(bool value = true) {
3887+
Bits.ClosureExpr.IsolatedByPreconcurrency = value;
3888+
}
3889+
38663890
/// Determine whether this closure expression has an
38673891
/// explicitly-specified result type.
38683892
bool hasExplicitResultType() const { return ArrowLoc.isValid(); }

lib/AST/Decl.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9030,11 +9030,13 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
90309030
if (auto *closure = dyn_cast<AbstractClosureExpr>(dc)) {
90319031
switch (auto isolation = closure->getActorIsolation()) {
90329032
case ClosureActorIsolation::Independent:
9033-
return ActorIsolation::forIndependent();
9033+
return ActorIsolation::forIndependent()
9034+
.withPreconcurrency(isolation.preconcurrency());
90349035

90359036
case ClosureActorIsolation::GlobalActor: {
90369037
return ActorIsolation::forGlobalActor(
9037-
isolation.getGlobalActor(), /*unsafe=*/false);
9038+
isolation.getGlobalActor(), /*unsafe=*/false)
9039+
.withPreconcurrency(isolation.preconcurrency());
90389040
}
90399041

90409042
case ClosureActorIsolation::ActorInstance: {
@@ -9043,7 +9045,8 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
90439045
->getClassOrBoundGenericClass();
90449046
// FIXME: Doesn't work properly with generics
90459047
assert(actorClass && "Bad closure actor isolation?");
9046-
return ActorIsolation::forActorInstance(actorClass);
9048+
return ActorIsolation::forActorInstance(actorClass)
9049+
.withPreconcurrency(isolation.preconcurrency());
90479050
}
90489051
}
90499052
}

lib/AST/TypeCheckRequests.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1530,7 +1530,8 @@ ActorIsolation ActorIsolation::subst(SubstitutionMap subs) const {
15301530
case GlobalActor:
15311531
case GlobalActorUnsafe:
15321532
return forGlobalActor(
1533-
getGlobalActor().subst(subs), kind == GlobalActorUnsafe);
1533+
getGlobalActor().subst(subs), kind == GlobalActorUnsafe)
1534+
.withPreconcurrency(preconcurrency());
15341535
}
15351536
llvm_unreachable("unhandled actor isolation kind!");
15361537
}

lib/Sema/CSApply.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5592,22 +5592,25 @@ static bool hasCurriedSelf(ConstraintSystem &cs, ConcreteDeclRef callee,
55925592

55935593
/// Apply the contextually Sendable flag to the given expression,
55945594
static void applyContextualClosureFlags(
5595-
Expr *expr, bool implicitSelfCapture, bool inheritActorContext) {
5595+
Expr *expr, bool implicitSelfCapture, bool inheritActorContext,
5596+
bool isolatedByPreconcurrency) {
55965597
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
55975598
closure->setAllowsImplicitSelfCapture(implicitSelfCapture);
55985599
closure->setInheritsActorContext(inheritActorContext);
5600+
closure->setIsolatedByPreconcurrency(isolatedByPreconcurrency);
55995601
return;
56005602
}
56015603

56025604
if (auto captureList = dyn_cast<CaptureListExpr>(expr)) {
56035605
applyContextualClosureFlags(
56045606
captureList->getClosureBody(), implicitSelfCapture,
5605-
inheritActorContext);
5607+
inheritActorContext, isolatedByPreconcurrency);
56065608
}
56075609

56085610
if (auto identity = dyn_cast<IdentityExpr>(expr)) {
56095611
applyContextualClosureFlags(
5610-
identity->getSubExpr(), implicitSelfCapture, inheritActorContext);
5612+
identity->getSubExpr(), implicitSelfCapture, inheritActorContext,
5613+
isolatedByPreconcurrency);
56115614
}
56125615
}
56135616

@@ -5634,6 +5637,8 @@ ArgumentList *ExprRewriter::coerceCallArguments(
56345637
// Determine the parameter bindings.
56355638
ParameterListInfo paramInfo(params, callee.getDecl(), skipCurriedSelf);
56365639

5640+
bool preconcurrency = callee && callee.getDecl()->preconcurrency();
5641+
56375642
// If this application is an init(wrappedValue:) call that needs an injected
56385643
// wrapped value placeholder, the first non-defaulted argument must be
56395644
// wrapped in an OpaqueValueExpr.
@@ -5804,7 +5809,7 @@ ArgumentList *ExprRewriter::coerceCallArguments(
58045809
bool isImplicitSelfCapture = paramInfo.isImplicitSelfCapture(paramIdx);
58055810
bool inheritsActorContext = paramInfo.inheritsActorContext(paramIdx);
58065811
applyContextualClosureFlags(
5807-
argExpr, isImplicitSelfCapture, inheritsActorContext);
5812+
argExpr, isImplicitSelfCapture, inheritsActorContext, preconcurrency);
58085813

58095814
// If the types exactly match, this is easy.
58105815
auto paramType = param.getOldType();

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2112,7 +2112,8 @@ namespace {
21122112
case ActorIsolation::GlobalActorUnsafe:
21132113
return ActorIsolation::forGlobalActor(
21142114
dc->mapTypeIntoContext(isolation.getGlobalActor()),
2115-
isolation == ActorIsolation::GlobalActorUnsafe);
2115+
isolation == ActorIsolation::GlobalActorUnsafe)
2116+
.withPreconcurrency(isolation.preconcurrency());
21162117
}
21172118
}
21182119

@@ -2336,14 +2337,16 @@ namespace {
23362337
apply->getLoc(), diag::actor_isolated_call_decl,
23372338
*unsatisfiedIsolation,
23382339
calleeDecl->getDescriptiveKind(), calleeDecl->getName(),
2339-
getContextIsolation());
2340+
getContextIsolation())
2341+
.warnUntilSwiftVersionIf(getContextIsolation().preconcurrency(), 6);
23402342
calleeDecl->diagnose(
23412343
diag::actor_isolated_sync_func, calleeDecl->getDescriptiveKind(),
23422344
calleeDecl->getName());
23432345
} else {
23442346
ctx.Diags.diagnose(
23452347
apply->getLoc(), diag::actor_isolated_call, *unsatisfiedIsolation,
2346-
getContextIsolation());
2348+
getContextIsolation())
2349+
.warnUntilSwiftVersionIf(getContextIsolation().preconcurrency(), 6);
23472350
}
23482351

23492352
if (unsatisfiedIsolation->isGlobalActor()) {
@@ -2956,45 +2959,52 @@ namespace {
29562959
/// isolation checked.
29572960
ClosureActorIsolation determineClosureIsolation(
29582961
AbstractClosureExpr *closure) {
2959-
// If the closure specifies a global actor, use it.
2962+
bool preconcurrency = false;
2963+
29602964
if (auto explicitClosure = dyn_cast<ClosureExpr>(closure)) {
2965+
preconcurrency = explicitClosure->isIsolatedByPreconcurrency();
2966+
2967+
// If the closure specifies a global actor, use it.
29612968
if (Type globalActorType = resolveGlobalActorType(explicitClosure))
2962-
return ClosureActorIsolation::forGlobalActor(globalActorType);
2969+
return ClosureActorIsolation::forGlobalActor(globalActorType,
2970+
preconcurrency);
29632971
}
29642972

29652973
// If a closure has an isolated parameter, it is isolated to that
29662974
// parameter.
29672975
for (auto param : *closure->getParameters()) {
29682976
if (param->isIsolated())
2969-
return ClosureActorIsolation::forActorInstance(param);
2977+
return ClosureActorIsolation::forActorInstance(param, preconcurrency);
29702978
}
29712979

29722980
// Sendable closures are actor-independent unless the closure has
29732981
// specifically opted into inheriting actor isolation.
29742982
if (isSendableClosure(closure, /*forActorIsolation=*/true))
2975-
return ClosureActorIsolation::forIndependent();
2983+
return ClosureActorIsolation::forIndependent(preconcurrency);
29762984

29772985
// A non-Sendable closure gets its isolation from its context.
29782986
auto parentIsolation = getActorIsolationOfContext(closure->getParent());
2987+
preconcurrency |= parentIsolation.preconcurrency();
29792988

29802989
// We must have parent isolation determined to get here.
29812990
switch (parentIsolation) {
29822991
case ActorIsolation::Independent:
29832992
case ActorIsolation::Unspecified:
2984-
return ClosureActorIsolation::forIndependent();
2993+
return ClosureActorIsolation::forIndependent(preconcurrency);
29852994

29862995
case ActorIsolation::GlobalActor:
29872996
case ActorIsolation::GlobalActorUnsafe: {
29882997
Type globalActorType = closure->mapTypeIntoContext(
29892998
parentIsolation.getGlobalActor()->mapTypeOutOfContext());
2990-
return ClosureActorIsolation::forGlobalActor(globalActorType);
2999+
return ClosureActorIsolation::forGlobalActor(globalActorType,
3000+
preconcurrency);
29913001
}
29923002

29933003
case ActorIsolation::ActorInstance: {
29943004
if (auto param = closure->getCaptureInfo().getIsolatedParamCapture())
2995-
return ClosureActorIsolation::forActorInstance(param);
3005+
return ClosureActorIsolation::forActorInstance(param, preconcurrency);
29963006

2997-
return ClosureActorIsolation::forIndependent();
3007+
return ClosureActorIsolation::forIndependent(preconcurrency);
29983008
}
29993009
}
30003010
}
@@ -3610,12 +3620,14 @@ ActorIsolation ActorIsolationRequest::evaluate(
36103620
// Stored properties cannot be non-isolated, so don't infer it.
36113621
if (auto var = dyn_cast<VarDecl>(value)) {
36123622
if (!var->isStatic() && var->hasStorage())
3613-
return ActorIsolation::forUnspecified();
3623+
return ActorIsolation::forUnspecified()
3624+
.withPreconcurrency(inferred.preconcurrency());
36143625
}
36153626

36163627

36173628
if (onlyGlobal)
3618-
return ActorIsolation::forUnspecified();
3629+
return ActorIsolation::forUnspecified()
3630+
.withPreconcurrency(inferred.preconcurrency());
36193631

36203632
value->getAttrs().add(new (ctx) NonisolatedAttr(/*IsImplicit=*/true));
36213633
break;
@@ -3630,7 +3642,8 @@ ActorIsolation ActorIsolationRequest::evaluate(
36303642
if (auto *nominal = varDC->getSelfNominalTypeDecl())
36313643
if (isa<StructDecl>(nominal) &&
36323644
!isWrappedValueOfPropWrapper(var))
3633-
return ActorIsolation::forUnspecified();
3645+
return ActorIsolation::forUnspecified()
3646+
.withPreconcurrency(inferred.preconcurrency());
36343647

36353648
auto typeExpr = TypeExpr::createImplicit(inferred.getGlobalActor(), ctx);
36363649
auto attr = CustomAttr::create(
@@ -3644,7 +3657,8 @@ ActorIsolation ActorIsolationRequest::evaluate(
36443657
case ActorIsolation::ActorInstance:
36453658
case ActorIsolation::Unspecified:
36463659
if (onlyGlobal)
3647-
return ActorIsolation::forUnspecified();
3660+
return ActorIsolation::forUnspecified()
3661+
.withPreconcurrency(inferred.preconcurrency());
36483662

36493663
// Nothing to do.
36503664
break;

0 commit comments

Comments
 (0)