Skip to content

Commit f965c1b

Browse files
committed
[Sema] Start propagating @_inheritActorContext(always) attribute to closures
1 parent b183462 commit f965c1b

File tree

6 files changed

+106
-35
lines changed

6 files changed

+106
-35
lines changed

include/swift/AST/Expr.h

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
267267
Kind : 2
268268
);
269269

270-
SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1+1+1+1+1+1+1+1,
270+
SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1+1+1+1+1+1+1+1+1,
271271
/// True if closure parameters were synthesized from anonymous closure
272272
/// variables.
273273
HasAnonymousClosureVars : 1,
@@ -276,9 +276,11 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
276276
/// on each member reference.
277277
ImplicitSelfCapture : 1,
278278

279-
/// True if this @Sendable async closure parameter should implicitly
280-
/// inherit the actor context from where it was formed.
279+
/// True if this closure parameter should implicitly inherit the actor
280+
/// context from where it was formed.
281281
InheritActorContext : 1,
282+
/// The kind for inheritance - none or always at the moment.
283+
InheritActorContextKind : 1,
282284

283285
/// True if this closure's actor isolation behavior was determined by an
284286
/// \c \@preconcurrency declaration.
@@ -4318,6 +4320,7 @@ class ClosureExpr : public AbstractClosureExpr {
43184320
Bits.ClosureExpr.HasAnonymousClosureVars = false;
43194321
Bits.ClosureExpr.ImplicitSelfCapture = false;
43204322
Bits.ClosureExpr.InheritActorContext = false;
4323+
Bits.ClosureExpr.InheritActorContextKind = 0;
43214324
Bits.ClosureExpr.IsPassedToSendingParameter = false;
43224325
Bits.ClosureExpr.NoGlobalActorAttribute = false;
43234326
Bits.ClosureExpr.RequiresDynamicIsolationChecking = false;
@@ -4366,8 +4369,29 @@ class ClosureExpr : public AbstractClosureExpr {
43664369
return Bits.ClosureExpr.InheritActorContext;
43674370
}
43684371

4369-
void setInheritsActorContext(bool value = true) {
4372+
/// Whether this closure should _always_ implicitly inherit the actor context
4373+
/// regardless of whether the isolation parameter is captured or not.
4374+
bool alwaysInheritsActorContext() const {
4375+
if (!inheritsActorContext())
4376+
return false;
4377+
return getInheritActorIsolationModifier() ==
4378+
InheritActorContextModifier::Always;
4379+
}
4380+
4381+
void setInheritsActorContext(bool value = true,
4382+
InheritActorContextModifier modifier =
4383+
InheritActorContextModifier::None) {
43704384
Bits.ClosureExpr.InheritActorContext = value;
4385+
Bits.ClosureExpr.InheritActorContextKind = uint8_t(modifier);
4386+
assert((static_cast<InheritActorContextModifier>(
4387+
Bits.ClosureExpr.InheritActorContextKind) == modifier) &&
4388+
"not enough bits for modifier");
4389+
}
4390+
4391+
InheritActorContextModifier getInheritActorIsolationModifier() const {
4392+
assert(inheritsActorContext());
4393+
return static_cast<InheritActorContextModifier>(
4394+
Bits.ClosureExpr.InheritActorContextKind);
43714395
}
43724396

43734397
/// Whether the closure's concurrency behavior was determined by an

include/swift/AST/Types.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4049,6 +4049,7 @@ struct ParameterListInfo {
40494049
SmallBitVector propertyWrappers;
40504050
SmallBitVector implicitSelfCapture;
40514051
SmallBitVector inheritActorContext;
4052+
SmallBitVector alwaysInheritActorContext;
40524053
SmallBitVector variadicGenerics;
40534054
SmallBitVector sendingParameters;
40544055

@@ -4075,7 +4076,8 @@ struct ParameterListInfo {
40754076

40764077
/// Whether the given parameter is a closure that should inherit the
40774078
/// actor context from the context in which it was created.
4078-
bool inheritsActorContext(unsigned paramIdx) const;
4079+
std::pair<bool, InheritActorContextModifier>
4080+
inheritsActorContext(unsigned paramIdx) const;
40794081

40804082
bool isVariadicGenericParameter(unsigned paramIdx) const;
40814083

lib/AST/Type.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,7 @@ ParameterListInfo::ParameterListInfo(
13781378
propertyWrappers.resize(params.size());
13791379
implicitSelfCapture.resize(params.size());
13801380
inheritActorContext.resize(params.size());
1381+
alwaysInheritActorContext.resize(params.size());
13811382
variadicGenerics.resize(params.size());
13821383
sendingParameters.resize(params.size());
13831384

@@ -1434,8 +1435,13 @@ ParameterListInfo::ParameterListInfo(
14341435
implicitSelfCapture.set(i);
14351436
}
14361437

1437-
if (param->getAttrs().hasAttribute<InheritActorContextAttr>()) {
1438-
inheritActorContext.set(i);
1438+
if (auto *attr =
1439+
param->getAttrs().getAttribute<InheritActorContextAttr>()) {
1440+
if (attr->isAlways()) {
1441+
alwaysInheritActorContext.set(i);
1442+
} else {
1443+
inheritActorContext.set(i);
1444+
}
14391445
}
14401446

14411447
if (param->getInterfaceType()->is<PackExpansionType>()) {
@@ -1469,10 +1475,18 @@ bool ParameterListInfo::isImplicitSelfCapture(unsigned paramIdx) const {
14691475
: false;
14701476
}
14711477

1472-
bool ParameterListInfo::inheritsActorContext(unsigned paramIdx) const {
1473-
return paramIdx < inheritActorContext.size()
1474-
? inheritActorContext[paramIdx]
1475-
: false;
1478+
std::pair<bool, InheritActorContextModifier>
1479+
ParameterListInfo::inheritsActorContext(unsigned paramIdx) const {
1480+
if (paramIdx >= inheritActorContext.size())
1481+
return std::make_pair(false, InheritActorContextModifier::None);
1482+
1483+
if (inheritActorContext[paramIdx])
1484+
return std::make_pair(true, InheritActorContextModifier::None);
1485+
1486+
if (alwaysInheritActorContext[paramIdx])
1487+
return std::make_pair(true, InheritActorContextModifier::Always);
1488+
1489+
return std::make_pair(false, InheritActorContextModifier::None);
14761490
}
14771491

14781492
bool ParameterListInfo::isVariadicGenericParameter(unsigned paramIdx) const {

lib/Sema/CSApply.cpp

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6097,35 +6097,35 @@ static bool hasCurriedSelf(ConstraintSystem &cs, ConcreteDeclRef callee,
60976097
}
60986098

60996099
/// Apply the contextually Sendable flag to the given expression,
6100-
static void applyContextualClosureFlags(Expr *expr, bool implicitSelfCapture,
6101-
bool inheritActorContext,
6102-
bool isPassedToSendingParameter,
6100+
static void applyContextualClosureFlags(Expr *expr, unsigned paramIdx,
6101+
const ParameterListInfo &paramInfo,
61036102
bool requiresDynamicIsolationChecking,
61046103
bool isMacroArg) {
61056104
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
6106-
closure->setAllowsImplicitSelfCapture(implicitSelfCapture);
6107-
closure->setInheritsActorContext(inheritActorContext);
6108-
closure->setIsPassedToSendingParameter(isPassedToSendingParameter);
6105+
closure->setAllowsImplicitSelfCapture(
6106+
paramInfo.isImplicitSelfCapture(paramIdx));
6107+
6108+
auto [inheritActorContext, modifier] =
6109+
paramInfo.inheritsActorContext(paramIdx);
6110+
closure->setInheritsActorContext(inheritActorContext, modifier);
6111+
6112+
closure->setIsPassedToSendingParameter(
6113+
paramInfo.isSendingParameter(paramIdx));
61096114
closure->setRequiresDynamicIsolationChecking(
61106115
requiresDynamicIsolationChecking);
61116116
closure->setIsMacroArgument(isMacroArg);
61126117
return;
61136118
}
61146119

61156120
if (auto captureList = dyn_cast<CaptureListExpr>(expr)) {
6116-
applyContextualClosureFlags(captureList->getClosureBody(),
6117-
implicitSelfCapture, inheritActorContext,
6118-
isPassedToSendingParameter,
6119-
requiresDynamicIsolationChecking,
6121+
applyContextualClosureFlags(captureList->getClosureBody(), paramIdx,
6122+
paramInfo, requiresDynamicIsolationChecking,
61206123
isMacroArg);
61216124
}
61226125

61236126
if (auto identity = dyn_cast<IdentityExpr>(expr)) {
6124-
applyContextualClosureFlags(identity->getSubExpr(), implicitSelfCapture,
6125-
inheritActorContext,
6126-
isPassedToSendingParameter,
6127-
requiresDynamicIsolationChecking,
6128-
isMacroArg);
6127+
applyContextualClosureFlags(identity->getSubExpr(), paramIdx, paramInfo,
6128+
requiresDynamicIsolationChecking, isMacroArg);
61296129
}
61306130
}
61316131

@@ -6251,19 +6251,13 @@ ArgumentList *ExprRewriter::coerceCallArguments(
62516251

62526252
auto applyFlagsToArgument = [&paramInfo,
62536253
&closuresRequireDynamicIsolationChecking,
6254-
&locator](
6255-
unsigned paramIdx, Expr *argument) {
6254+
&locator](unsigned paramIdx, Expr *argument) {
62566255
if (!isClosureLiteralExpr(argument))
62576256
return;
62586257

6259-
bool isImplicitSelfCapture = paramInfo.isImplicitSelfCapture(paramIdx);
6260-
bool inheritsActorContext = paramInfo.inheritsActorContext(paramIdx);
6261-
bool isPassedToSendingParameter = paramInfo.isSendingParameter(paramIdx);
62626258
bool isMacroArg = isExpr<MacroExpansionExpr>(locator.getAnchor());
62636259

6264-
applyContextualClosureFlags(argument, isImplicitSelfCapture,
6265-
inheritsActorContext,
6266-
isPassedToSendingParameter,
6260+
applyContextualClosureFlags(argument, paramIdx, paramInfo,
62676261
closuresRequireDynamicIsolationChecking,
62686262
isMacroArg);
62696263
};

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4774,6 +4774,11 @@ ActorIsolation ActorIsolationChecker::determineClosureIsolation(
47744774

47754775
case ActorIsolation::ActorInstance: {
47764776
if (checkIsolatedCapture) {
4777+
auto *explicitClosure = dyn_cast<ClosureExpr>(closure);
4778+
// @_inheritActorContext(always) forces the isolation capture.
4779+
if (explicitClosure && explicitClosure->alwaysInheritsActorContext())
4780+
return parentIsolation;
4781+
47774782
if (auto param = closure->getCaptureInfo().getIsolatedParamCapture())
47784783
return ActorIsolation::forActorInstanceCapture(param);
47794784
} else {

test/Concurrency/actor_isolation.swift

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,8 @@ actor MyServer : Server {
12101210
func acceptAsyncSendableClosure<T>(_: @Sendable () async -> T) { }
12111211
@available(SwiftStdlib 5.1, *)
12121212
func acceptAsyncSendableClosureInheriting<T>(@_inheritActorContext _: @Sendable () async -> T) { }
1213+
@available(SwiftStdlib 5.1, *)
1214+
func acceptAsyncSendableClosureInheritingAlways<T>(@_inheritActorContext(always) _: @Sendable () async -> T) { }
12131215

12141216
@available(SwiftStdlib 5.1, *)
12151217
extension MyActor {
@@ -1237,6 +1239,10 @@ extension MyActor {
12371239
_ = await synchronous() // expected-warning{{no 'async' operations occur within 'await' expression}}
12381240
counter += 1 // okay
12391241
}
1242+
1243+
acceptAsyncSendableClosureInheritingAlways {
1244+
counter += 1 // Ok
1245+
}
12401246
}
12411247
}
12421248

@@ -1257,6 +1263,32 @@ func testGlobalActorInheritance() {
12571263
acceptAsyncSendableClosureInheriting {
12581264
counter += 1 // ok
12591265
}
1266+
1267+
acceptAsyncSendableClosureInheritingAlways {
1268+
counter += 1 // ok
1269+
}
1270+
}
1271+
1272+
@available(SwiftStdlib 5.1, *)
1273+
func testIsolatedParameter1(_: isolated any Actor, v: inout Int) {
1274+
acceptAsyncSendableClosureInheriting {
1275+
v += 1 // expected-warning {{mutable capture of 'inout' parameter 'v' is not allowed in concurrently-executing code}}
1276+
}
1277+
1278+
acceptAsyncSendableClosureInheritingAlways {
1279+
v += 1 // Ok
1280+
}
1281+
}
1282+
1283+
@available(SwiftStdlib 5.1, *)
1284+
func testIsolatedParameter2(_: isolated (any Actor)? = #isolation, v: inout Int) {
1285+
acceptAsyncSendableClosureInheriting {
1286+
v += 1 // expected-warning {{mutable capture of 'inout' parameter 'v' is not allowed in concurrently-executing code}}
1287+
}
1288+
1289+
acceptAsyncSendableClosureInheritingAlways {
1290+
v += 1 // Ok
1291+
}
12601292
}
12611293

12621294
@available(SwiftStdlib 5.1, *)
@@ -1763,4 +1795,4 @@ actor UserDefinedActorSelfDotMethod {
17631795
// error message changes with InferSendabaleFromCaptures - see actor_isolation_swift6.swift
17641796
return functionRef // expected-error {{cannot convert return expression of type '(isolated Self) -> () -> ()' to return type '(UserDefinedActorSelfDotMethod) -> @isolated(any) () -> Void'}}
17651797
}
1766-
}
1798+
}

0 commit comments

Comments
 (0)