Skip to content

Commit 62a2a73

Browse files
authored
Merge pull request #37020 from DougGregor/async-operation-5.5
[5.5] [Concurrency] Add "async" operation for continuing work asynchronously.
2 parents 2ca3c73 + bf603ea commit 62a2a73

File tree

19 files changed

+332
-21
lines changed

19 files changed

+332
-21
lines changed

include/swift/AST/Attr.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,11 @@ SIMPLE_DECL_ATTR(_implicitSelfCapture, ImplicitSelfCapture,
652652
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIBreakingToRemove,
653653
115)
654654

655+
SIMPLE_DECL_ATTR(_inheritActorContext, InheritActorContext,
656+
OnParam | UserInaccessible |
657+
ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIBreakingToRemove,
658+
116)
659+
655660
#undef TYPE_ATTR
656661
#undef DECL_ATTR_ALIAS
657662
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/Expr.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,14 +292,18 @@ class alignas(8) Expr {
292292
Kind : 2
293293
);
294294

295-
SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1+1,
295+
SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1+1+1,
296296
/// True if closure parameters were synthesized from anonymous closure
297297
/// variables.
298298
HasAnonymousClosureVars : 1,
299299

300300
/// True if "self" can be captured implicitly without requiring "self."
301301
/// on each member reference.
302-
ImplicitSelfCapture : 1
302+
ImplicitSelfCapture : 1,
303+
304+
/// True if this @Sendable async closure parameter should implicitly
305+
/// inherit the actor context from where it was formed.
306+
InheritActorContext : 1
303307
);
304308

