Skip to content

Commit 8079f1b

Browse files
authored
Merge pull request #81645 from xedin/alwaysInheritActorContext+Task-immediate-6.2
[6.2][Sema/stdlib] SE-0472: implement `@_inheritActorContext(always)` and adopt it in `Task.immediate` APIs
2 parents 8140cbe + 5997a4d commit 8079f1b

38 files changed

+623
-314
lines changed

docs/ReferenceGuides/UnderscoredAttributes.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,43 @@ inherit the actor context (i.e. what actor it should be run on) based on the
600600
declaration site of the closure rather than be non-Sendable. This does not do
601601
anything if the closure is synchronous.
602602

603+
This works with global actors as expected:
604+
605+
```swift
606+
@MainActor
607+
func test() {
608+
Task { /* main actor isolated */ }
609+
}
610+
```
611+
612+
However, for the inference to work with instance actors (i.e. `isolated` parameters),
613+
the closure must capture the isolated parameter explicitly:
614+
615+
```swift
616+
func test(actor: isolated (any Actor)) {
617+
Task { /* non isolated */ } // !!!
618+
}
619+
620+
func test(actor: isolated (any Actor)) {
621+
Task { // @_inheritActorContext
622+
_ = actor // 'actor'-isolated
623+
}
624+
}
625+
```
626+
627+
The attribute takes an optional modifier '`always`', which changes this behavior
628+
and *always* captures the enclosing isolated context, rather than forcing developers
629+
to perform the explicit capture themselfes:
630+
631+
```swift
632+
func test(actor: isolated (any Actor)) {
633+
Task.immediate { // @_inheritActorContext(always)
634+
// 'actor'-isolated!
635+
// (without having to capture 'actor explicitly')
636+
}
637+
}
638+
```
639+
603640
DISCUSSION: The reason why this does nothing when the closure is synchronous is
604641
since it does not have the ability to hop to the appropriate executor before it
605642
is run, so we may create concurrency errors.

include/swift/AST/ASTBridging.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,18 @@ BridgedNonisolatedAttr_createParsed(BridgedASTContext cContext,
12391239
BridgedSourceRange cRange,
12401240
BridgedNonIsolatedModifier modifier);
12411241

