diff --git a/docs/ReferenceGuides/UnderscoredAttributes.md b/docs/ReferenceGuides/UnderscoredAttributes.md index 07d66bc5013b9..a9db7c7ea998e 100644 --- a/docs/ReferenceGuides/UnderscoredAttributes.md +++ b/docs/ReferenceGuides/UnderscoredAttributes.md @@ -600,6 +600,43 @@ inherit the actor context (i.e. what actor it should be run on) based on the declaration site of the closure rather than be non-Sendable. This does not do anything if the closure is synchronous. +This works with global actors as expected: + +```swift +@MainActor +func test() { + Task { /* main actor isolated */ } +} +``` + +However, for the inference to work with instance actors (i.e. `isolated` parameters), +the closure must capture the isolated parameter explicitly: + +```swift +func test(actor: isolated (any Actor)) { + Task { /* non isolated */ } // !!! +} + +func test(actor: isolated (any Actor)) { + Task { // @_inheritActorContext + _ = actor // 'actor'-isolated + } +} +``` + +The attribute takes an optional modifier '`always`', which changes this behavior +and *always* captures the enclosing isolated context, rather than forcing developers +to perform the explicit capture themselfes: + +```swift +func test(actor: isolated (any Actor)) { + Task.immediate { // @_inheritActorContext(always) + // 'actor'-isolated! + // (without having to capture 'actor explicitly') + } +} +``` + DISCUSSION: The reason why this does nothing when the closure is synchronous is since it does not have the ability to hop to the appropriate executor before it is run, so we may create concurrency errors. diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 4e4f477a463d3..2af46450c199e 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -1239,6 +1239,18 @@ BridgedNonisolatedAttr_createParsed(BridgedASTContext cContext, BridgedSourceRange cRange, BridgedNonIsolatedModifier modifier); +enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedInheritActorContextModifier { + BridgedInheritActorContextModifierNone, + BridgedInheritActorContextModifierAlways, +}; + +SWIFT_NAME("BridgedInheritActorContextAttr.createParsed(_:atLoc:range:modifier:)") +BridgedInheritActorContextAttr +BridgedInheritActorContextAttr_createParsed(BridgedASTContext cContext, + BridgedSourceLoc cAtLoc, + BridgedSourceRange cRange, + BridgedInheritActorContextModifier modifier); + SWIFT_NAME("BridgedObjCAttr.createParsedUnnamed(_:atLoc:attrNameLoc:)") BridgedObjCAttr BridgedObjCAttr_createParsedUnnamed(BridgedASTContext cContext, diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index d7f3eb1c7f7d0..db41cee73de9e 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -230,6 +230,10 @@ class DeclAttribute : public AttributeBase { Modifier : NumNonIsolatedModifierBits ); + SWIFT_INLINE_BITFIELD(InheritActorContextAttr, DeclAttribute, NumInheritActorContextKindBits, + Modifier : NumInheritActorContextKindBits + ); + SWIFT_INLINE_BITFIELD_FULL(AllowFeatureSuppressionAttr, DeclAttribute, 1+31, : NumPadBits, Inverted : 1, @@ -3004,6 +3008,50 @@ class NonisolatedAttr final : public DeclAttribute { } }; +/// Represents @_inheritActorContext modifier. +class InheritActorContextAttr final : public DeclAttribute { +public: + InheritActorContextAttr(SourceLoc atLoc, SourceRange range, + InheritActorContextModifier modifier, bool implicit) + : DeclAttribute(DeclAttrKind::InheritActorContext, atLoc, range, + implicit) { + Bits.InheritActorContextAttr.Modifier = static_cast(modifier); + assert((getModifier() == modifier) && "not enough bits for modifier"); + } + + InheritActorContextModifier getModifier() const { + return static_cast( + Bits.InheritActorContextAttr.Modifier); + } + + bool isAlways() const { + return getModifier() == InheritActorContextModifier::Always; + } + + static InheritActorContextAttr * + createImplicit(ASTContext &ctx, InheritActorContextModifier modifier = + InheritActorContextModifier::None) { + return new (ctx) + InheritActorContextAttr(/*atLoc*/ {}, /*range*/ {}, modifier, + /*implicit=*/true); + } + + static bool classof(const DeclAttribute *DA) { + return DA->getKind() == DeclAttrKind::InheritActorContext; + } + + /// Create a copy of this attribute. + InheritActorContextAttr *clone(ASTContext &ctx) const { + return new (ctx) + InheritActorContextAttr(AtLoc, Range, getModifier(), isImplicit()); + } + + bool isEquivalent(const InheritActorContextAttr *other, + Decl *attachedTo) const { + return getModifier() == other->getModifier(); + } +}; + /// A macro role attribute, spelled with either @attached or @freestanding, /// which declares one of the roles that a given macro can inhabit. class MacroRoleAttr final diff --git a/include/swift/AST/AttrKind.h b/include/swift/AST/AttrKind.h index 7ac94fb07c0e2..1d1a6226f7a91 100644 --- a/include/swift/AST/AttrKind.h +++ b/include/swift/AST/AttrKind.h @@ -142,6 +142,22 @@ enum : unsigned { static_cast(NonIsolatedModifier::Last_NonIsolatedModifier)) }; +enum class InheritActorContextModifier : uint8_t { + /// Inherit the actor execution context if the isolated parameter was + /// captured by the closure, context is nonisolated or isolated to a + /// global actor. + None = 0, + /// Always inherit the actor context, even when the isolated parameter + /// for the context is not closed over explicitly. + Always, + Last_InheritActorContextKind = Always +}; + +enum : unsigned { + NumInheritActorContextKindBits = countBitsUsed(static_cast( + InheritActorContextModifier::Last_InheritActorContextKind)) +}; + enum class DeclAttrKind : unsigned { #define DECL_ATTR(_, CLASS, ...) CLASS, #define LAST_DECL_ATTR(CLASS) Last_DeclAttr = CLASS, diff --git a/include/swift/AST/DeclAttr.def b/include/swift/AST/DeclAttr.def index 2c428aa9586fc..5d250a8e0fd03 100644 --- a/include/swift/AST/DeclAttr.def +++ b/include/swift/AST/DeclAttr.def @@ -619,9 +619,10 @@ SIMPLE_DECL_ATTR(_implicitSelfCapture, ImplicitSelfCapture, UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIBreakingToRemove | ForbiddenInABIAttr, 115) -SIMPLE_DECL_ATTR(_inheritActorContext, InheritActorContext, +DECL_ATTR(_inheritActorContext, InheritActorContext, OnParam, - UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIBreakingToRemove | ForbiddenInABIAttr, + // since the _inheritActorContext(always) forces an actor capture, it changes ABI of the closure this applies to + UserInaccessible | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove | UnconstrainedInABIAttr, 116) SIMPLE_DECL_ATTR(_eagerMove, EagerMove, diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 1ff5afaca3bee..19987ceb5a588 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8546,6 +8546,23 @@ GROUPED_ERROR(isolated_conformance_wrong_domain,IsolatedConformances,none, "%0 conformance of %1 to %2 cannot be used in %3 context", (ActorIsolation, Type, DeclName, ActorIsolation)) +//===----------------------------------------------------------------------===// +// MARK: @_inheritActorContext +//===----------------------------------------------------------------------===// +ERROR(inherit_actor_context_only_on_func_types,none, + "%0 only applies to parameters with function types (got: %1)", + (DeclAttribute, Type)) + +ERROR(inherit_actor_context_only_on_sending_or_Sendable_params,none, + "%0 only applies to 'sending' parameters or parameters with " + "'@Sendable' function types", + (DeclAttribute)) + +ERROR(inherit_actor_context_only_on_async_or_isolation_erased_params,none, + "%0 only applies to '@isolated(any)' parameters or parameters with " + "asynchronous function types", + (DeclAttribute)) + //===----------------------------------------------------------------------===// // MARK: @concurrent and nonisolated(nonsending) attributes //===----------------------------------------------------------------------===// diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 2d052da7ce819..fa7fc3664b083 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -267,7 +267,7 @@ class alignas(8) Expr : public ASTAllocated { Kind : 2 ); - SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1+1+1+1+1+1+1+1, + SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1+1+1+1+1+1+1+1+1, /// True if closure parameters were synthesized from anonymous closure /// variables. HasAnonymousClosureVars : 1, @@ -276,9 +276,11 @@ class alignas(8) Expr : public ASTAllocated { /// on each member reference. ImplicitSelfCapture : 1, - /// True if this @Sendable async closure parameter should implicitly - /// inherit the actor context from where it was formed. + /// True if this closure parameter should implicitly inherit the actor + /// context from where it was formed. InheritActorContext : 1, + /// The kind for inheritance - none or always at the moment. + InheritActorContextKind : 1, /// True if this closure's actor isolation behavior was determined by an /// \c \@preconcurrency declaration. @@ -4318,6 +4320,7 @@ class ClosureExpr : public AbstractClosureExpr { Bits.ClosureExpr.HasAnonymousClosureVars = false; Bits.ClosureExpr.ImplicitSelfCapture = false; Bits.ClosureExpr.InheritActorContext = false; + Bits.ClosureExpr.InheritActorContextKind = 0; Bits.ClosureExpr.IsPassedToSendingParameter = false; Bits.ClosureExpr.NoGlobalActorAttribute = false; Bits.ClosureExpr.RequiresDynamicIsolationChecking = false; @@ -4366,8 +4369,29 @@ class ClosureExpr : public AbstractClosureExpr { return Bits.ClosureExpr.InheritActorContext; } - void setInheritsActorContext(bool value = true) { + /// Whether this closure should _always_ implicitly inherit the actor context + /// regardless of whether the isolation parameter is captured or not. + bool alwaysInheritsActorContext() const { + if (!inheritsActorContext()) + return false; + return getInheritActorIsolationModifier() == + InheritActorContextModifier::Always; + } + + void setInheritsActorContext(bool value = true, + InheritActorContextModifier modifier = + InheritActorContextModifier::None) { Bits.ClosureExpr.InheritActorContext = value; + Bits.ClosureExpr.InheritActorContextKind = uint8_t(modifier); + assert((static_cast( + Bits.ClosureExpr.InheritActorContextKind) == modifier) && + "not enough bits for modifier"); + } + + InheritActorContextModifier getInheritActorIsolationModifier() const { + assert(inheritsActorContext()); + return static_cast( + Bits.ClosureExpr.InheritActorContextKind); } /// Whether the closure's concurrency behavior was determined by an diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index c4651036541ea..8be2729b9376a 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -325,6 +325,7 @@ IDENTIFIER(SerializationRequirement) IDENTIFIER_WITH_NAME(builderSelf, "$builderSelf") // Attribute options +IDENTIFIER(always) IDENTIFIER_(_always) IDENTIFIER_(assumed) IDENTIFIER(checked) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index b563d50c280bd..97411075d53ee 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -4045,6 +4045,7 @@ struct ParameterListInfo { SmallBitVector propertyWrappers; SmallBitVector implicitSelfCapture; SmallBitVector inheritActorContext; + SmallBitVector alwaysInheritActorContext; SmallBitVector variadicGenerics; SmallBitVector sendingParameters; @@ -4071,7 +4072,8 @@ struct ParameterListInfo { /// Whether the given parameter is a closure that should inherit the /// actor context from the context in which it was created. - bool inheritsActorContext(unsigned paramIdx) const; + std::pair + inheritsActorContext(unsigned paramIdx) const; bool isVariadicGenericParameter(unsigned paramIdx) const; diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index 2dae1663c8eea..bb878a287fa98 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -260,6 +260,7 @@ LANGUAGE_FEATURE(GeneralizedIsSameMetaTypeBuiltin, 465, "Builtin.is_same_metatyp LANGUAGE_FEATURE(ValueGenericsNameLookup, 452, "Value generics appearing as static members for namelookup") SUPPRESSIBLE_LANGUAGE_FEATURE(ABIAttributeSE0479, 479, "@abi attribute on functions, initializers, properties, and subscripts") LANGUAGE_FEATURE(BuiltinSelect, 0, "Builtin.select") +LANGUAGE_FEATURE(AlwaysInheritActorContext, 472, "@_inheritActorContext(always)") // Swift 6 UPCOMING_FEATURE(ConciseMagicFile, 274, 6) diff --git a/include/swift/Parse/IDEInspectionCallbacks.h b/include/swift/Parse/IDEInspectionCallbacks.h index 938083795af51..3605662f6ac1c 100644 --- a/include/swift/Parse/IDEInspectionCallbacks.h +++ b/include/swift/Parse/IDEInspectionCallbacks.h @@ -39,7 +39,8 @@ enum class ParameterizedDeclAttributeKind { Available, FreestandingMacro, AttachedMacro, - StorageRestrictions + StorageRestrictions, + InheritActorContext }; /// A bit of a hack. When completing inside the '@storageRestrictions' diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 98379320d7175..eeac331170169 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -4994,7 +4994,6 @@ class PrintAttribute : public AttributeVisitor, TRIVIAL_ATTR_PRINTER(ImplicitSelfCapture, implicit_self_capture) TRIVIAL_ATTR_PRINTER(Indirect, indirect) TRIVIAL_ATTR_PRINTER(Infix, infix) - TRIVIAL_ATTR_PRINTER(InheritActorContext, inherit_actor_context) TRIVIAL_ATTR_PRINTER(InheritsConvenienceInitializers, inherits_convenience_initializers) TRIVIAL_ATTR_PRINTER(Inlinable, inlinable) @@ -5317,6 +5316,12 @@ class PrintAttribute : public AttributeVisitor, printFlag(Attr->isNonSending(), "nonsending"); printFoot(); } + void visitInheritActorContextAttr(InheritActorContextAttr *Attr, + Label label) { + printCommon(Attr, "inherit_actor_context_attr", label); + printFlag(Attr->isAlways(), "always"); + printFoot(); + } void visitObjCAttr(ObjCAttr *Attr, Label label) { printCommon(Attr, "objc_attr", label); if (Attr->hasName()) diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 5e3f93ab8c77a..4b1e011441397 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -1531,6 +1531,18 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, break; } + case DeclAttrKind::InheritActorContext: { + Printer.printAttrName("@_inheritActorContext"); + switch (cast(this)->getModifier()) { + case InheritActorContextModifier::None: + break; + case InheritActorContextModifier::Always: + Printer << "(always)"; + break; + } + break; + } + case DeclAttrKind::MacroRole: { auto Attr = cast(this); @@ -1913,6 +1925,13 @@ StringRef DeclAttribute::getAttrName() const { case NonIsolatedModifier::NonSending: return "nonisolated(nonsending)"; } + case DeclAttrKind::InheritActorContext: + switch (cast(this)->getModifier()) { + case InheritActorContextModifier::None: + return "_inheritActorContext"; + case InheritActorContextModifier::Always: + return "_inheritActorContext(always)"; + } case DeclAttrKind::MacroRole: switch (cast(this)->getMacroSyntax()) { case MacroSyntax::Freestanding: diff --git a/lib/AST/Bridging/DeclAttributeBridging.cpp b/lib/AST/Bridging/DeclAttributeBridging.cpp index a9a6654dc2342..2e20415f509f9 100644 --- a/lib/AST/Bridging/DeclAttributeBridging.cpp +++ b/lib/AST/Bridging/DeclAttributeBridging.cpp @@ -649,6 +649,25 @@ BridgedNonisolatedAttr_createParsed(BridgedASTContext cContext, /*implicit=*/false); } +static InheritActorContextModifier +unbridged(BridgedInheritActorContextModifier modifier) { + switch (modifier) { + case BridgedInheritActorContextModifierNone: + return InheritActorContextModifier::None; + case BridgedInheritActorContextModifierAlways: + return InheritActorContextModifier::Always; + } + llvm_unreachable("unhandled enum value"); +} + +BridgedInheritActorContextAttr BridgedInheritActorContextAttr_createParsed( + BridgedASTContext cContext, BridgedSourceLoc cAtLoc, + BridgedSourceRange cRange, BridgedInheritActorContextModifier modifier) { + return new (cContext.unbridged()) InheritActorContextAttr( + cAtLoc.unbridged(), cRange.unbridged(), unbridged(modifier), + /*implicit=*/false); +} + BridgedObjCAttr BridgedObjCAttr_createParsedUnnamed(BridgedASTContext cContext, BridgedSourceLoc cAtLoc, diff --git a/lib/AST/FeatureSet.cpp b/lib/AST/FeatureSet.cpp index 77ef362183ac0..e859c8b742dd6 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -617,6 +617,21 @@ static bool usesFeatureAsyncExecutionBehaviorAttributes(Decl *decl) { UNINTERESTING_FEATURE(BuiltinSelect) +static bool usesFeatureAlwaysInheritActorContext(Decl *decl) { + auto *VD = dyn_cast(decl); + if (!VD) + return false; + + if (auto *PL = VD->getParameterList()) { + return llvm::any_of(*PL, [&](const ParamDecl *P) { + auto *attr = P->getAttrs().getAttribute(); + return attr && attr->isAlways(); + }); + } + + return false; +} + // ---------------------------------------------------------------------------- // MARK: - FeatureSet // ---------------------------------------------------------------------------- diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index e8d624ccc4b0b..70e1884d4fd45 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1353,6 +1353,7 @@ ParameterListInfo::ParameterListInfo( propertyWrappers.resize(params.size()); implicitSelfCapture.resize(params.size()); inheritActorContext.resize(params.size()); + alwaysInheritActorContext.resize(params.size()); variadicGenerics.resize(params.size()); sendingParameters.resize(params.size()); @@ -1409,8 +1410,13 @@ ParameterListInfo::ParameterListInfo( implicitSelfCapture.set(i); } - if (param->getAttrs().hasAttribute()) { - inheritActorContext.set(i); + if (auto *attr = + param->getAttrs().getAttribute()) { + if (attr->isAlways()) { + alwaysInheritActorContext.set(i); + } else { + inheritActorContext.set(i); + } } if (param->getInterfaceType()->is()) { @@ -1444,10 +1450,18 @@ bool ParameterListInfo::isImplicitSelfCapture(unsigned paramIdx) const { : false; } -bool ParameterListInfo::inheritsActorContext(unsigned paramIdx) const { - return paramIdx < inheritActorContext.size() - ? inheritActorContext[paramIdx] - : false; +std::pair +ParameterListInfo::inheritsActorContext(unsigned paramIdx) const { + if (paramIdx >= inheritActorContext.size()) + return std::make_pair(false, InheritActorContextModifier::None); + + if (inheritActorContext[paramIdx]) + return std::make_pair(true, InheritActorContextModifier::None); + + if (alwaysInheritActorContext[paramIdx]) + return std::make_pair(true, InheritActorContextModifier::Always); + + return std::make_pair(false, InheritActorContextModifier::None); } bool ParameterListInfo::isVariadicGenericParameter(unsigned paramIdx) const { diff --git a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift index 6e4cc53e0ff95..42b97f32de61c 100644 --- a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift @@ -247,7 +247,6 @@ extension ASTGenVisitor { .ibSegueAction, .implementationOnly, .implicitSelfCapture, - .inheritActorContext, .inheritsConvenienceInitializers, .inlinable, .isolated, @@ -310,6 +309,9 @@ extension ASTGenVisitor { case .referenceOwnership: // TODO: Diagnose. return handle(self.generateReferenceOwnershipAttr(attribute: node, attrName: attrName)?.asDeclAttribute) + case .inheritActorContext: + return handle(self.generateInheritActorContextAttr(attribute: node)?.asDeclAttribute) + case .async, .consuming, .borrowing, @@ -1409,6 +1411,28 @@ extension ASTGenVisitor { ) } + func generateInheritActorContextAttr(attribute node: AttributeSyntax) -> BridgedInheritActorContextAttr? { + let modifier: BridgedInheritActorContextModifier? = self.generateSingleAttrOption( + attribute: node, + { + switch $0.rawText { + case "always": return .always + default: return nil + } + }, + valueIfOmitted: BridgedInheritActorContextModifier.none + ) + guard let modifier else { + return nil + } + return .createParsed( + self.ctx, + atLoc: self.generateSourceLoc(node.atSign), + range: self.generateAttrSourceRange(node), + modifier: modifier + ) + } + /// E.g.: /// ``` /// @objc diff --git a/lib/IDE/CompletionLookup.cpp b/lib/IDE/CompletionLookup.cpp index 2dee28a4455bf..ab861f006e627 100644 --- a/lib/IDE/CompletionLookup.cpp +++ b/lib/IDE/CompletionLookup.cpp @@ -3141,6 +3141,9 @@ void CompletionLookup::getAttributeDeclParamCompletions( addDeclAttrParamKeyword("unsafe", /*Parameters=*/{}, "", false); addDeclAttrParamKeyword("nonsending", /*Parameters=*/{}, "", false); break; + case ParameterizedDeclAttributeKind::InheritActorContext: + addDeclAttrParamKeyword("always", /*Parameters=*/{}, "", false); + break; case ParameterizedDeclAttributeKind::AccessControl: addDeclAttrParamKeyword("set", /*Parameters=*/{}, "", false); break; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index c6e1776656047..2ff78c1f5fee7 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3772,6 +3772,25 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, } break; } + case DeclAttrKind::InheritActorContext: { + AttrRange = Loc; + std::optional Modifier( + InheritActorContextModifier::None); + Modifier = parseSingleAttrOption( + *this, Loc, AttrRange, AttrName, DK, + {{Context.Id_always, InheritActorContextModifier::Always}}, *Modifier, + ParameterizedDeclAttributeKind::InheritActorContext); + if (!Modifier) { + return makeParserSuccess(); + } + + if (!DiscardAttribute) { + Attributes.add(new (Context) InheritActorContextAttr( + AtLoc, AttrRange, *Modifier, /*implicit=*/false)); + } + + break; + } case DeclAttrKind::MacroRole: { auto syntax = (AttrName == "freestanding" ? MacroSyntax::Freestanding : MacroSyntax::Attached); diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index 231dee51708da..0a60c4fd449d1 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -4683,6 +4683,24 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) { collectConstantCaptures(fn); + // @_inheritActorContext(always) attribute allows implicit + // capture of isolation parameter from the context. This + // cannot be done as part of computing captures because + // isolation is not available at that point because it in + // turn depends on captures sometimes. + if (auto *closure = fn.getClosureExpr()) { + if (closure->alwaysInheritsActorContext()) { + auto isolation = closure->getActorIsolation(); + if (isolation.isActorInstanceIsolated()) { + if (auto *var = isolation.getActorInstance()) { + recordCapture(CapturedValue(var, /*flags=*/0, SourceLoc())); + } else if (auto *actorExpr = isolation.getActorInstanceExpr()) { + recordCapture(CapturedValue(actorExpr, /*flags=*/0)); + } + } + } + } + SmallVector resultingCaptures; for (auto capturePair : varCaptures) { resultingCaptures.push_back(capturePair.second); diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 373027547ba7e..1e11809c4f2b0 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -6109,15 +6109,20 @@ static bool hasCurriedSelf(ConstraintSystem &cs, ConcreteDeclRef callee, } /// Apply the contextually Sendable flag to the given expression, -static void applyContextualClosureFlags(Expr *expr, bool implicitSelfCapture, - bool inheritActorContext, - bool isPassedToSendingParameter, +static void applyContextualClosureFlags(Expr *expr, unsigned paramIdx, + const ParameterListInfo ¶mInfo, bool requiresDynamicIsolationChecking, bool isMacroArg) { if (auto closure = dyn_cast(expr)) { - closure->setAllowsImplicitSelfCapture(implicitSelfCapture); - closure->setInheritsActorContext(inheritActorContext); - closure->setIsPassedToSendingParameter(isPassedToSendingParameter); + closure->setAllowsImplicitSelfCapture( + paramInfo.isImplicitSelfCapture(paramIdx)); + + auto [inheritActorContext, modifier] = + paramInfo.inheritsActorContext(paramIdx); + closure->setInheritsActorContext(inheritActorContext, modifier); + + closure->setIsPassedToSendingParameter( + paramInfo.isSendingParameter(paramIdx)); closure->setRequiresDynamicIsolationChecking( requiresDynamicIsolationChecking); closure->setIsMacroArgument(isMacroArg); @@ -6125,19 +6130,14 @@ static void applyContextualClosureFlags(Expr *expr, bool implicitSelfCapture, } if (auto captureList = dyn_cast(expr)) { - applyContextualClosureFlags(captureList->getClosureBody(), - implicitSelfCapture, inheritActorContext, - isPassedToSendingParameter, - requiresDynamicIsolationChecking, + applyContextualClosureFlags(captureList->getClosureBody(), paramIdx, + paramInfo, requiresDynamicIsolationChecking, isMacroArg); } if (auto identity = dyn_cast(expr)) { - applyContextualClosureFlags(identity->getSubExpr(), implicitSelfCapture, - inheritActorContext, - isPassedToSendingParameter, - requiresDynamicIsolationChecking, - isMacroArg); + applyContextualClosureFlags(identity->getSubExpr(), paramIdx, paramInfo, + requiresDynamicIsolationChecking, isMacroArg); } } @@ -6263,19 +6263,13 @@ ArgumentList *ExprRewriter::coerceCallArguments( auto applyFlagsToArgument = [¶mInfo, &closuresRequireDynamicIsolationChecking, - &locator]( - unsigned paramIdx, Expr *argument) { + &locator](unsigned paramIdx, Expr *argument) { if (!isClosureLiteralExpr(argument)) return; - bool isImplicitSelfCapture = paramInfo.isImplicitSelfCapture(paramIdx); - bool inheritsActorContext = paramInfo.inheritsActorContext(paramIdx); - bool isPassedToSendingParameter = paramInfo.isSendingParameter(paramIdx); bool isMacroArg = isExpr(locator.getAnchor()); - applyContextualClosureFlags(argument, isImplicitSelfCapture, - inheritsActorContext, - isPassedToSendingParameter, + applyContextualClosureFlags(argument, paramIdx, paramInfo, closuresRequireDynamicIsolationChecking, isMacroArg); }; diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 531077ab215dd..2ac93bdda413a 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -184,7 +184,6 @@ class AttributeChecker : public AttributeVisitor { IGNORED_ATTR(AtRethrows) IGNORED_ATTR(AtReasync) IGNORED_ATTR(ImplicitSelfCapture) - IGNORED_ATTR(InheritActorContext) IGNORED_ATTR(Preconcurrency) IGNORED_ATTR(BackDeployed) IGNORED_ATTR(Documentation) @@ -418,8 +417,10 @@ class AttributeChecker : public AttributeVisitor { void visitNonisolatedAttr(NonisolatedAttr *attr); void visitIsolatedAttr(IsolatedAttr *attr); + void visitInheritActorContextAttr(InheritActorContextAttr *attr); + void visitNoImplicitCopyAttr(NoImplicitCopyAttr *attr); - + void visitAlwaysEmitConformanceMetadataAttr(AlwaysEmitConformanceMetadataAttr *attr); void visitExtractConstantsFromMembersAttr(ExtractConstantsFromMembersAttr *attr); @@ -7820,6 +7821,40 @@ void AttributeChecker::visitAsyncAttr(AsyncAttr *attr) { } } +void AttributeChecker::visitInheritActorContextAttr( + InheritActorContextAttr *attr) { + auto *P = dyn_cast(D); + if (!P) + return; + + auto paramTy = P->getInterfaceType(); + auto *funcTy = + paramTy->lookThroughAllOptionalTypes()->getAs(); + if (!funcTy) { + diagnoseAndRemoveAttr(attr, diag::inherit_actor_context_only_on_func_types, + attr, paramTy); + return; + } + + // The type has to be either `@Sendable` or `sending` _and_ + // `async` or `@isolated(any)`. + if (!(funcTy->isSendable() || P->isSending())) { + diagnose(attr->getLocation(), + diag::inherit_actor_context_only_on_sending_or_Sendable_params, + attr) + .warnUntilFutureSwiftVersion(); + } + + // Eiether `async` or `@isolated(any)`. + if (!(funcTy->isAsync() || funcTy->getIsolation().isErased())) { + diagnose( + attr->getLocation(), + diag::inherit_actor_context_only_on_async_or_isolation_erased_params, + attr) + .warnUntilFutureSwiftVersion(); + } +} + void AttributeChecker::visitMarkerAttr(MarkerAttr *attr) { auto proto = dyn_cast(D); if (!proto) diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index aa0671a2c17c1..2fa9f1d794bc5 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4801,6 +4801,16 @@ ActorIsolation ActorIsolationChecker::determineClosureIsolation( if (checkIsolatedCapture) { if (auto param = closure->getCaptureInfo().getIsolatedParamCapture()) return ActorIsolation::forActorInstanceCapture(param); + + auto *explicitClosure = dyn_cast(closure); + // @_inheritActorContext(always) forces the isolation capture. + if (explicitClosure && explicitClosure->alwaysInheritsActorContext()) { + if (parentIsolation.isActorInstanceIsolated()) { + if (auto *param = parentIsolation.getActorInstance()) + return ActorIsolation::forActorInstanceCapture(param); + } + return parentIsolation; + } } else { // If we don't have capture information during code completion, assume // that the closure captures the `isolated` parameter from the parent diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index c34c8f808be0c..9a8a2a6338d9a 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -6523,6 +6523,17 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() { break; } + case decls_block::InheritActorContext_DECL_ATTR: { + unsigned modifier; + bool isImplicit{}; + serialization::decls_block::InheritActorContextDeclAttrLayout:: + readRecord(scratch, modifier, isImplicit); + Attr = new (ctx) InheritActorContextAttr( + {}, {}, static_cast(modifier), + isImplicit); + break; + } + case decls_block::MacroRole_DECL_ATTR: { bool isImplicit; uint8_t rawMacroSyntax; diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 458c2c845c1db..ee17e4caf0904 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 940; // remove SwiftSettings +const uint16_t SWIFTMODULE_VERSION_MINOR = 941; // add modifier to @_inheritActorContext /// A standard hash seed used for all string hashes in a serialized module. /// @@ -2556,6 +2556,12 @@ namespace decls_block { BCFixed<1> // implicit flag >; + using InheritActorContextDeclAttrLayout = + BCRecordLayout, // the modifier (none = 0, always = 1) + BCFixed<1> // implicit flag + >; + using MacroRoleDeclAttrLayout = BCRecordLayout< MacroRole_DECL_ATTR, BCFixed<1>, // implicit flag diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 8954282808bb4..dac00f99a2413 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3473,6 +3473,16 @@ class Serializer::DeclSerializer : public DeclVisitor { return; } + case DeclAttrKind::InheritActorContext: { + auto *theAttr = cast(DA); + auto abbrCode = + S.DeclTypeAbbrCodes[InheritActorContextDeclAttrLayout::Code]; + InheritActorContextDeclAttrLayout::emitRecord( + S.Out, S.ScratchRecord, abbrCode, + static_cast(theAttr->getModifier()), theAttr->isImplicit()); + return; + } + case DeclAttrKind::MacroRole: { auto *theAttr = cast(DA); auto abbrCode = S.DeclTypeAbbrCodes[MacroRoleDeclAttrLayout::Code]; diff --git a/stdlib/public/Concurrency/Task+immediate.swift.gyb b/stdlib/public/Concurrency/Task+immediate.swift.gyb index 6381db9c968a5..8e48c7f72975b 100644 --- a/stdlib/public/Concurrency/Task+immediate.swift.gyb +++ b/stdlib/public/Concurrency/Task+immediate.swift.gyb @@ -38,9 +38,9 @@ extension Task where Failure == ${FAILURE_TYPE} { public static func startSynchronously( name: String? = nil, priority: TaskPriority? = nil, - @_implicitSelfCapture _ operation: __owned @isolated(any) @escaping () async throws -> Success + @_implicitSelfCapture @_inheritActorContext(always) _ operation: sending @isolated(any) @escaping () async throws -> Success ) -> Task { - immediate(name: name, priority: priority, operation) + immediate(name: name, priority: priority, operation: operation) } /// Create and immediately start running a new task in the context of the calling thread/task. @@ -66,13 +66,14 @@ extension Task where Failure == ${FAILURE_TYPE} { /// - operation: the operation to be run immediately upon entering the task. /// - Returns: A reference to the unstructured task which may be awaited on. @available(SwiftStdlib 6.2, *) + @_alwaysEmitIntoClient @discardableResult public static func immediate( name: String? = nil, priority: TaskPriority? = nil, % # NOTE: This closure cannot be 'sending' because we'll trigger ' pattern that the region based isolation checker does not understand how to check' % # In this case: `func syncOnMyGlobalActor() { Task.immediate { @MyGlobalActor in } }` - @_implicitSelfCapture _ operation: __owned @isolated(any) @escaping () async throws -> Success + @_implicitSelfCapture @_inheritActorContext(always) operation: sending @isolated(any) @escaping () async throws -> Success ) -> Task { let builtinSerialExecutor = @@ -188,6 +189,7 @@ extension ${GROUP_TYPE} { /// is semantically equivalent to its basic version which can be /// created using ``${GROUP_TYPE}/addTask``. @available(SwiftStdlib 6.2, *) + @_alwaysEmitIntoClient public func ${METHOD_NAME}( // in ${GROUP_TYPE} name: String? = nil, priority: TaskPriority? = nil, @@ -275,5 +277,7 @@ extension Task where Failure == ${FAILURE_TYPE} { @_silgen_name("swift_task_startOnMainActor") internal func _startTaskOnMainActor(_ task: Builtin.NativeObject) +@available(SwiftStdlib 6.2, *) @_silgen_name("swift_task_immediate") +@usableFromInline internal func _startTaskImmediately(_ task: Builtin.NativeObject, targetExecutor: Builtin.Executor?) diff --git a/test/ASTGen/attrs.swift b/test/ASTGen/attrs.swift index 9b9c3aba5e497..a223977aa26f2 100644 --- a/test/ASTGen/attrs.swift +++ b/test/ASTGen/attrs.swift @@ -256,3 +256,6 @@ struct LayoutOuter { struct AnyEraser: EraserProto { init(erasing: T) {} } + +func takeNone(@_inheritActorContext param: @Sendable () async -> ()) { } +func takeAlways(@_inheritActorContext(always) param: sending @isolated(any) () -> ()) { } diff --git a/test/Concurrency/Runtime/startImmediately.swift b/test/Concurrency/Runtime/startImmediately.swift index 629fa9f20a640..5951ed30a2149 100644 --- a/test/Concurrency/Runtime/startImmediately.swift +++ b/test/Concurrency/Runtime/startImmediately.swift @@ -1,6 +1,3 @@ -// FIXME: Marking this disabled since we're reworking the semantics and the test is a bit racy until we do -// REQUIRES: rdar149506152 - // RUN: %empty-directory(%t) // RUN: %target-build-swift -Xfrontend -disable-availability-checking %s %import-libdispatch -swift-version 6 -o %t/a.out // RUN: %target-codesign %t/a.out diff --git a/test/Concurrency/actor_isolation.swift b/test/Concurrency/actor_isolation.swift index 19e1adf9c5945..0c44bb5af784c 100644 --- a/test/Concurrency/actor_isolation.swift +++ b/test/Concurrency/actor_isolation.swift @@ -1210,6 +1210,8 @@ actor MyServer : Server { func acceptAsyncSendableClosure(_: @Sendable () async -> T) { } @available(SwiftStdlib 5.1, *) func acceptAsyncSendableClosureInheriting(@_inheritActorContext _: @Sendable () async -> T) { } +@available(SwiftStdlib 5.1, *) +func acceptAsyncSendableClosureInheritingAlways(@_inheritActorContext(always) _: @Sendable () async -> T) { } @available(SwiftStdlib 5.1, *) extension MyActor { @@ -1237,6 +1239,10 @@ extension MyActor { _ = await synchronous() // expected-warning{{no 'async' operations occur within 'await' expression}} counter += 1 // okay } + + acceptAsyncSendableClosureInheritingAlways { + counter += 1 // Ok + } } } @@ -1257,6 +1263,32 @@ func testGlobalActorInheritance() { acceptAsyncSendableClosureInheriting { counter += 1 // ok } + + acceptAsyncSendableClosureInheritingAlways { + counter += 1 // ok + } +} + +@available(SwiftStdlib 5.1, *) +func testIsolatedParameter1(_: isolated any Actor, v: inout Int) { + acceptAsyncSendableClosureInheriting { + v += 1 // expected-warning {{mutable capture of 'inout' parameter 'v' is not allowed in concurrently-executing code}} + } + + acceptAsyncSendableClosureInheritingAlways { + v += 1 // Ok + } +} + +@available(SwiftStdlib 5.1, *) +func testIsolatedParameter2(_: isolated (any Actor)? = #isolation, v: inout Int) { + acceptAsyncSendableClosureInheriting { + v += 1 // expected-warning {{mutable capture of 'inout' parameter 'v' is not allowed in concurrently-executing code}} + } + + acceptAsyncSendableClosureInheritingAlways { + v += 1 // Ok + } } @available(SwiftStdlib 5.1, *) @@ -1763,4 +1795,4 @@ actor UserDefinedActorSelfDotMethod { // error message changes with InferSendabaleFromCaptures - see actor_isolation_swift6.swift return functionRef // expected-error {{cannot convert return expression of type '(isolated Self) -> () -> ()' to return type '(UserDefinedActorSelfDotMethod) -> @isolated(any) () -> Void'}} } -} \ No newline at end of file +} diff --git a/test/Concurrency/startImmediatelyIsolation.swift b/test/Concurrency/startImmediatelyIsolation.swift index d864285757a85..fc2d843eb9884 100644 --- a/test/Concurrency/startImmediatelyIsolation.swift +++ b/test/Concurrency/startImmediatelyIsolation.swift @@ -38,3 +38,14 @@ func async() async throws { group.addImmediateTaskUnlessCancelled { () async throws -> Void in } } } + +@available(SwiftStdlib 6.2, *) +actor TestSelfCapture { + func method() {} + + func test() { + Task.immediate { + method() // Ok due to `@_implicitSelfCapture` + } + } +} diff --git a/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift b/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift index e073badfbf2ac..0c52bb1d73cbd 100644 --- a/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift +++ b/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift @@ -24,10 +24,6 @@ func normalAcceptsClosure(_ x: () -> ()) {} func normalAcceptsSendingClosure(_ x: sending () -> ()) {} func normalAcceptsSendableClosure(_ x: @Sendable () -> ()) {} -func inheritActorContextAcceptsClosure(@_inheritActorContext _ x: () -> ()) { } -func inheritActorContextAcceptsSendingClosure(@_inheritActorContext _ x: sending () -> ()) { } -func inheritActorContextAcceptsSendableClosure(@_inheritActorContext _ x: @Sendable () -> ()) { } - @MainActor func normalGlobalActorAcceptsClosure(_ x: () -> ()) { } @MainActor @@ -35,18 +31,10 @@ func normalGlobalActorAcceptsSendingClosure(_ x: sending () -> ()) { } @MainActor func normalGlobalActorAcceptsSendableClosure(_ x: @Sendable () -> ()) { } -@MainActor -func inheritActorContextGlobalActorAcceptsClosure(@_inheritActorContext _ x: () -> ()) { } -@MainActor -func inheritActorContextGlobalActorAcceptsSendingClosure(@_inheritActorContext _ x: sending () -> ()) { } -@MainActor -func inheritActorContextGlobalActorAcceptsSendableClosure(@_inheritActorContext _ x: @Sendable () -> ()) { } - func normalAcceptsAsyncClosure(_ x: () async -> ()) {} func normalAcceptsSendingAsyncClosure(_ x: sending () async -> ()) {} func normalAcceptsSendableAsyncClosure(_ x: @Sendable () async -> ()) {} -func inheritActorContextAcceptsAsyncClosure(@_inheritActorContext _ x: () async -> ()) { } func inheritActorContextAcceptsSendingAsyncClosure(@_inheritActorContext _ x: sending () async -> ()) { } func inheritActorContextAcceptsSendableAsyncClosure(@_inheritActorContext _ x: @Sendable () async -> ()) { } @@ -57,8 +45,6 @@ func normalGlobalActorAcceptsSendingAsyncClosure(_ x: sending () async -> ()) { @MainActor func normalGlobalActorAcceptsSendableAsyncClosure(_ x: @Sendable () async -> ()) { } -@MainActor -func inheritActorContextGlobalActorAcceptsAsyncClosure(@_inheritActorContext _ x: () async -> ()) { } @MainActor func inheritActorContextGlobalActorAcceptsSendingAsyncClosure(@_inheritActorContext _ x: sending () async -> ()) { } @MainActor @@ -68,10 +54,6 @@ func asyncNormalAcceptsClosure(_ x: () -> ()) async {} func asyncNormalAcceptsSendingClosure(_ x: sending () -> ()) async {} func asyncNormalAcceptsSendableClosure(_ x: @Sendable () -> ()) async {} -func asyncInheritActorContextAcceptsClosure(@_inheritActorContext _ x: () -> ()) async {} -func asyncInheritActorContextAcceptsSendingClosure(@_inheritActorContext _ x: sending () -> ()) async {} -func asyncInheritActorContextAcceptsSendableClosure(@_inheritActorContext _ x: @Sendable () -> ()) async {} - @MainActor func asyncNormalGlobalActorAcceptsClosure(_ x: () -> ()) async {} @MainActor @@ -79,18 +61,10 @@ func asyncNormalGlobalActorAcceptsSendingClosure(_ x: sending () -> ()) async {} @MainActor func asyncNormalGlobalActorAcceptsSendableClosure(_ x: @Sendable () -> ()) async {} -@MainActor -func asyncInheritActorContextGlobalActorAcceptsClosure(@_inheritActorContext _ x: () -> ()) async {} -@MainActor -func asyncInheritActorContextGlobalActorAcceptsSendingClosure(@_inheritActorContext _ x: sending () -> ()) async {} -@MainActor -func asyncInheritActorContextGlobalActorAcceptsSendableClosure(@_inheritActorContext _ x: @Sendable () -> ()) async {} - func asyncNormalAcceptsAsyncClosure(_ x: () async -> ()) async {} func asyncNormalAcceptsSendingAsyncClosure(_ x: sending () async -> ()) async {} func asyncNormalAcceptsSendableAsyncClosure(_ x: @Sendable () async -> ()) async {} -func asyncInheritActorContextAcceptsAsyncClosure(@_inheritActorContext _ x: () async -> ()) async {} func asyncInheritActorContextAcceptsSendingAsyncClosure(@_inheritActorContext _ x: sending () async -> ()) async {} func asyncInheritActorContextAcceptsSendableAsyncClosure(@_inheritActorContext _ x: @Sendable () async -> ()) async {} @@ -101,8 +75,6 @@ func asyncNormalGlobalActorAcceptsSendingAsyncClosure(_ x: sending () async -> ( @MainActor func asyncNormalGlobalActorAcceptsSendableAsyncClosure(_ x: @Sendable () async -> ()) async {} -@MainActor -func asyncInheritActorContextGlobalActorAcceptsAsyncClosure(@_inheritActorContext _ x: () async -> ()) async {} @MainActor func asyncInheritActorContextGlobalActorAcceptsSendingAsyncClosure(@_inheritActorContext _ x: sending () async -> ()) async {} @MainActor @@ -138,26 +110,6 @@ func test_CallerSyncNormal_CalleeSyncNonIsolated() async { normalAcceptsSendableClosure { } } -@CustomActor -func test_CallerSyncInheritsActorContext_CalleeSyncNonisolated() { - // CHECK: } // end sil function '$s54transfernonsendable_closureliterals_isolationinference042test_CallerSyncInheritsActorContext_CalleeF11NonisolatedyyF' - - // CHECK-LABEL: // closure #1 in test_CallerSyncInheritsActorContext_CalleeSyncNonisolated() - // CHECK-NEXT: // Isolation: global_actor. type: CustomActor - inheritActorContextAcceptsClosure { } - - // This is a synchronous closure, so we error here. - // - // CHECK-LABEL: // closure #2 in test_CallerSyncInheritsActorContext_CalleeSyncNonisolated() - // CHECK-NEXT: // Isolation: global_actor. type: CustomActor - inheritActorContextAcceptsSendingClosure { } // expected-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} - // expected-note @-1 {{Passing global actor 'CustomActor'-isolated value of non-Sendable type '() -> ()' as a 'sending' parameter to global function 'inheritActorContextAcceptsSendingClosure' risks causing races inbetween global actor 'CustomActor'-isolated uses and uses reachable from 'inheritActorContextAcceptsSendingClosure'}} - - // CHECK-LABEL: // closure #3 in test_CallerSyncInheritsActorContext_CalleeSyncNonisolated() - // CHECK-NEXT: // Isolation: global_actor. type: CustomActor - inheritActorContextAcceptsSendableClosure { } -} - @CustomActor func test_CallerSyncNormal_CalleeSyncMainActorIsolated() async { // CHECK-LABEL: } // end sil function '$s54transfernonsendable_closureliterals_isolationinference028test_CallerSyncNormal_CalleeF17MainActorIsolatedyyYaF' @@ -176,27 +128,6 @@ func test_CallerSyncNormal_CalleeSyncMainActorIsolated() async { await normalGlobalActorAcceptsSendableClosure { } } -@CustomActor -func test_CallerSyncInheritsActorContext_CalleeSyncMainActorIsolated() async { - // CHECK-LABEL: } // end sil function '$s54transfernonsendable_closureliterals_isolationinference042test_CallerSyncInheritsActorContext_Calleef4MainH8IsolatedyyYaF' - - // CHECK-LABEL: // closure #1 in test_CallerSyncInheritsActorContext_CalleeSyncMainActorIsolated() - // CHECK-NEXT: // Isolation: global_actor. type: CustomActor - await inheritActorContextGlobalActorAcceptsClosure { } // expected-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} - // expected-note @-1 {{sending global actor 'CustomActor'-isolated value of non-Sendable type '() -> ()' to main actor-isolated global function 'inheritActorContextGlobalActorAcceptsClosure' risks causing races in between global actor 'CustomActor'-isolated and main actor-isolated uses}} - - // This is a synchronous closure, so we error here. - // - // CHECK-LABEL: // closure #2 in test_CallerSyncInheritsActorContext_CalleeSyncMainActorIsolated() - // CHECK-NEXT: // Isolation: global_actor. type: CustomActor - await inheritActorContextGlobalActorAcceptsSendingClosure { } // expected-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} - // expected-note @-1 {{Passing global actor 'CustomActor'-isolated value of non-Sendable type '() -> ()' as a 'sending' parameter to global function 'inheritActorContextGlobalActorAcceptsSendingClosure' risks causing races inbetween global actor 'CustomActor'-isolated uses and uses reachable from 'inheritActorContextGlobalActorAcceptsSendingClosure'}} - - // CHECK-LABEL: // closure #3 in test_CallerSyncInheritsActorContext_CalleeSyncMainActorIsolated() - // CHECK-NEXT: // Isolation: global_actor. type: CustomActor - await inheritActorContextGlobalActorAcceptsSendableClosure { } -} - //////////////////////////////////////////////// // MARK: Global Actor Sync User Async Closure // //////////////////////////////////////////////// @@ -223,13 +154,9 @@ func test_CallerSyncInheritsActorContext_CalleeAsyncNonisolated() { // CHECK-LABEL: // closure #1 in test_CallerSyncInheritsActorContext_CalleeAsyncNonisolated() // CHECK-NEXT: // Isolation: global_actor. type: CustomActor - inheritActorContextAcceptsAsyncClosure { } - - // CHECK-LABEL: // closure #2 in test_CallerSyncInheritsActorContext_CalleeAsyncNonisolated() - // CHECK-NEXT: // Isolation: global_actor. type: CustomActor inheritActorContextAcceptsSendingAsyncClosure { } - // CHECK-LABEL: // closure #3 in test_CallerSyncInheritsActorContext_CalleeAsyncNonisolated() + // CHECK-LABEL: // closure #2 in test_CallerSyncInheritsActorContext_CalleeAsyncNonisolated() // CHECK-NEXT: // Isolation: global_actor. type: CustomActor inheritActorContextAcceptsSendableAsyncClosure { } } @@ -258,13 +185,9 @@ func test_CallerSyncInheritsActorContext_CalleeAsyncMainActorIsolated() async { // CHECK-LABEL: // closure #1 in test_CallerSyncInheritsActorContext_CalleeAsyncMainActorIsolated() // CHECK-NEXT: // Isolation: global_actor. type: CustomActor - await inheritActorContextGlobalActorAcceptsAsyncClosure { } - - // CHECK-LABEL: // closure #2 in test_CallerSyncInheritsActorContext_CalleeAsyncMainActorIsolated() - // CHECK-NEXT: // Isolation: global_actor. type: CustomActor await inheritActorContextGlobalActorAcceptsSendingAsyncClosure { } - // CHECK-LABEL: // closure #3 in test_CallerSyncInheritsActorContext_CalleeAsyncMainActorIsolated() + // CHECK-LABEL: // closure #2 in test_CallerSyncInheritsActorContext_CalleeAsyncMainActorIsolated() // CHECK-NEXT: // Isolation: global_actor. type: CustomActor await inheritActorContextGlobalActorAcceptsSendableAsyncClosure { } } @@ -293,27 +216,6 @@ func test_CallerAsyncNormal_CalleeSyncNonIsolated() async { await asyncNormalAcceptsSendableClosure { } } -@CustomActor -func test_CallerAsyncInheritsActorContext_CalleeSyncNonisolated() async { - // CHECK: } // end sil function '$s54transfernonsendable_closureliterals_isolationinference58test_CallerAsyncInheritsActorContext_CalleeSyncNonisolatedyyYaF' - - // CHECK-LABEL: // closure #1 in test_CallerAsyncInheritsActorContext_CalleeSyncNonisolated() - // CHECK-NEXT: // Isolation: global_actor. type: CustomActor - await asyncInheritActorContextAcceptsClosure { } // expected-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} - // expected-note @-1 {{sending global actor 'CustomActor'-isolated value of non-Sendable type '() -> ()' to nonisolated global function 'asyncInheritActorContextAcceptsClosure' risks causing races in between global actor 'CustomActor'-isolated and nonisolated uses}} - - // This is a synchronous closure, so we error here. - // - // CHECK-LABEL: // closure #2 in test_CallerAsyncInheritsActorContext_CalleeSyncNonisolated() - // CHECK-NEXT: // Isolation: global_actor. type: CustomActor - await asyncInheritActorContextAcceptsSendingClosure { } // expected-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} - // expected-note @-1 {{Passing global actor 'CustomActor'-isolated value of non-Sendable type '() -> ()' as a 'sending' parameter to global function 'asyncInheritActorContextAcceptsSendingClosure' risks causing races inbetween global actor 'CustomActor'-isolated uses and uses reachable from 'asyncInheritActorContextAcceptsSendingClosure'}} - - // CHECK-LABEL: // closure #3 in test_CallerAsyncInheritsActorContext_CalleeSyncNonisolated() - // CHECK-NEXT: // Isolation: global_actor. type: CustomActor - await asyncInheritActorContextAcceptsSendableClosure { } -} - @CustomActor func test_CallerAsyncNormal_CalleeSyncMainActorIsolated() async { // CHECK-LABEL: } // end sil function '$s54transfernonsendable_closureliterals_isolationinference50test_CallerAsyncNormal_CalleeSyncMainActorIsolatedyyYaF' @@ -332,27 +234,6 @@ func test_CallerAsyncNormal_CalleeSyncMainActorIsolated() async { await asyncNormalGlobalActorAcceptsSendableClosure { } } -@CustomActor -func test_CallerAsyncInheritsActorContext_CalleeSyncMainActorIsolated() async { - // CHECK-LABEL: } // end sil function '$s54transfernonsendable_closureliterals_isolationinference051test_CallerAsyncInheritsActorContext_CalleeSyncMainH8IsolatedyyYaF' - - // CHECK-LABEL: // closure #1 in test_CallerAsyncInheritsActorContext_CalleeSyncMainActorIsolated() - // CHECK-NEXT: // Isolation: global_actor. type: CustomActor - await asyncInheritActorContextGlobalActorAcceptsClosure { } // expected-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} - // expected-note @-1 {{sending global actor 'CustomActor'-isolated value of non-Sendable type '() -> ()' to main actor-isolated global function 'asyncInheritActorContextGlobalActorAcceptsClosure' risks causing races in between global actor 'CustomActor'-isolated and main actor-isolated uses}} - - // This is a synchronous closure, so we error here. - // - // CHECK-LABEL: // closure #2 in test_CallerAsyncInheritsActorContext_CalleeSyncMainActorIsolated() - // CHECK-NEXT: // Isolation: global_actor. type: CustomActor - await asyncInheritActorContextGlobalActorAcceptsSendingClosure { } // expected-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} - // expected-note @-1 {{Passing global actor 'CustomActor'-isolated value of non-Sendable type '() -> ()' as a 'sending' parameter to global function 'asyncInheritActorContextGlobalActorAcceptsSendingClosure' risks causing races inbetween global actor 'CustomActor'-isolated uses and uses reachable from 'asyncInheritActorContextGlobalActorAcceptsSendingClosure'}} - - // CHECK-LABEL: // closure #3 in test_CallerAsyncInheritsActorContext_CalleeSyncMainActorIsolated() - // CHECK-NEXT: // Isolation: global_actor. type: CustomActor - await asyncInheritActorContextGlobalActorAcceptsSendableClosure { } -} - ///////////////////////////////////////////////// // MARK: Global Actor Async User Async Closure // ///////////////////////////////////////////////// @@ -381,21 +262,17 @@ func test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() async { // CHECK-LABEL: // closure #1 in test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() // CHECK-NEXT: // Isolation: global_actor. type: CustomActor - await asyncInheritActorContextAcceptsAsyncClosure { } - - // CHECK-LABEL: // closure #2 in test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() - // CHECK-NEXT: // Isolation: global_actor. type: CustomActor await asyncInheritActorContextAcceptsSendingAsyncClosure { } - // CHECK-LABEL: // closure #3 in test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() + // CHECK-LABEL: // closure #2 in test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() // CHECK-NEXT: // Isolation: global_actor. type: CustomActor await asyncInheritActorContextAcceptsSendingAsyncClosure { @CustomActor in } - // CHECK-LABEL: // closure #4 in test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() + // CHECK-LABEL: // closure #3 in test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() // CHECK-NEXT: // Isolation: global_actor. type: MainActor await asyncInheritActorContextAcceptsSendingAsyncClosure { @MainActor in } - // CHECK-LABEL: // closure #5 in test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() + // CHECK-LABEL: // closure #4 in test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() // CHECK-NEXT: // Isolation: global_actor. type: CustomActor await asyncInheritActorContextAcceptsSendableAsyncClosure { } } @@ -424,21 +301,17 @@ func test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() async { // CHECK-LABEL: // closure #1 in test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() // CHECK-NEXT: // Isolation: global_actor. type: CustomActor - await asyncInheritActorContextGlobalActorAcceptsAsyncClosure { } - - // CHECK-LABEL: // closure #2 in test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() - // CHECK-NEXT: // Isolation: global_actor. type: CustomActor await asyncInheritActorContextGlobalActorAcceptsSendingAsyncClosure { } - // CHECK-LABEL: // closure #3 in test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() + // CHECK-LABEL: // closure #2 in test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() // CHECK-NEXT: // Isolation: global_actor. type: CustomActor await asyncInheritActorContextGlobalActorAcceptsSendingAsyncClosure { @CustomActor in } - // CHECK-LABEL: // closure #4 in test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() + // CHECK-LABEL: // closure #3 in test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() // CHECK-NEXT: // Isolation: global_actor. type: MainActor await asyncInheritActorContextGlobalActorAcceptsSendingAsyncClosure { @MainActor in } - // CHECK-LABEL: // closure #5 in test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() + // CHECK-LABEL: // closure #4 in test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() // CHECK-NEXT: // Isolation: global_actor. type: CustomActor await asyncInheritActorContextGlobalActorAcceptsSendableAsyncClosure { } } @@ -464,26 +337,6 @@ extension MyActor { normalAcceptsSendableClosure { print(self) } } - func test_CallerSyncInheritsActorContext_CalleeSyncNonisolated() { - // CHECK: } // end sil function '$s54transfernonsendable_closureliterals_isolationinference7MyActorC023test_CallerSyncInheritse14Context_CalleeH11NonisolatedyyF' - - // CHECK-LABEL: // closure #1 in MyActor.test_CallerSyncInheritsActorContext_CalleeSyncNonisolated() - // CHECK-NEXT: // Isolation: actor_instance. name: 'self' - inheritActorContextAcceptsClosure { print(self) } - - // This is a synchronous closure, so we error here. - // - // CHECK-LABEL: // closure #2 in MyActor.test_CallerSyncInheritsActorContext_CalleeSyncNonisolated() - // CHECK-NEXT: // Isolation: actor_instance. name: 'self' - inheritActorContextAcceptsSendingClosure { // expected-error {{passing closure as a 'sending' parameter risks causing data races between 'self'-isolated code and concurrent execution of the closure}} - print(self) // expected-note {{closure captures 'self'}} - } - - // CHECK-LABEL: // closure #3 in MyActor.test_CallerSyncInheritsActorContext_CalleeSyncNonisolated() - // CHECK-NEXT: // Isolation: actor_instance. name: 'self' - inheritActorContextAcceptsSendableClosure { print(self) } - } - func test_CallerSyncNormal_CalleeSyncMainActorIsolated() async { // CHECK-LABEL: } // end sil function '$s54transfernonsendable_closureliterals_isolationinference7MyActorC028test_CallerSyncNormal_Calleeh4MainE8IsolatedyyYaF' @@ -500,27 +353,6 @@ extension MyActor { // CHECK-NEXT: // Isolation: nonisolated await normalGlobalActorAcceptsSendableClosure { print(self) } } - - func test_CallerSyncInheritsActorContext_CalleeSyncMainActorIsolated() async { - // CHECK-LABEL: } // end sil function '$s54transfernonsendable_closureliterals_isolationinference7MyActorC023test_CallerSyncInheritse14Context_Calleeh4MainE8IsolatedyyYaF' - - // CHECK-LABEL: // closure #1 in MyActor.test_CallerSyncInheritsActorContext_CalleeSyncMainActorIsolated() - // CHECK-NEXT: // Isolation: actor_instance. name: 'self' - await inheritActorContextGlobalActorAcceptsClosure { print(self) } // expected-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} - // expected-note @-1 {{sending 'self'-isolated value of non-Sendable type '() -> ()' to main actor-isolated global function 'inheritActorContextGlobalActorAcceptsClosure' risks causing races in between 'self'-isolated and main actor-isolated uses}} - - // This is a synchronous closure, so we error here. - // - // CHECK-LABEL: // closure #2 in MyActor.test_CallerSyncInheritsActorContext_CalleeSyncMainActorIsolated() - // CHECK-NEXT: // Isolation: actor_instance. name: 'self' - await inheritActorContextGlobalActorAcceptsSendingClosure { // expected-error {{passing closure as a 'sending' parameter risks causing data races between 'self'-isolated code and concurrent execution of the closure}} - print(self) // expected-note {{closure captures 'self'}} - } - - // CHECK-LABEL: // closure #3 in MyActor.test_CallerSyncInheritsActorContext_CalleeSyncMainActorIsolated() - // CHECK-NEXT: // Isolation: actor_instance. name: 'self' - await inheritActorContextGlobalActorAcceptsSendableClosure { print(self) } - } } ////////////////////////////////////////////////// @@ -550,13 +382,9 @@ extension MyActor { // CHECK-LABEL: // closure #1 in MyActor.test_CallerSyncInheritsActorContext_CalleeAsyncNonisolated() // CHECK-NEXT: // Isolation: actor_instance. name: 'self' - inheritActorContextAcceptsAsyncClosure { print(self) } - - // CHECK-LABEL: // closure #2 in MyActor.test_CallerSyncInheritsActorContext_CalleeAsyncNonisolated() - // CHECK-NEXT: // Isolation: actor_instance. name: 'self' inheritActorContextAcceptsSendingAsyncClosure { print(self) } - // CHECK-LABEL: // closure #3 in MyActor.test_CallerSyncInheritsActorContext_CalleeAsyncNonisolated() + // CHECK-LABEL: // closure #2 in MyActor.test_CallerSyncInheritsActorContext_CalleeAsyncNonisolated() // CHECK-NEXT: // Isolation: actor_instance. name: 'self' inheritActorContextAcceptsSendableAsyncClosure { print(self) } } @@ -583,13 +411,9 @@ extension MyActor { // CHECK-LABEL: // closure #1 in MyActor.test_CallerSyncInheritsActorContext_CalleeAsyncMainActorIsolated() // CHECK-NEXT: // Isolation: actor_instance. name: 'self' - await inheritActorContextGlobalActorAcceptsAsyncClosure { print(self) } - - // CHECK-LABEL: // closure #2 in MyActor.test_CallerSyncInheritsActorContext_CalleeAsyncMainActorIsolated() - // CHECK-NEXT: // Isolation: actor_instance. name: 'self' await inheritActorContextGlobalActorAcceptsSendingAsyncClosure { print(self) } - // CHECK-LABEL: // closure #3 in MyActor.test_CallerSyncInheritsActorContext_CalleeAsyncMainActorIsolated() + // CHECK-LABEL: // closure #2 in MyActor.test_CallerSyncInheritsActorContext_CalleeAsyncMainActorIsolated() // CHECK-NEXT: // Isolation: actor_instance. name: 'self' await inheritActorContextGlobalActorAcceptsSendableAsyncClosure { print(self) } } @@ -620,27 +444,6 @@ extension MyActor { await asyncNormalAcceptsSendableClosure { print(self) } } - func test_CallerAsyncInheritsActorContext_CalleeSyncNonisolated() async { - // CHECK: } // end sil function '$s54transfernonsendable_closureliterals_isolationinference7MyActorC024test_CallerAsyncInheritsE29Context_CalleeSyncNonisolatedyyYaF' - - // CHECK-LABEL: // closure #1 in MyActor.test_CallerAsyncInheritsActorContext_CalleeSyncNonisolated() - // CHECK-NEXT: // Isolation: actor_instance. name: 'self' - await asyncInheritActorContextAcceptsClosure { print(self) } // expected-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} - // expected-note @-1 {{sending 'self'-isolated value of non-Sendable type '() -> ()' to nonisolated global function 'asyncInheritActorContextAcceptsClosure' risks causing races in between 'self'-isolated and nonisolated uses}} - - // This is a synchronous closure, so we error here. - // - // CHECK-LABEL: // closure #2 in MyActor.test_CallerAsyncInheritsActorContext_CalleeSyncNonisolated() - // CHECK-NEXT: // Isolation: actor_instance. name: 'self' - await asyncInheritActorContextAcceptsSendingClosure { // expected-error {{passing closure as a 'sending' parameter risks causing data races between 'self'-isolated code and concurrent execution of the closure}} - print(self) // expected-note {{closure captures 'self'}} - } - - // CHECK-LABEL: // closure #3 in MyActor.test_CallerAsyncInheritsActorContext_CalleeSyncNonisolated() - // CHECK-NEXT: // Isolation: actor_instance. name: 'self' - await asyncInheritActorContextAcceptsSendableClosure { print(self) } - } - func test_CallerAsyncNormal_CalleeSyncMainActorIsolated() async { // CHECK-LABEL: } // end sil function '$s54transfernonsendable_closureliterals_isolationinference7MyActorC037test_CallerAsyncNormal_CalleeSyncMainE8IsolatedyyYaF' @@ -657,27 +460,6 @@ extension MyActor { // CHECK-NEXT: // Isolation: nonisolated await asyncNormalGlobalActorAcceptsSendableClosure { print(self) } } - - func test_CallerAsyncInheritsActorContext_CalleeSyncMainActorIsolated() async { - // CHECK-LABEL: } // end sil function '$s54transfernonsendable_closureliterals_isolationinference7MyActorC024test_CallerAsyncInheritse22Context_CalleeSyncMainE8IsolatedyyYaF' - - // CHECK-LABEL: // closure #1 in MyActor.test_CallerAsyncInheritsActorContext_CalleeSyncMainActorIsolated() - // CHECK-NEXT: // Isolation: actor_instance. name: 'self' - await asyncInheritActorContextGlobalActorAcceptsClosure { print(self) } // expected-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} - // expected-note @-1 {{sending 'self'-isolated value of non-Sendable type '() -> ()' to main actor-isolated global function 'asyncInheritActorContextGlobalActorAcceptsClosure' risks causing races in between 'self'-isolated and main actor-isolated uses}} - - // This is a synchronous function, so we error. - // - // CHECK-LABEL: // closure #2 in MyActor.test_CallerAsyncInheritsActorContext_CalleeSyncMainActorIsolated() - // CHECK-NEXT: // Isolation: actor_instance. name: 'self' - await asyncInheritActorContextGlobalActorAcceptsSendingClosure { // expected-error {{passing closure as a 'sending' parameter risks causing data races between 'self'-isolated code and concurrent execution of the closure}} - print(self) // expected-note {{closure captures 'self'}} - } - - // CHECK-LABEL: // closure #3 in MyActor.test_CallerAsyncInheritsActorContext_CalleeSyncMainActorIsolated() - // CHECK-NEXT: // Isolation: actor_instance. name: 'self' - await asyncInheritActorContextGlobalActorAcceptsSendableClosure { print(self) } - } } /////////////////////////////////////////////////// @@ -708,21 +490,17 @@ extension MyActor { // CHECK-LABEL: // closure #1 in MyActor.test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() // CHECK-NEXT: // Isolation: actor_instance. name: 'self' - await asyncInheritActorContextAcceptsAsyncClosure { print(self) } - - // CHECK-LABEL: // closure #2 in MyActor.test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() - // CHECK-NEXT: // Isolation: actor_instance. name: 'self' await asyncInheritActorContextAcceptsSendingAsyncClosure { print(self) } - // CHECK-LABEL: // closure #3 in MyActor.test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() + // CHECK-LABEL: // closure #2 in MyActor.test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() // CHECK-NEXT: // Isolation: global_actor. type: CustomActor await asyncInheritActorContextAcceptsSendingAsyncClosure { @CustomActor in print(self) } - // CHECK-LABEL: // closure #4 in MyActor.test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() + // CHECK-LABEL: // closure #3 in MyActor.test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() // CHECK-NEXT: // Isolation: global_actor. type: MainActor await asyncInheritActorContextAcceptsSendingAsyncClosure { @MainActor in print(self) } - // CHECK-LABEL: // closure #5 in MyActor.test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() + // CHECK-LABEL: // closure #4 in MyActor.test_CallerAsyncInheritsActorContext_CalleeAsyncNonisolated() // CHECK-NEXT: // Isolation: actor_instance. name: 'self' await asyncInheritActorContextAcceptsSendableAsyncClosure { print(self) } } @@ -749,21 +527,17 @@ extension MyActor { // CHECK-LABEL: // closure #1 in MyActor.test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() // CHECK-NEXT: // Isolation: actor_instance. name: 'self' - await asyncInheritActorContextGlobalActorAcceptsAsyncClosure { print(self) } - - // CHECK-LABEL: // closure #2 in MyActor.test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() - // CHECK-NEXT: // Isolation: actor_instance. name: 'self' await asyncInheritActorContextGlobalActorAcceptsSendingAsyncClosure { print(self) } - // CHECK-LABEL: // closure #3 in MyActor.test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() + // CHECK-LABEL: // closure #2 in MyActor.test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() // CHECK-NEXT: // Isolation: global_actor. type: CustomActor await asyncInheritActorContextGlobalActorAcceptsSendingAsyncClosure { @CustomActor in print(self) } - // CHECK-LABEL: // closure #4 in MyActor.test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() + // CHECK-LABEL: // closure #3 in MyActor.test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() // CHECK-NEXT: // Isolation: global_actor. type: MainActor await asyncInheritActorContextGlobalActorAcceptsSendingAsyncClosure { @MainActor in print(self) } - // CHECK-LABEL: // closure #5 in MyActor.test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() + // CHECK-LABEL: // closure #4 in MyActor.test_CallerAsyncInheritsActorContext_CalleeAsyncMainActorIsolated() // CHECK-NEXT: // Isolation: actor_instance. name: 'self' await asyncInheritActorContextGlobalActorAcceptsSendableAsyncClosure { print(self) } } diff --git a/test/ModuleInterface/inheritActorContext_attr.swift b/test/ModuleInterface/inheritActorContext_attr.swift new file mode 100644 index 0000000000000..d36bc1b655457 --- /dev/null +++ b/test/ModuleInterface/inheritActorContext_attr.swift @@ -0,0 +1,43 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-emit-module-interface(%t/Library.swiftinterface) %s -module-name Library +// RUN: %target-swift-typecheck-module-from-interface(%t/Library.swiftinterface) -module-name Library +// RUN: %FileCheck %s < %t/Library.swiftinterface + +// CHECK-NOT: #if compiler(>=5.3) && $AlwaysInheritActorContext +// CHECK: public func globalTest(@_inheritActorContext _: @Sendable () async -> Swift.Void) +// CHECK-NOT: #endif +public func globalTest(@_inheritActorContext _: @Sendable () async -> Void) {} + +// CHECK: #if compiler(>=5.3) && $AlwaysInheritActorContext +// CHECK-NEXT: public func globalTestAlways(@_inheritActorContext(always) _: @Sendable () async -> Swift.Void) +// CHECK-NEXT: #endif +public func globalTestAlways(@_inheritActorContext(always) _: @Sendable () async -> Void) {} + +public struct Test { + // CHECK-NOT: #if compiler(>=5.3) && $AlwaysInheritActorContext + // CHECK: public init(@_inheritActorContext x: @Sendable () async -> Swift.Int) + // CHECK-NOT: #endif + public init(@_inheritActorContext x: @Sendable () async -> Int) {} + + // CHECK: #if compiler(>=5.3) && $AlwaysInheritActorContext + // CHECK-NEXT: #if compiler(>=5.3) && $SendingArgsAndResults + // CHECK-NEXT: public init(@_inheritActorContext(always) y: sending () async -> Swift.Void) + // CHECK-NEXT: #else + // CHECK-NEXT: public init(@_inheritActorContext(always) y: () async -> Swift.Void) + // CHECK-NEXT: #endif + // CHECK-NEXT: #endif + public init(@_inheritActorContext(always) y: sending () async -> Void) {} + + // CHECK-NOT: #if compiler(>=5.3) && $AlwaysInheritActorContext + // CHECK: public subscript(@_inheritActorContext _: @Sendable () async -> Swift.Void) -> Swift.Bool { + // CHECK-NEXT: get + // CHECK-NEXT: } + // CHECK-NOT: #endif + public subscript(@_inheritActorContext _: @Sendable () async -> Void) -> Bool { false } + + // CHECK: #if compiler(>=5.3) && $AlwaysInheritActorContext + // CHECK-NEXT: public subscript(@_inheritActorContext(always) _: @Sendable (Swift.Int) async -> Swift.Void) -> Swift.Bool { + // CHECK-NEXT: get + // CHECK-NEXT: } + public subscript(@_inheritActorContext(always) _: @Sendable (Int) async -> Void) -> Bool { false } +} diff --git a/test/SILGen/hop_to_executor.swift b/test/SILGen/hop_to_executor.swift index 63736dad7c1b6..a1daf20bed2c5 100644 --- a/test/SILGen/hop_to_executor.swift +++ b/test/SILGen/hop_to_executor.swift @@ -324,6 +324,8 @@ func testGlobalActorFuncValue(_ fn: @RedActor () -> Void) async { } func acceptAsyncSendableClosureInheriting(@_inheritActorContext _: @Sendable () async -> T) { } +func acceptAsyncSendableClosureAlwaysInheriting(@_inheritActorContext(always) _: @Sendable () async -> T) { } +func acceptAsyncSendableClosureAlwaysInheritingErased(@_inheritActorContext(always) _: sending @isolated(any) () async -> T) { } extension MyActor { func synchronous() { } @@ -338,6 +340,66 @@ extension MyActor { synchronous() } } + + // CHECK-LABEL: sil private [ossa] @$s4test7MyActorC0A16AlwaysInheritingyyFyyYaYbXEfU_ + // CHECK: debug_value [[SELF:%[0-9]+]] : $MyActor + // CHECK-NEXT: [[COPY:%[0-9]+]] = copy_value [[SELF]] : $MyActor + // CHECK-NEXT: [[BORROW:%[0-9]+]] = begin_borrow [[COPY]] : $MyActor + // CHECK-NEXT: hop_to_executor [[BORROW]] : $MyActor + func testAlwaysInheriting() { + acceptAsyncSendableClosureAlwaysInheriting { + } + } +} + +func testIsolatedParameterWithInheritActorContext(_ isolation: isolated (any Actor)?) { + // CHECK-LABEL: sil private [ossa] @$s4test0A40IsolatedParameterWithInheritActorContextyyScA_pSgYiFyyYaYbXEfU_ + // CHECK: debug_value [[ISOLATION:%[0-9]+]] : $Optional + // CHECK-NEXT: [[COPY:%[0-9]+]] = copy_value [[ISOLATION]] : $Optional + // CHECK-NEXT: [[BORROW:%[0-9]+]] = begin_borrow [[COPY]] : $Optional + // CHECK-NEXT: hop_to_executor [[BORROW]] : $Optional + acceptAsyncSendableClosureAlwaysInheriting { + } + + // CHECK-LABEL: sil private [ossa] @$s4test0A40IsolatedParameterWithInheritActorContextyyScA_pSgYiFyyYaYbScMYcXEfU0_ + // CHECK: hop_to_executor {{.*}} : $MainActor + acceptAsyncSendableClosureAlwaysInheriting { @MainActor in + // CHECK-LABEL: sil private [ossa] @$s4test0A40IsolatedParameterWithInheritActorContextyyScA_pSgYiFyyYaYbScMYcXEfU0_yyYaYbXEfU_ + // CHECK: hop_to_executor {{.*}} : $MainActor + acceptAsyncSendableClosureAlwaysInheriting { + } + } + + // CHECK-LABEL: sil private [ossa] @$s4test0A40IsolatedParameterWithInheritActorContextyyScA_pSgYiFyyYaYbXEfU1_ + // CHECK: debug_value [[ISOLATION:%[0-9]+]] : $Optional + // CHECK-NEXT: [[COPY:%[0-9]+]] = copy_value [[ISOLATION]] : $Optional + // CHECK-NEXT: [[BORROW:%[0-9]+]] = begin_borrow [[COPY]] : $Optional + // CHECK-NEXT: hop_to_executor [[BORROW]] : $Optional + acceptAsyncSendableClosureAlwaysInheriting { + // CHECK-LABEL: sil private [ossa] @$s4test0A40IsolatedParameterWithInheritActorContextyyScA_pSgYiFyyYaYbXEfU1_yyYaYbXEfU_ + // CHECK: debug_value [[ISOLATION:%[0-9]+]] : $Optional + // CHECK-NEXT: [[COPY:%[0-9]+]] = copy_value [[ISOLATION]] : $Optional + // CHECK-NEXT: [[BORROW:%[0-9]+]] = begin_borrow [[COPY]] : $Optional + // CHECK-NEXT: hop_to_executor [[BORROW]] : $Optional + acceptAsyncSendableClosureAlwaysInheriting { + } + } +} + +// CHECK-LABEL: sil hidden [ossa] @$s4test0a17IsolatedParamWithB3AnyyyScA_pYiF +// CHECK: [[CLOSURE_REF:%.*]] = function_ref @$s4test0a17IsolatedParamWithB3AnyyyScA_pYiFyyYaXEfU_ +// CHECK-NEXT: [[ISOLATION_COPY_1:%.*]] = copy_value %0 : $any Actor +// CHECK-NEXT: [[ISOLATION_COPY_2:%.*]] = copy_value [[ISOLATION_COPY_1]] : $any Actor +// CHECK-NEXT: [[DYNAMIC_ISOLATION:%.*]] = enum $Optional, #Optional.some!enumelt, [[ISOLATION_COPY_2]] : $any Actor +// CHECK-NEXT: [[CLOSURE_WITH_APPLIED_ISOLATION:%.*]] = partial_apply [callee_guaranteed] [isolated_any] [[CLOSURE_REF]]([[DYNAMIC_ISOLATION]], [[ISOLATION_COPY_1]]) +func testIsolatedParamWithIsolatedAny(_ isolation: isolated any Actor) { + // CHECK-LABEL: sil private [ossa] @$s4test0a17IsolatedParamWithB3AnyyyScA_pYiFyyYaXEfU_ + // CHECK: bb0(%0 : $*(), [[DYNAMIC_ISOLATION:%[0-9]+]] : @guaranteed $Optional, [[CAPTURED_ISOLATION:%[0-9]+]] : @closureCapture @guaranteed $any Actor): + // CHECK: [[COPY:%[0-9]+]] = copy_value [[CAPTURED_ISOLATION]] : $any Actor + // CHECK-NEXT: [[BORROW:%[0-9]+]] = begin_borrow [[COPY]] : $any Actor + // CHECK-NEXT: hop_to_executor [[BORROW]] : $any Actor + acceptAsyncSendableClosureAlwaysInheritingErased { + } } func acceptAsyncClosure(_: () async -> Void) { } diff --git a/test/abi/macOS/arm64/concurrency.swift b/test/abi/macOS/arm64/concurrency.swift index 85942a9747bf0..2b048f7b53188 100644 --- a/test/abi/macOS/arm64/concurrency.swift +++ b/test/abi/macOS/arm64/concurrency.swift @@ -393,16 +393,6 @@ Added: _swift_task_getCurrentTaskName Added: _swift_task_immediate Added: _$sScTss5Error_pRs_rlE18startSynchronously4name8priority_ScTyxsAA_pGSSSg_ScPSgxyYaKYAcntFZ Added: _$sScTss5NeverORs_rlE18startSynchronously4name8priority_ScTyxABGSSSg_ScPSgxyYaKYAcntFZ -Added: _$sScG16addImmediateTask4name8priority9operationySSSg_ScPSgxyYaYAcntF -Added: _$sScg31addImmediateTaskUnlessCancelled4name8priority9operationySSSg_ScPSgxyYaKYAcntF -Added: _$sScG31addImmediateTaskUnlessCancelled4name8priority9operationySSSg_ScPSgxyYaYAcntF -Added: _$sScTss5NeverORs_rlE9immediate4name8priority_ScTyxABGSSSg_ScPSgxyYaKYAcntFZ -Added: _$sScTss5Error_pRs_rlE9immediate4name8priority_ScTyxsAA_pGSSSg_ScPSgxyYaKYAcntFZ -Added: _$sScg16addImmediateTask4name8priority9operationySSSg_ScPSgxyYaKYAcntF -Added: _$ss19DiscardingTaskGroupV012addImmediateB04name8priority9operationySSSg_ScPSgyyYaYAcntF -Added: _$ss19DiscardingTaskGroupV012addImmediateB15UnlessCancelled4name8priority9operationySSSg_ScPSgyyYaYAcntF -Added: _$ss27ThrowingDiscardingTaskGroupV012addImmediateC04name8priority9operationySSSg_ScPSgyyYaKYAcntF -Added: _$ss27ThrowingDiscardingTaskGroupV012addImmediateC15UnlessCancelled4name8priority9operationySSSg_ScPSgyyYaKYAcntF // isIsolatingCurrentContext Added: _swift_task_invokeSwiftIsIsolatingCurrentContext diff --git a/test/abi/macOS/x86_64/concurrency.swift b/test/abi/macOS/x86_64/concurrency.swift index d960126b0b448..a88721bc535f2 100644 --- a/test/abi/macOS/x86_64/concurrency.swift +++ b/test/abi/macOS/x86_64/concurrency.swift @@ -393,16 +393,6 @@ Added: _swift_task_getCurrentTaskName Added: _swift_task_immediate Added: _$sScTss5Error_pRs_rlE18startSynchronously4name8priority_ScTyxsAA_pGSSSg_ScPSgxyYaKYAcntFZ Added: _$sScTss5NeverORs_rlE18startSynchronously4name8priority_ScTyxABGSSSg_ScPSgxyYaKYAcntFZ -Added: _$sScG16addImmediateTask4name8priority9operationySSSg_ScPSgxyYaYAcntF -Added: _$sScg31addImmediateTaskUnlessCancelled4name8priority9operationySSSg_ScPSgxyYaKYAcntF -Added: _$sScG31addImmediateTaskUnlessCancelled4name8priority9operationySSSg_ScPSgxyYaYAcntF -Added: _$sScTss5NeverORs_rlE9immediate4name8priority_ScTyxABGSSSg_ScPSgxyYaKYAcntFZ -Added: _$sScTss5Error_pRs_rlE9immediate4name8priority_ScTyxsAA_pGSSSg_ScPSgxyYaKYAcntFZ -Added: _$sScg16addImmediateTask4name8priority9operationySSSg_ScPSgxyYaKYAcntF -Added: _$ss19DiscardingTaskGroupV012addImmediateB04name8priority9operationySSSg_ScPSgyyYaYAcntF -Added: _$ss19DiscardingTaskGroupV012addImmediateB15UnlessCancelled4name8priority9operationySSSg_ScPSgyyYaYAcntF -Added: _$ss27ThrowingDiscardingTaskGroupV012addImmediateC04name8priority9operationySSSg_ScPSgyyYaKYAcntF -Added: _$ss27ThrowingDiscardingTaskGroupV012addImmediateC15UnlessCancelled4name8priority9operationySSSg_ScPSgyyYaKYAcntF // isIsolatingCurrentContext Added: _swift_task_invokeSwiftIsIsolatingCurrentContext diff --git a/test/attr/attr_abi.swift b/test/attr/attr_abi.swift index 49116208b3740..3b163dac05c99 100644 --- a/test/attr/attr_abi.swift +++ b/test/attr/attr_abi.swift @@ -1406,16 +1406,19 @@ func nonEphemeral2(_: UnsafeRawPointer) {} @abi(func disfavoredOverload3(_: UnsafeRawPointer)) func nonEphemeral3(@_nonEphemeral _: UnsafeRawPointer) {} -// @_inheritActorContext -- banned in @abi -@abi(func inheritActorContext1(@_inheritActorContext fn: @Sendable @escaping () async -> Void)) // expected-error {{unused '_inheritActorContext' attribute in '@abi'}} {{32-53=}} +// @_inheritActorContext +@abi(func inheritActorContext1(@_inheritActorContext fn: @Sendable @escaping () async -> Void)) func inheritActorContext1(@_inheritActorContext fn: @Sendable @escaping () async -> Void) {} -@abi(func inheritActorContext2(@_inheritActorContext fn: @Sendable @escaping () async -> Void)) // expected-error {{unused '_inheritActorContext' attribute in '@abi'}} {{32-53=}} +@abi(func inheritActorContext2(@_inheritActorContext fn: @Sendable @escaping () async -> Void)) func inheritActorContext2(fn: @Sendable @escaping () async -> Void) {} @abi(func inheritActorContext3(fn: @Sendable @escaping () async -> Void)) func inheritActorContext3(@_inheritActorContext fn: @Sendable @escaping () async -> Void) {} +@abi(func inheritActorContext4(@_inheritActorContext(always) fn: @Sendable @escaping () async -> Void)) +func inheritActorContext4(fn: @Sendable @escaping () async -> Void) {} + // @excusivity(checked/unchecked) -- banned in @abi class Exclusivity { @abi(var checked00: Int) diff --git a/test/attr/attr_inheritActorContext.swift b/test/attr/attr_inheritActorContext.swift new file mode 100644 index 0000000000000..7d490878a12c5 --- /dev/null +++ b/test/attr/attr_inheritActorContext.swift @@ -0,0 +1,38 @@ +// RUN: %target-typecheck-verify-swift + +func test1(@_inheritActorContext _: @Sendable () async -> Void) {} // Ok +func test2(@_inheritActorContext(always) _: sending () async -> Void) {} // Ok + +func test3(@_inheritActorContext _: () async -> Void) {} +// expected-warning@-1 {{@_inheritActorContext only applies to 'sending' parameters or parameters with '@Sendable' function types}} +func test3(@_inheritActorContext _: @Sendable () -> Void) {} +// expected-warning@-1 {{@_inheritActorContext only applies to '@isolated(any)' parameters or parameters with asynchronous function types}} + +func test4(@_inheritActorContext _: Int) {} +// expected-error@-1 {{@_inheritActorContext only applies to parameters with function types (got: 'Int')}} + +func test5(@_inheritActorContext _: sending Optional<() async -> Int>) {} // Ok +func test6(@_inheritActorContext _: (Optional<@Sendable () async -> Int>)?) {} // Ok +func test6(@_inheritActorContext _: (Optional<@Sendable @isolated(any) () -> Int>)?) {} // Ok + +func test7(@_inheritActorContext _: Int?) {} // Ok +// expected-error@-1 {{@_inheritActorContext only applies to parameters with function types (got: 'Int?')}} + +struct S { + init(@_inheritActorContext(always) _: @escaping @Sendable () async -> Void) {} // Ok + + var test: @_inheritActorContext () async -> Void { // expected-error {{attribute can only be applied to declarations, not types}} + { } + } + + subscript(@_inheritActorContext _: @Sendable () async -> Void) -> Bool { false } // Ok + subscript(@_inheritActorContext(always) _: @Sendable (Int) async -> Void) -> Bool { false } // Ok + + subscript(@_inheritActorContext _: sending (String) async -> Void) -> Bool { false } + subscript(x: Int, @_inheritActorContext(always) _: @Sendable (Int, Int) async -> Void) -> Bool { false } + + func testClosure() { + _ = { @_inheritActorContext in // expected-error {{attribute @_inheritActorContext is not supported on a closure}} + } + } +}