305309
SWIFT_INLINE_BITFIELD_FULL(BindOptionalExpr, Expr, 16,
@@ -3876,6 +3880,7 @@ class ClosureExpr : public AbstractClosureExpr {
38763880
setParameterList(params);
38773881
Bits.ClosureExpr.HasAnonymousClosureVars = false;
38783882
Bits.ClosureExpr.ImplicitSelfCapture = false;
3883+
Bits.ClosureExpr.InheritActorContext = false;
38793884
}
38803885

38813886
SourceRange getSourceRange() const;
@@ -3914,6 +3919,16 @@ class ClosureExpr : public AbstractClosureExpr {
39143919
Bits.ClosureExpr.ImplicitSelfCapture = value;
39153920
}
39163921

3922+
/// Whether this closure should implicitly inherit the actor context from
3923+
/// where it was formed. This only affects @Sendable async closures.
3924+
bool inheritsActorContext() const {
3925+
return Bits.ClosureExpr.InheritActorContext;
3926+
}
3927+
3928+
void setInheritsActorContext(bool value = true) {
3929+
Bits.ClosureExpr.InheritActorContext = value;
3930+
}
3931+
39173932
/// Determine whether this closure expression has an
39183933
/// explicitly-specified result type.
39193934
bool hasExplicitResultType() const { return ArrowLoc.isValid(); }

include/swift/AST/Types.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3383,6 +3383,7 @@ struct ParameterListInfo {
33833383
SmallBitVector unsafeSendable;
33843384
SmallBitVector unsafeMainActor;
33853385
SmallBitVector implicitSelfCapture;
3386+
SmallBitVector inheritActorContext;
33863387

33873388
public:
33883389
ParameterListInfo() { }
@@ -3415,6 +3416,10 @@ struct ParameterListInfo {
34153416
/// 'self' to be implicit, without requiring "self.".
34163417
bool isImplicitSelfCapture(unsigned paramIdx) const;
34173418

3419+
/// Whether the given parameter is a closure that should inherit the
3420+
/// actor context from the context in which it was created.
3421+
bool inheritsActorContext(unsigned paramIdx) const;
3422+
34183423
/// Whether there is any contextual information set on this parameter list.
34193424
bool anyContextualInfo() const;
34203425

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,6 @@ LANGUAGE_FEATURE(Sendable, 0, "Sendable and @Sendable", true)
4646
LANGUAGE_FEATURE(BuiltinExecutor, 0, "Executor builtins", true)
4747
LANGUAGE_FEATURE(BuiltinContinuation, 0, "Continuation builtins", true)
4848
LANGUAGE_FEATURE(BuiltinTaskGroup, 0, "TaskGroup builtins", true)
49+
LANGUAGE_FEATURE(InheritActorContext, 0, "@_inheritActorContext attribute", true)
4950

5051
#undef LANGUAGE_FEATURE

include/swift/Runtime/Concurrency.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,10 @@ SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
584584
void swift_task_reportUnexpectedExecutor(
585585
const unsigned char *file, uintptr_t fileLength, bool fileIsASCII,
586586
uintptr_t line, ExecutorRef executor);
587+
588+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
589+
JobPriority swift_task_getCurrentThreadPriority(void);
590+
587591
}
588592

589593
#pragma clang diagnostic pop

lib/AST/ASTDumper.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2548,6 +2548,8 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
25482548
PrintWithColorRAII(OS, ClosureModifierColor) << " single-expression";
25492549
if (E->allowsImplicitSelfCapture())
25502550
PrintWithColorRAII(OS, ClosureModifierColor) << " implicit-self";
2551+
if (E->inheritsActorContext())
2552+
PrintWithColorRAII(OS, ClosureModifierColor) << " inherits-actor-context";
25512553

25522554
if (E->getParameters()) {
25532555
OS << '\n';

lib/AST/ASTPrinter.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2782,6 +2782,17 @@ static bool usesFeatureBuiltinTaskGroup(Decl *decl) {
27822782
return false;
27832783
}
27842784

2785+
static bool usesFeatureInheritActorContext(Decl *decl) {
2786+
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
2787+
for (auto param : *func->getParameters()) {
2788+
if (param->getAttrs().hasAttribute<InheritActorContextAttr>())
2789+
return true;
2790+
}
2791+
}
2792+
2793+
return false;
2794+
}
2795+
27852796
/// Determine the set of "new" features used on a given declaration.
27862797
///
27872798
/// Note: right now, all features we check for are "new". At some point, we'll

lib/AST/Type.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,7 @@ ParameterListInfo::ParameterListInfo(
971971
unsafeSendable.resize(params.size());
972972
unsafeMainActor.resize(params.size());
973973
implicitSelfCapture.resize(params.size());
974+
inheritActorContext.resize(params.size());
974975

975976
// No parameter owner means no parameter list means no default arguments
976977
// - hand back the zeroed bitvector.
@@ -1034,6 +1035,10 @@ ParameterListInfo::ParameterListInfo(
10341035
if (param->getAttrs().hasAttribute<ImplicitSelfCaptureAttr>()) {
10351036
implicitSelfCapture.set(i);
10361037
}
1038+
1039+
if (param->getAttrs().hasAttribute<InheritActorContextAttr>()) {
1040+
inheritActorContext.set(i);
1041+
}
10371042
}
10381043
}
10391044

@@ -1070,9 +1075,15 @@ bool ParameterListInfo::isImplicitSelfCapture(unsigned paramIdx) const {
10701075
: false;
10711076
}
10721077

1078+
bool ParameterListInfo::inheritsActorContext(unsigned paramIdx) const {
1079+
return paramIdx < inheritActorContext.size()
1080+
? inheritActorContext[paramIdx]
1081+
: false;
1082+
}
1083+
10731084
bool ParameterListInfo::anyContextualInfo() const {
10741085
return unsafeSendable.any() || unsafeMainActor.any() ||
1075-
implicitSelfCapture.any();
1086+
implicitSelfCapture.any() || inheritActorContext.any();
10761087
}
10771088

10781089
/// Turn a param list into a symbolic and printable representation that does not

lib/Sema/CSApply.cpp

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5712,17 +5712,25 @@ static bool hasCurriedSelf(ConstraintSystem &cs, ConcreteDeclRef callee,
57125712

57135713
/// Apply the contextually Sendable flag to the given expression,
57145714
static void applyContextualClosureFlags(
5715-
Expr *expr, bool sendable, bool forMainActor, bool implicitSelfCapture) {
5715+
Expr *expr, bool sendable, bool forMainActor, bool implicitSelfCapture,
5716+
bool inheritActorContext) {
57165717
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
57175718
closure->setUnsafeConcurrent(sendable, forMainActor);
57185719
closure->setAllowsImplicitSelfCapture(implicitSelfCapture);
5720+
closure->setInheritsActorContext(inheritActorContext);
57195721
return;
57205722
}
57215723

57225724
if (auto captureList = dyn_cast<CaptureListExpr>(expr)) {
57235725
applyContextualClosureFlags(
57245726
captureList->getClosureBody(), sendable, forMainActor,
5725-
implicitSelfCapture);
5727+
implicitSelfCapture, inheritActorContext);
5728+
}
5729+
5730+
if (auto identity = dyn_cast<IdentityExpr>(expr)) {
5731+
applyContextualClosureFlags(
5732+
identity->getSubExpr(), sendable, forMainActor,
5733+
implicitSelfCapture, inheritActorContext);
57265734
}
57275735
}
57285736

@@ -5983,9 +5991,10 @@ Expr *ExprRewriter::coerceCallArguments(
59835991
bool isMainActor = paramInfo.isUnsafeMainActor(paramIdx) ||
59845992
(isUnsafeSendable && apply && isMainDispatchQueue(apply->getFn()));
59855993
bool isImplicitSelfCapture = paramInfo.isImplicitSelfCapture(paramIdx);
5994+
bool inheritsActorContext = paramInfo.inheritsActorContext(paramIdx);
59865995
applyContextualClosureFlags(
59875996
arg, isUnsafeSendable && contextUsesConcurrencyFeatures(dc),
5988-
isMainActor, isImplicitSelfCapture);
5997+
isMainActor, isImplicitSelfCapture, inheritsActorContext);
59895998

59905999
// If the types exactly match, this is easy.
59916000
auto paramType = param.getOldType();
@@ -6138,6 +6147,20 @@ static bool isClosureLiteralExpr(Expr *expr) {
61386147
return (isa<CaptureListExpr>(expr) || isa<ClosureExpr>(expr));
61396148
}
61406149

6150+
/// Whether we should propagate async down to a closure.
6151+
static bool shouldPropagateAsyncToClosure(Expr *expr) {
6152+
if (auto IE = dyn_cast<IdentityExpr>(expr))
6153+
return shouldPropagateAsyncToClosure(IE->getSubExpr());
6154+
6155+
if (auto CLE = dyn_cast<CaptureListExpr>(expr))
6156+
return shouldPropagateAsyncToClosure(CLE->getClosureBody());
6157+
6158+
if (auto CE = dyn_cast<ClosureExpr>(expr))
6159+
return CE->inheritsActorContext();
6160+
6161+
return false;
6162+
}
6163+
61416164
/// If the expression is an explicit closure expression (potentially wrapped in
61426165
/// IdentityExprs), change the type of the closure and identities to the
61436166
/// specified type and return true. Otherwise, return false with no effect.
@@ -7002,8 +7025,8 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
70027025
}
70037026
}
70047027