1242+
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedInheritActorContextModifier {
1243+
BridgedInheritActorContextModifierNone,
1244+
BridgedInheritActorContextModifierAlways,
1245+
};
1246+
1247+
SWIFT_NAME("BridgedInheritActorContextAttr.createParsed(_:atLoc:range:modifier:)")
1248+
BridgedInheritActorContextAttr
1249+
BridgedInheritActorContextAttr_createParsed(BridgedASTContext cContext,
1250+
BridgedSourceLoc cAtLoc,
1251+
BridgedSourceRange cRange,
1252+
BridgedInheritActorContextModifier modifier);
1253+
12421254
SWIFT_NAME("BridgedObjCAttr.createParsedUnnamed(_:atLoc:attrNameLoc:)")
12431255
BridgedObjCAttr
12441256
BridgedObjCAttr_createParsedUnnamed(BridgedASTContext cContext,

include/swift/AST/Attr.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,10 @@ class DeclAttribute : public AttributeBase {
230230
Modifier : NumNonIsolatedModifierBits
231231
);
232232

233+
SWIFT_INLINE_BITFIELD(InheritActorContextAttr, DeclAttribute, NumInheritActorContextKindBits,
234+
Modifier : NumInheritActorContextKindBits
235+
);
236+
233237
SWIFT_INLINE_BITFIELD_FULL(AllowFeatureSuppressionAttr, DeclAttribute, 1+31,
234238
: NumPadBits,
235239
Inverted : 1,
@@ -3004,6 +3008,50 @@ class NonisolatedAttr final : public DeclAttribute {
30043008
}
30053009
};
30063010

3011+
/// Represents @_inheritActorContext modifier.
3012+
class InheritActorContextAttr final : public DeclAttribute {
3013+
public:
3014+
InheritActorContextAttr(SourceLoc atLoc, SourceRange range,
3015+
InheritActorContextModifier modifier, bool implicit)
3016+
: DeclAttribute(DeclAttrKind::InheritActorContext, atLoc, range,
3017+
implicit) {
3018+
Bits.InheritActorContextAttr.Modifier = static_cast<unsigned>(modifier);
3019+
assert((getModifier() == modifier) && "not enough bits for modifier");
3020+
}
3021+
3022+
InheritActorContextModifier getModifier() const {
3023+
return static_cast<InheritActorContextModifier>(
3024+
Bits.InheritActorContextAttr.Modifier);
3025+
}
3026+
3027+
bool isAlways() const {
3028+
return getModifier() == InheritActorContextModifier::Always;
3029+
}
3030+
3031+
static InheritActorContextAttr *
3032+
createImplicit(ASTContext &ctx, InheritActorContextModifier modifier =
3033+
InheritActorContextModifier::None) {
3034+
return new (ctx)
3035+
InheritActorContextAttr(/*atLoc*/ {}, /*range*/ {}, modifier,
3036+
/*implicit=*/true);
3037+
}
3038+
3039+
static bool classof(const DeclAttribute *DA) {
3040+
return DA->getKind() == DeclAttrKind::InheritActorContext;
3041+
}
3042+
3043+
/// Create a copy of this attribute.
3044+
InheritActorContextAttr *clone(ASTContext &ctx) const {
3045+
return new (ctx)
3046+
InheritActorContextAttr(AtLoc, Range, getModifier(), isImplicit());
3047+
}
3048+
3049+
bool isEquivalent(const InheritActorContextAttr *other,
3050+
Decl *attachedTo) const {
3051+
return getModifier() == other->getModifier();
3052+
}
3053+
};
3054+
30073055
/// A macro role attribute, spelled with either @attached or @freestanding,
30083056
/// which declares one of the roles that a given macro can inhabit.
30093057
class MacroRoleAttr final

include/swift/AST/AttrKind.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,22 @@ enum : unsigned {
142142
static_cast<unsigned>(NonIsolatedModifier::Last_NonIsolatedModifier))
143143
};
144144

145+
enum class InheritActorContextModifier : uint8_t {
146+
/// Inherit the actor execution context if the isolated parameter was
147+
/// captured by the closure, context is nonisolated or isolated to a
148+
/// global actor.
149+
None = 0,
150+
/// Always inherit the actor context, even when the isolated parameter
151+
/// for the context is not closed over explicitly.
152+
Always,
153+
Last_InheritActorContextKind = Always
154+
};
155+
156+
enum : unsigned {
157+
NumInheritActorContextKindBits = countBitsUsed(static_cast<unsigned>(
158+
InheritActorContextModifier::Last_InheritActorContextKind))
159+
};
160+
145161
enum class DeclAttrKind : unsigned {
146162
#define DECL_ATTR(_, CLASS, ...) CLASS,
147163
#define LAST_DECL_ATTR(CLASS) Last_DeclAttr = CLASS,

include/swift/AST/DeclAttr.def

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -619,9 +619,10 @@ SIMPLE_DECL_ATTR(_implicitSelfCapture, ImplicitSelfCapture,
619619
UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIBreakingToRemove | ForbiddenInABIAttr,
620620
115)
621621

622-
SIMPLE_DECL_ATTR(_inheritActorContext, InheritActorContext,
622+
DECL_ATTR(_inheritActorContext, InheritActorContext,
623623
OnParam,
624-
UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIBreakingToRemove | ForbiddenInABIAttr,
624+
// since the _inheritActorContext(always) forces an actor capture, it changes ABI of the closure this applies to
625+
UserInaccessible | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove | UnconstrainedInABIAttr,
625626
116)
626627

627628
SIMPLE_DECL_ATTR(_eagerMove, EagerMove,

include/swift/AST/DiagnosticsSema.def

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8546,6 +8546,23 @@ GROUPED_ERROR(isolated_conformance_wrong_domain,IsolatedConformances,none,
85468546
"%0 conformance of %1 to %2 cannot be used in %3 context",
85478547
(ActorIsolation, Type, DeclName, ActorIsolation))
85488548
8549+
//===----------------------------------------------------------------------===//
8550+
// MARK: @_inheritActorContext
8551+
//===----------------------------------------------------------------------===//
8552+
ERROR(inherit_actor_context_only_on_func_types,none,
8553+
"%0 only applies to parameters with function types (got: %1)",
8554+
(DeclAttribute, Type))
8555+
8556+
ERROR(inherit_actor_context_only_on_sending_or_Sendable_params,none,
8557+
"%0 only applies to 'sending' parameters or parameters with "
8558+
"'@Sendable' function types",
8559+
(DeclAttribute))
8560+
8561+
ERROR(inherit_actor_context_only_on_async_or_isolation_erased_params,none,
8562+
"%0 only applies to '@isolated(any)' parameters or parameters with "
8563+
"asynchronous function types",
8564+
(DeclAttribute))
8565+
85498566
//===----------------------------------------------------------------------===//
85508567
// MARK: @concurrent and nonisolated(nonsending) attributes
85518568
//===----------------------------------------------------------------------===//

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/KnownIdentifiers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ IDENTIFIER(SerializationRequirement)
325325
IDENTIFIER_WITH_NAME(builderSelf, "$builderSelf")
326326

327327
// Attribute options
328+
IDENTIFIER(always)
328329
IDENTIFIER_(_always)
329330
IDENTIFIER_(assumed)
330331
IDENTIFIER(checked)

include/swift/AST/Types.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4045,6 +4045,7 @@ struct ParameterListInfo {
40454045
SmallBitVector propertyWrappers;
40464046
SmallBitVector implicitSelfCapture;
40474047
SmallBitVector inheritActorContext;
4048+
SmallBitVector alwaysInheritActorContext;
40484049
SmallBitVector variadicGenerics;
40494050
SmallBitVector sendingParameters;
40504051

@@ -4071,7 +4072,8 @@ struct ParameterListInfo {
40714072

40724073
/// Whether the given parameter is a closure that should inherit the
40734074
/// actor context from the context in which it was created.
4074-
bool inheritsActorContext(unsigned paramIdx) const;
4075+
std::pair<bool, InheritActorContextModifier>
4076+
inheritsActorContext(unsigned paramIdx) const;
40754077

40764078
bool isVariadicGenericParameter(unsigned paramIdx) const;
40774079

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ LANGUAGE_FEATURE(GeneralizedIsSameMetaTypeBuiltin, 465, "Builtin.is_same_metatyp
260260
LANGUAGE_FEATURE(ValueGenericsNameLookup, 452, "Value generics appearing as static members for namelookup")
261261
SUPPRESSIBLE_LANGUAGE_FEATURE(ABIAttributeSE0479, 479, "@abi attribute on functions, initializers, properties, and subscripts")
262262
LANGUAGE_FEATURE(BuiltinSelect, 0, "Builtin.select")
263+
LANGUAGE_FEATURE(AlwaysInheritActorContext, 472, "@_inheritActorContext(always)")
263264

264265
// Swift 6
265266
UPCOMING_FEATURE(ConciseMagicFile, 274, 6)

include/swift/Parse/IDEInspectionCallbacks.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ enum class ParameterizedDeclAttributeKind {
3939
Available,
4040
FreestandingMacro,
4141
AttachedMacro,
42-
StorageRestrictions
42+
StorageRestrictions,
43+
InheritActorContext
4344
};
4445

4546
/// A bit of a hack. When completing inside the '@storageRestrictions'

lib/AST/ASTDumper.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4994,7 +4994,6 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
49944994
TRIVIAL_ATTR_PRINTER(ImplicitSelfCapture, implicit_self_capture)
49954995
TRIVIAL_ATTR_PRINTER(Indirect, indirect)
49964996
TRIVIAL_ATTR_PRINTER(Infix, infix)
4997-
TRIVIAL_ATTR_PRINTER(InheritActorContext, inherit_actor_context)
49984997
TRIVIAL_ATTR_PRINTER(InheritsConvenienceInitializers,
49994998
inherits_convenience_initializers)
50004999
TRIVIAL_ATTR_PRINTER(Inlinable, inlinable)
@@ -5317,6 +5316,12 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
53175316
printFlag(Attr->isNonSending(), "nonsending");
53185317
printFoot();
53195318
}
5319+
void visitInheritActorContextAttr(InheritActorContextAttr *Attr,
5320+
Label label) {
5321+
printCommon(Attr, "inherit_actor_context_attr", label);
5322+
printFlag(Attr->isAlways(), "always");
5323+
printFoot();
5324+
}
53205325
void visitObjCAttr(ObjCAttr *Attr, Label label) {
53215326
printCommon(Attr, "objc_attr", label);
53225327
if (Attr->hasName())

lib/AST/Attr.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,6 +1531,18 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
15311531
break;
15321532
}
15331533

1534+
case DeclAttrKind::InheritActorContext: {
1535+
Printer.printAttrName("@_inheritActorContext");
1536+
switch (cast<InheritActorContextAttr>(this)->getModifier()) {
1537+
case InheritActorContextModifier::None:
1538+
break;
1539+
case InheritActorContextModifier::Always:
1540+
Printer << "(always)";
1541+
break;
1542+
}
1543+
break;
1544+
}
1545+
15341546
case DeclAttrKind::MacroRole: {
15351547
auto Attr = cast<MacroRoleAttr>(this);
15361548

@@ -1913,6 +1925,13 @@ StringRef DeclAttribute::getAttrName() const {
19131925
case NonIsolatedModifier::NonSending:
19141926
return "nonisolated(nonsending)";
19151927
}
1928+
case DeclAttrKind::InheritActorContext:
1929+
switch (cast<InheritActorContextAttr>(this)->getModifier()) {
1930+
case InheritActorContextModifier::None:
1931+
return "_inheritActorContext";
1932+
case InheritActorContextModifier::Always:
1933+
return "_inheritActorContext(always)";
1934+
}
19161935
case DeclAttrKind::MacroRole:
19171936
switch (cast<MacroRoleAttr>(this)->getMacroSyntax()) {
19181937
case MacroSyntax::Freestanding:

lib/AST/Bridging/DeclAttributeBridging.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,25 @@ BridgedNonisolatedAttr_createParsed(BridgedASTContext cContext,
649649
/*implicit=*/false);
650650
}
651651

652+
static InheritActorContextModifier
653+
unbridged(BridgedInheritActorContextModifier modifier) {
654+
switch (modifier) {
655+
case BridgedInheritActorContextModifierNone:
656+
return InheritActorContextModifier::None;
657+
case BridgedInheritActorContextModifierAlways:
658+
return InheritActorContextModifier::Always;
659+
}
660+
llvm_unreachable("unhandled enum value");
661+
}
662+
663+
BridgedInheritActorContextAttr BridgedInheritActorContextAttr_createParsed(
664+
BridgedASTContext cContext, BridgedSourceLoc cAtLoc,
665+
BridgedSourceRange cRange, BridgedInheritActorContextModifier modifier) {
666+
return new (cContext.unbridged()) InheritActorContextAttr(
667+
cAtLoc.unbridged(), cRange.unbridged(), unbridged(modifier),
668+
/*implicit=*/false);
669+
}
670+
652671
BridgedObjCAttr
653672
BridgedObjCAttr_createParsedUnnamed(BridgedASTContext cContext,
654673
BridgedSourceLoc cAtLoc,

lib/AST/FeatureSet.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,21 @@ static bool usesFeatureAsyncExecutionBehaviorAttributes(Decl *decl) {
617617

618618
UNINTERESTING_FEATURE(BuiltinSelect)
619619

620+
static bool usesFeatureAlwaysInheritActorContext(Decl *decl) {
621+
auto *VD = dyn_cast<ValueDecl>(decl);
622+
if (!VD)
623+
return false;
624+
625+
if (auto *PL = VD->getParameterList()) {
626+
return llvm::any_of(*PL, [&](const ParamDecl *P) {
627+
auto *attr = P->getAttrs().getAttribute<InheritActorContextAttr>();
628+
return attr && attr->isAlways();
629+
});
630+
}
631+
632+
return false;
633+
}
634+
620635
// ----------------------------------------------------------------------------
621636
// MARK: - FeatureSet
622637
// ----------------------------------------------------------------------------

0 commit comments

Comments
 (0)