7005-
// If we have a ClosureExpr, then we can safely propagate the 'concurrent'
7006-
// bit to the closure without invalidating prior analysis.
7028+
// If we have a ClosureExpr, then we can safely propagate @Sendable
7029+
// to the closure without invalidating prior analysis.
70077030
auto fromEI = fromFunc->getExtInfo();
70087031
if (toEI.isSendable() && !fromEI.isSendable()) {
70097032
auto newFromFuncType = fromFunc->withExtInfo(fromEI.withConcurrent());
@@ -7017,6 +7040,22 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
70177040
}
70187041
}
70197042

7043+
// If we have a ClosureExpr, then we can safely propagate the 'async'
7044+
// bit to the closure without invalidating prior analysis.
7045+
fromEI = fromFunc->getExtInfo();
7046+
if (toEI.isAsync() && !fromEI.isAsync() &&
7047+
shouldPropagateAsyncToClosure(expr)) {
7048+
auto newFromFuncType = fromFunc->withExtInfo(fromEI.withAsync());
7049+
if (applyTypeToClosureExpr(cs, expr, newFromFuncType)) {
7050+
fromFunc = newFromFuncType->castTo<FunctionType>();
7051+
7052+
// Propagating the 'concurrent' bit might have satisfied the entire
7053+
// conversion. If so, we're done, otherwise keep converting.
7054+
if (fromFunc->isEqual(toType))
7055+
return expr;
7056+
}
7057+
}
7058+
70207059
// If we have a ClosureExpr, then we can safely propagate a global actor
70217060
// to the closure without invalidating prior analysis.
70227061
fromEI = fromFunc->getExtInfo();

lib/Sema/TypeCheckAttr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
138138
IGNORED_ATTR(UnsafeSendable)
139139
IGNORED_ATTR(UnsafeMainActor)
140140
IGNORED_ATTR(ImplicitSelfCapture)
141+
IGNORED_ATTR(InheritActorContext)
141142
#undef IGNORED_ATTR
142143

143144
void visitAlignmentAttr(AlignmentAttr *attr) {

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -773,19 +773,26 @@ static bool isAsyncCall(const ApplyExpr *call) {
773773
/// features.
774774
static bool shouldDiagnoseExistingDataRaces(const DeclContext *dc);
775775

776-
/// Determine whether this closure is escaping.
777-
static bool isSendableClosure(const AbstractClosureExpr *closure) {
776+
/// Determine whether this closure should be treated as Sendable.
777+
///
778+
/// \param forActorIsolation Whether this check is for the purposes of
779+
/// determining whether the closure must be non-isolated.
780+
static bool isSendableClosure(
781+
const AbstractClosureExpr *closure, bool forActorIsolation) {
782+
if (auto explicitClosure = dyn_cast<ClosureExpr>(closure)) {
783+
if (forActorIsolation && explicitClosure->inheritsActorContext())
784+
return false;
785+
786+
if (explicitClosure->isUnsafeSendable())
787+
return true;
788+
}
789+
778790
if (auto type = closure->getType()) {
779791
if (auto fnType = type->getAs<AnyFunctionType>())
780792
if (fnType->isSendable())
781793
return true;
782794
}
783795

784-
if (auto explicitClosure = dyn_cast<ClosureExpr>(closure)) {
785-
if (explicitClosure->isUnsafeSendable())
786-
return true;
787-
}
788-
789796
return false;
790797
}
791798

@@ -2113,7 +2120,7 @@ namespace {
21132120
}
21142121

21152122
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
2116-
if (isSendableClosure(closure)) {
2123+
if (isSendableClosure(closure, /*forActorIsolation=*/true)) {
21172124
return diag::actor_isolated_from_concurrent_closure;
21182125
}
21192126

@@ -2310,8 +2317,9 @@ namespace {
23102317
}
23112318
}
23122319

2313-
// Sendable closures are always actor-independent.
2314-
if (isSendableClosure(closure))
2320+
// Sendable closures are actor-independent unless the closure has
2321+
// specifically opted into inheriting actor isolation.
2322+
if (isSendableClosure(closure, /*forActorIsolation=*/true))
23152323
return ClosureActorIsolation::forIndependent();
23162324

23172325
// A non-escaping closure gets its isolation from its context.
@@ -2362,7 +2370,7 @@ bool ActorIsolationChecker::mayExecuteConcurrentlyWith(
23622370
while (useContext != defContext) {
23632371
// If we find a concurrent closure... it can be run concurrently.
23642372
if (auto closure = dyn_cast<AbstractClosureExpr>(useContext)) {
2365-
if (isSendableClosure(closure))
2373+
if (isSendableClosure(closure, /*forActorIsolation=*/false))
23662374
return true;
23672375
}
23682376

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,7 @@ namespace {
15471547
UNINTERESTING_ATTR(UnsafeSendable)
15481548
UNINTERESTING_ATTR(UnsafeMainActor)
15491549
UNINTERESTING_ATTR(ImplicitSelfCapture)
1550+
UNINTERESTING_ATTR(InheritActorContext)
15501551
#undef UNINTERESTING_ATTR
15511552

15521553
void visitAvailableAttr(AvailableAttr *attr) {

stdlib/public/Concurrency/Actor.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "swift/ABI/Actor.h"
2828
#include "llvm/ADT/PointerIntPair.h"
2929
#include "TaskPrivate.h"
30+
#include <dispatch/dispatch.h>
3031

3132
#if defined(__APPLE__)
3233
#include <asl.h>
@@ -259,6 +260,17 @@ static bool isExecutingOnMainThread() {
259260
#endif
260261
}
261262

263+
JobPriority swift::swift_task_getCurrentThreadPriority() {
264+
if (isExecutingOnMainThread())
265+
return JobPriority::UserInitiated;
266+
267+
#if defined(__APPLE__)
268+
return static_cast<JobPriority>(qos_class_self());
269+
#else
270+
return JobPriority::Unspecified;
271+
#endif
272+
}
273+
262274
SWIFT_CC(swift)
263275
static bool swift_task_isCurrentExecutorImpl(ExecutorRef executor) {
264276
if (auto currentTracking = ExecutorTrackingInfo::current()) {

0 commit comments

Comments
 (0)