diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index f3b7220761f56..4273dcae8e416 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -910,16 +910,6 @@ void BridgedAvailableAttr_setIsGroupedWithWildcard(BridgedAvailableAttr cAttr); SWIFT_NAME("BridgedAvailableAttr.setIsGroupTerminator(self:)") void BridgedAvailableAttr_setIsGroupTerminator(BridgedAvailableAttr cAttr); -enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedExecutionKind { - BridgedExecutionKindConcurrent, - BridgedExecutionKindCaller, -}; - -SWIFT_NAME("BridgedExecutionAttr.createParsed(_:atLoc:range:behavior:)") -BridgedExecutionAttr BridgedExecutionAttr_createParsed( - BridgedASTContext cContext, BridgedSourceLoc atLoc, - BridgedSourceRange range, BridgedExecutionKind behavior); - enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedAccessLevel { BridgedAccessLevelPrivate, BridgedAccessLevelFilePrivate, @@ -1235,11 +1225,18 @@ BridgedNonSendableAttr BridgedNonSendableAttr_createParsed( BridgedASTContext cContext, BridgedSourceLoc cAtLoc, BridgedSourceRange cRange, BridgedNonSendableKind cKind); -SWIFT_NAME("BridgedNonisolatedAttr.createParsed(_:atLoc:range:isUnsafe:)") +enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedNonIsolatedModifier { + BridgedNonIsolatedModifierNone, + BridgedNonIsolatedModifierUnsafe, + BridgedNonIsolatedModifierNonSending +}; + +SWIFT_NAME("BridgedNonisolatedAttr.createParsed(_:atLoc:range:modifier:)") BridgedNonisolatedAttr BridgedNonisolatedAttr_createParsed(BridgedASTContext cContext, BridgedSourceLoc cAtLoc, - BridgedSourceRange cRange, bool isUnsafe); + BridgedSourceRange cRange, + BridgedNonIsolatedModifier modifier); SWIFT_NAME("BridgedObjCAttr.createParsedUnnamed(_:atLoc:attrNameLoc:)") BridgedObjCAttr @@ -2590,11 +2587,6 @@ BridgedConventionTypeAttr BridgedConventionTypeAttr_createParsed( BridgedSourceLoc cNameLoc, BridgedDeclNameRef cWitnessMethodProtocol, BridgedStringRef cClangType, BridgedSourceLoc cClangTypeLoc); -enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedExecutionTypeAttrExecutionKind { - BridgedExecutionTypeAttrExecutionKind_Concurrent, - BridgedExecutionTypeAttrExecutionKind_Caller -}; - SWIFT_NAME("BridgedDifferentiableTypeAttr.createParsed(_:atLoc:nameLoc:" "parensRange:kind:kindLoc:)") BridgedDifferentiableTypeAttr BridgedDifferentiableTypeAttr_createParsed( @@ -2602,14 +2594,6 @@ BridgedDifferentiableTypeAttr BridgedDifferentiableTypeAttr_createParsed( BridgedSourceLoc cNameLoc, BridgedSourceRange cParensRange, BridgedDifferentiabilityKind cKind, BridgedSourceLoc cKindLoc); -SWIFT_NAME("BridgedExecutionTypeAttr.createParsed(_:atLoc:nameLoc:parensRange:" - "behavior:behaviorLoc:)") -BridgedExecutionTypeAttr BridgedExecutionTypeAttr_createParsed( - BridgedASTContext cContext, BridgedSourceLoc cAtLoc, - BridgedSourceLoc cNameLoc, BridgedSourceRange cParensRange, - BridgedExecutionTypeAttrExecutionKind behavior, - BridgedSourceLoc cBehaviorLoc); - SWIFT_NAME("BridgedIsolatedTypeAttr.createParsed(_:atLoc:nameLoc:parensRange:" "isolationKind:isolationKindLoc:)") BridgedIsolatedTypeAttr BridgedIsolatedTypeAttr_createParsed( @@ -2777,6 +2761,12 @@ BridgedSendingTypeRepr_createParsed(BridgedASTContext cContext, BridgedTypeRepr base, BridgedSourceLoc cSpecifierLoc); +SWIFT_NAME("BridgedCallerIsolatedTypeRepr.createParsed(_:base:specifierLoc:)") +BridgedCallerIsolatedTypeRepr +BridgedCallerIsolatedTypeRepr_createParsed(BridgedASTContext cContext, + BridgedTypeRepr base, + BridgedSourceLoc cSpecifierLoc); + SWIFT_NAME( "BridgedTupleTypeRepr.createParsed(_:elements:leftParenLoc:rightParenLoc:)") BridgedTupleTypeRepr BridgedTupleTypeRepr_createParsed( diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index fb8afc911a3b6..0c4de231462ab 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -226,8 +226,8 @@ class DeclAttribute : public AttributeBase { isEarlyAdopter : 1 ); - SWIFT_INLINE_BITFIELD(NonisolatedAttr, DeclAttribute, 1, - isUnsafe : 1 + SWIFT_INLINE_BITFIELD(NonisolatedAttr, DeclAttribute, NumNonIsolatedModifierBits, + Modifier : NumNonIsolatedModifierBits ); SWIFT_INLINE_BITFIELD_FULL(AllowFeatureSuppressionAttr, DeclAttribute, 1+31, @@ -236,10 +236,6 @@ class DeclAttribute : public AttributeBase { NumFeatures : 31 ); - - SWIFT_INLINE_BITFIELD(ExecutionAttr, DeclAttribute, NumExecutionKindBits, - Behavior : NumExecutionKindBits - ); } Bits; // clang-format on @@ -2978,17 +2974,28 @@ class ObjCImplementationAttr final : public DeclAttribute { /// Represents nonisolated modifier. class NonisolatedAttr final : public DeclAttribute { public: - NonisolatedAttr(SourceLoc atLoc, SourceRange range, bool unsafe, - bool implicit) + NonisolatedAttr(SourceLoc atLoc, SourceRange range, + NonIsolatedModifier modifier, bool implicit) : DeclAttribute(DeclAttrKind::Nonisolated, atLoc, range, implicit) { - Bits.NonisolatedAttr.isUnsafe = unsafe; - assert((isUnsafe() == unsafe) && "not enough bits for unsafe state"); + Bits.NonisolatedAttr.Modifier = static_cast(modifier); + assert((getModifier() == modifier) && "not enough bits for modifier"); } - NonisolatedAttr(bool unsafe, bool implicit) - : NonisolatedAttr({}, {}, unsafe, implicit) {} + NonIsolatedModifier getModifier() const { + return static_cast(Bits.NonisolatedAttr.Modifier); + } - bool isUnsafe() const { return Bits.NonisolatedAttr.isUnsafe; } + bool isUnsafe() const { return getModifier() == NonIsolatedModifier::Unsafe; } + bool isNonSending() const { + return getModifier() == NonIsolatedModifier::NonSending; + } + + static NonisolatedAttr * + createImplicit(ASTContext &ctx, + NonIsolatedModifier modifier = NonIsolatedModifier::None) { + return new (ctx) NonisolatedAttr(/*atLoc*/ {}, /*range*/ {}, modifier, + /*implicit=*/true); + } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DeclAttrKind::Nonisolated; @@ -2996,11 +3003,11 @@ class NonisolatedAttr final : public DeclAttribute { /// Create a copy of this attribute. NonisolatedAttr *clone(ASTContext &ctx) const { - return new (ctx) NonisolatedAttr(AtLoc, Range, isUnsafe(), isImplicit()); + return new (ctx) NonisolatedAttr(AtLoc, Range, getModifier(), isImplicit()); } bool isEquivalent(const NonisolatedAttr *other, Decl *attachedTo) const { - return isUnsafe() == other->isUnsafe(); + return getModifier() == other->getModifier(); } }; @@ -3275,34 +3282,6 @@ class ABIAttr : public DeclAttribute { } }; -class ExecutionAttr : public DeclAttribute { -public: - ExecutionAttr(SourceLoc AtLoc, SourceRange Range, - ExecutionKind behavior, - bool Implicit) - : DeclAttribute(DeclAttrKind::Execution, AtLoc, Range, Implicit) { - Bits.ExecutionAttr.Behavior = static_cast(behavior); - } - - ExecutionAttr(ExecutionKind behavior, bool Implicit) - : ExecutionAttr(/*AtLoc=*/SourceLoc(), /*Range=*/SourceRange(), behavior, - Implicit) {} - - ExecutionKind getBehavior() const { - return static_cast(Bits.ExecutionAttr.Behavior); - } - - static bool classof(const DeclAttribute *DA) { - return DA->getKind() == DeclAttrKind::Execution; - } - - UNIMPLEMENTED_CLONE(ExecutionAttr) - - bool isEquivalent(const ExecutionAttr *other, Decl *attachedTo) const { - return getBehavior() == other->getBehavior(); - } -}; - /// Attributes that may be applied to declarations. class DeclAttributes { /// Linked list of declaration attributes. @@ -3762,10 +3741,6 @@ class alignas(1 << AttrAlignInBits) TypeAttribute SWIFT_INLINE_BITFIELD_FULL(IsolatedTypeAttr, TypeAttribute, 8, Kind : 8 ); - - SWIFT_INLINE_BITFIELD_FULL(ExecutionTypeAttr, TypeAttribute, 8, - Behavior : 8 - ); } Bits; // clang-format on @@ -4037,28 +4012,6 @@ class IsolatedTypeAttr : public SimpleTypeAttrWithArgs { void printImpl(ASTPrinter &printer, const PrintOptions &options) const; }; -/// The @execution function type attribute. -class ExecutionTypeAttr : public SimpleTypeAttrWithArgs { - SourceLoc BehaviorLoc; - -public: - ExecutionTypeAttr(SourceLoc atLoc, SourceLoc kwLoc, SourceRange parensRange, - Located behavior) - : SimpleTypeAttr(atLoc, kwLoc, parensRange), BehaviorLoc(behavior.Loc) { - Bits.ExecutionTypeAttr.Behavior = uint8_t(behavior.Item); - } - - ExecutionKind getBehavior() const { - return ExecutionKind(Bits.ExecutionTypeAttr.Behavior); - } - - SourceLoc getBehaviorLoc() const { - return BehaviorLoc; - } - - void printImpl(ASTPrinter &printer, const PrintOptions &options) const; -}; - using TypeOrCustomAttr = llvm::PointerUnion; diff --git a/include/swift/AST/AttrKind.h b/include/swift/AST/AttrKind.h index d56edbc4b6e31..7ac94fb07c0e2 100644 --- a/include/swift/AST/AttrKind.h +++ b/include/swift/AST/AttrKind.h @@ -130,14 +130,17 @@ enum class ExternKind: uint8_t { enum : unsigned { NumExternKindBits = countBitsUsed(static_cast(ExternKind::Last_ExternKind)) }; -enum class ExecutionKind : uint8_t { - Concurrent = 0, - Caller, - Last_ExecutionKind = Caller +enum class NonIsolatedModifier : uint8_t { + None = 0, + Unsafe, + NonSending, + Last_NonIsolatedModifier = NonSending }; -enum : unsigned { NumExecutionKindBits = - countBitsUsed(static_cast(ExecutionKind::Last_ExecutionKind)) }; +enum : unsigned { + NumNonIsolatedModifierBits = countBitsUsed( + static_cast(NonIsolatedModifier::Last_NonIsolatedModifier)) +}; enum class DeclAttrKind : unsigned { #define DECL_ATTR(_, CLASS, ...) CLASS, diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 5aadace6c9830..fb2b1475bb484 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -8146,8 +8146,6 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { return cast_or_null(ValueDecl::getOverriddenDecl()); } - std::optional getExecutionBehavior() const; - /// Whether the declaration is later overridden in the module /// /// Overrides are resolved during type checking; only query this field after diff --git a/include/swift/AST/DeclAttr.def b/include/swift/AST/DeclAttr.def index 7e40507ef6072..38e758448c8b7 100644 --- a/include/swift/AST/DeclAttr.def +++ b/include/swift/AST/DeclAttr.def @@ -862,11 +862,7 @@ DECL_ATTR(abi, ABI, 165) DECL_ATTR_FEATURE_REQUIREMENT(ABI, ABIAttribute) -DECL_ATTR(execution, Execution, - OnFunc | OnConstructor | OnSubscript | OnVar, - ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove | UnconstrainedInABIAttr, - 166) -DECL_ATTR_FEATURE_REQUIREMENT(Execution, ExecutionAttribute) +// Unused '166': Used to be `@execution(caller | concurrent)` replaced with `@concurrent` and `nonisolated(nonsending)` SIMPLE_DECL_ATTR(const, ConstVal, OnParam | OnVar | OnFunc, @@ -884,7 +880,12 @@ SIMPLE_DECL_ATTR(extensible, Extensible, ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove | ForbiddenInABIAttr, 169) -LAST_DECL_ATTR(Extensible) +SIMPLE_DECL_ATTR(concurrent, Concurrent, + OnFunc | OnConstructor | OnSubscript | OnVar, + ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove | UnconstrainedInABIAttr, + 170) + +LAST_DECL_ATTR(Concurrent) #undef DECL_ATTR_ALIAS #undef CONTEXTUAL_DECL_ATTR_ALIAS diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index e7d6ba6adcc97..06c64b5177e93 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -1700,14 +1700,6 @@ ERROR(attr_isolated_expected_rparen,none, ERROR(attr_isolated_expected_kind,none, "expected 'any' as the isolation kind", ()) -ERROR(attr_execution_expected_lparen,none, - "expected '(' after '@execution'", - ()) -ERROR(attr_execution_expected_rparen,none, - "expected ')' after execution behavior", ()) -ERROR(attr_execution_expected_kind,none, - "expected 'concurrent' or 'caller' as the execution behavior", ()) - ERROR(attr_private_import_expected_rparen,none, "expected ')' after function name for @_private", ()) ERROR(attr_private_import_expected_sourcefile, none, @@ -2172,5 +2164,18 @@ ERROR(sil_thunkinst_failed_to_parse_kind,none, ERROR(sil_failed_to_parse_sil_optional,none, "Expected SIL optional value of the form '[' NAME ']'", ()) +//------------------------------------------------------------------------------ +// MARK: nonisolated(nonsending) +//------------------------------------------------------------------------------ + +ERROR(nonisolated_nonsending_expected_lparen,PointsToFirstBadToken, + "expected '(' following 'nonisolated'", ()) +ERROR(nonisolated_nonsending_incorrect_modifier,PointsToFirstBadToken, + "expected 'nonsending' in modifier", ()) +ERROR(nonisolated_nonsending_expected_rparen,PointsToFirstBadToken, + "expected ')' after 'nonisolated' modifier", ()) +ERROR(nonisolated_nonsending_repeated,none, + "parameter may have at most one 'nonisolated(nonsending)' specifier", ()) + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 217a95377b350..7661d18157842 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8550,43 +8550,79 @@ GROUPED_ERROR(isolated_conformance_wrong_domain,IsolatedConformances,none, (ActorIsolation, Type, DeclName, ActorIsolation)) //===----------------------------------------------------------------------===// -// MARK: @execution Attribute +// MARK: @concurrent and nonisolated(nonsending) attributes //===----------------------------------------------------------------------===// -ERROR(attr_execution_only_on_async,none, - "cannot use '@execution' on non-async %kind0", - (ValueDecl *)) +ERROR(execution_behavior_only_on_async,none, + "cannot use %0 on non-async %kind1", + (DeclAttribute, ValueDecl *)) -ERROR(attr_execution_only_on_async_closure,none, - "cannot use '@execution' on non-async closure", - ()) +ERROR(cannot_specify_execution_behavior_for_decl,none, + "%0 is only applicable to asynchronous functions, " + "initializers, subscripts and computed properties", + (DeclAttribute)) -ERROR(attr_execution_type_attr_only_on_async,none, - "cannot use '@execution' on non-async function type", - ()) +ERROR(execution_behavior_only_on_async_closure,none, + "cannot use %0 on non-async closure", + (DeclAttribute)) -ERROR(attr_execution_incompatible_isolated_parameter,none, - "cannot use '@execution' on %kind0 because it has " - "an isolated parameter: %1", - (ValueDecl *, ValueDecl *)) +ERROR(execution_behavior_type_attr_only_on_async,none, + "cannot use '@%0' on non-async function type", + (StringRef)) -ERROR(attr_execution_incompatible_dynamically_isolated_parameter,none, - "cannot use '@execution' on %kind0 because it has " - "a dynamically isolated parameter: %1", - (ValueDecl *, ValueDecl *)) +ERROR(nonisolated_nonsending_only_on_function_types, none, + "%0 may only be used on function types", + (TypeRepr *)) -ERROR(attr_execution_type_attr_incompatible_with_global_isolation,none, - "cannot use '@execution' because function type is " - "isolated to a global actor %0", - (Type)) +ERROR(nonisolated_nonsending_only_on_async,none, + "cannot use %0 on non-async function type", + (TypeRepr *)) -ERROR(attr_execution_type_attr_incompatible_with_isolated_param,none, - "cannot use '@execution' together with an isolated parameter", - ()) +ERROR(cannot_use_nonisolated_nonsending_together_with_concurrent,none, + "cannot use %0 together with '@concurrent'", + (TypeRepr *)) -ERROR(attr_execution_type_attr_incompatible_with_isolated_any,none, - "cannot use '@execution' together with @isolated(any)", - ()) +ERROR(execution_behavior_incompatible_isolated_parameter,none, + "cannot use %0 on %kind1 because it has " + "an isolated parameter: %2", + (DeclAttribute, ValueDecl *, ValueDecl *)) + +ERROR(execution_behavior_incompatible_dynamically_isolated_parameter,none, + "cannot use %0 on %kind1 because it has " + "a dynamically isolated parameter: %2", + (DeclAttribute, ValueDecl *, ValueDecl *)) + +ERROR(execution_behavior_attr_incompatible_with_global_isolation,none, + "cannot use %0 because function type is isolated to a global actor %1", + (DeclAttribute, Type)) + +ERROR(execution_behavior_attr_incompatible_with_isolated_param,none, + "cannot use %0 together with an isolated parameter", + (DeclAttribute)) + +ERROR(execution_behavior_type_attr_incompatible_with_global_isolation,none, + "cannot use '@%0' because function type is isolated to a global actor %1", + (StringRef, Type)) + +ERROR(nonisolated_nonsending_incompatible_with_global_isolation,none, + "cannot use %0 because function type is isolated to a global actor %1", + (TypeRepr *, Type)) + +ERROR(execution_behavior_type_attr_incompatible_with_isolated_param,none, + "cannot use '@%0' together with an isolated parameter", + (StringRef)) + +ERROR(nonisolated_nonsending_incompatible_with_isolated_param,none, + "cannot use %0 together with an isolated parameter", + (TypeRepr *)) + +ERROR(execution_behavior_type_attr_incompatible_with_isolated_any,none, + "cannot use '@%0' together with @isolated(any)", + (StringRef)) + +ERROR(nonisolated_nonsending_incompatible_with_isolated_any,none, + "cannot use %0 together with @isolated(any)", + (TypeRepr *)) ERROR(invalid_function_conversion_with_non_sendable,none, "cannot convert %0 to %1 because crossing of an isolation boundary " diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index 73e3b44485598..c4651036541ea 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -127,6 +127,7 @@ IDENTIFIER(main) IDENTIFIER_WITH_NAME(MainEntryPoint, "$main") IDENTIFIER(message) IDENTIFIER(next) +IDENTIFIER(nonsending) IDENTIFIER_(nsErrorDomain) IDENTIFIER(objectAtIndexedSubscript) IDENTIFIER(objectForKeyedSubscript) diff --git a/include/swift/AST/PrintOptions.h b/include/swift/AST/PrintOptions.h index 94edc007269eb..37a643e023133 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -404,9 +404,6 @@ struct PrintOptions { /// Suppress modify/read accessors. bool SuppressCoroutineAccessors = false; - /// Suppress the @execution attribute - bool SuppressExecutionAttribute = false; - /// List of attribute kinds that should not be printed. std::vector ExcludeAttrList = { DeclAttrKind::Transparent, DeclAttrKind::Effects, diff --git a/include/swift/AST/TypeAttr.def b/include/swift/AST/TypeAttr.def index 811e85a08d865..4defd43cf1cdf 100644 --- a/include/swift/AST/TypeAttr.def +++ b/include/swift/AST/TypeAttr.def @@ -67,7 +67,7 @@ TYPE_ATTR(_opaqueReturnTypeOf, OpaqueReturnTypeOf) TYPE_ATTR(isolated, Isolated) SIMPLE_TYPE_ATTR(nonisolated, Nonisolated) SIMPLE_TYPE_ATTR(_addressable, Addressable) -TYPE_ATTR(execution, Execution) +SIMPLE_TYPE_ATTR(concurrent, Concurrent) // SIL-specific attributes SIMPLE_SIL_TYPE_ATTR(async, Async) diff --git a/include/swift/AST/TypeRepr.h b/include/swift/AST/TypeRepr.h index 749cf72190223..e4cde7d2d0b3f 100644 --- a/include/swift/AST/TypeRepr.h +++ b/include/swift/AST/TypeRepr.h @@ -1249,6 +1249,35 @@ class SendingTypeRepr : public SpecifierTypeRepr { static bool classof(const SendingTypeRepr *T) { return true; } }; +/// A 'nonisolated(nonsending)' function type. +/// \code +/// x : nonisolated(nonsending) () async -> Int +/// \endcode +class CallerIsolatedTypeRepr : public TypeRepr { + TypeRepr *Base; + SourceLoc Loc; + +public: + CallerIsolatedTypeRepr(TypeRepr *Base, SourceLoc Loc) + : TypeRepr(TypeReprKind::CallerIsolated), Base(Base), Loc(Loc) { + assert(Base); + } + + TypeRepr *getBase() const { return Base; } + + static bool classof(const TypeRepr *T) { + return T->getKind() == TypeReprKind::CallerIsolated; + } + static bool classof(const CallerIsolatedTypeRepr *T) { return true; } + +private: + SourceLoc getStartLocImpl() const { return Loc; } + SourceLoc getEndLocImpl() const { return Base->getEndLoc(); } + SourceLoc getLocImpl() const { return Base->getLoc(); } + void printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const; + friend class TypeRepr; +}; + /// A TypeRepr for a known, fixed type. /// /// Fixed type representations should be used sparingly, in places @@ -1680,6 +1709,7 @@ inline bool TypeRepr::isSimple() const { case TypeReprKind::ConstValue: case TypeReprKind::LifetimeDependent: case TypeReprKind::Integer: + case TypeReprKind::CallerIsolated: return true; } llvm_unreachable("bad TypeRepr kind"); diff --git a/include/swift/AST/TypeReprNodes.def b/include/swift/AST/TypeReprNodes.def index a1f7e51ded313..6a98b8f4dd3e6 100644 --- a/include/swift/AST/TypeReprNodes.def +++ b/include/swift/AST/TypeReprNodes.def @@ -77,6 +77,7 @@ TYPEREPR(Fixed, TypeRepr) TYPEREPR(SILBox, TypeRepr) TYPEREPR(Self, TypeRepr) TYPEREPR(LifetimeDependent, TypeRepr) +TYPEREPR(CallerIsolated, TypeRepr) TYPEREPR(Integer, TypeRepr) LAST_TYPEREPR(Integer) diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index 672ca8f02dff9..2bf7ba744f313 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -254,6 +254,7 @@ SUPPRESSIBLE_LANGUAGE_FEATURE(MemorySafetyAttributes, 458, "@unsafe attribute") LANGUAGE_FEATURE(ValueGenerics, 452, "Value generics feature (integer generics)") LANGUAGE_FEATURE(RawIdentifiers, 451, "Raw identifiers") LANGUAGE_FEATURE(SendableCompletionHandlers, 463, "Objective-C completion handler parameters are imported as @Sendable") +LANGUAGE_FEATURE(AsyncExecutionBehaviorAttributes, 0, "@concurrent and nonisolated(nonsending)") // Swift 6 UPCOMING_FEATURE(ConciseMagicFile, 274, 6) @@ -484,10 +485,6 @@ SUPPRESSIBLE_EXPERIMENTAL_FEATURE(AddressableTypes, true) /// Allow the @abi attribute. SUPPRESSIBLE_EXPERIMENTAL_FEATURE(ABIAttribute, true) -/// Allow the @execution attribute. This is also connected to -/// AsyncCallerExecution feature. -SUPPRESSIBLE_EXPERIMENTAL_FEATURE(ExecutionAttribute, false) - /// Functions with nonisolated isolation inherit their isolation from the /// calling context. ADOPTABLE_EXPERIMENTAL_FEATURE(AsyncCallerExecution, false) diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index f834cb84ce9b6..6da0b8a8788b0 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1169,6 +1169,8 @@ class Parser { Tok.isContextualKeyword("isolated") || Tok.isContextualKeyword("_const")) return true; + if (isCallerIsolatedSpecifier()) + return true; if (Context.LangOpts.hasFeature(Feature::SendingArgsAndResults) && Tok.isContextualKeyword("sending")) return true; @@ -1187,6 +1189,12 @@ class Parser { (peekToken().isContextualKeyword("lifetime")); } + bool isCallerIsolatedSpecifier() { + if (!Tok.isContextualKeyword("nonisolated")) + return false; + return peekToken().isFollowingLParen(); + } + bool canHaveParameterSpecifierContextualKeyword() { // The parameter specifiers like `isolated`, `consuming`, `borrowing` are // also valid identifiers and could be the name of a type. Check whether @@ -1421,6 +1429,7 @@ class Parser { SourceLoc IsolatedLoc; SourceLoc ConstLoc; SourceLoc SendingLoc; + SourceLoc CallerIsolatedLoc; SmallVector Attributes; LifetimeEntry *lifetimeEntry = nullptr; @@ -1723,6 +1732,10 @@ class Parser { /// Returns true if a qualified declaration name base type can be parsed. bool canParseBaseTypeForQualifiedDeclName(); + /// Returns true if `nonisolated` contextual keyword could be parsed + /// as part of the type a the current location. + bool canParseNonisolatedAsTypeModifier(); + /// Returns true if the current token is '->' or effects specifiers followed /// by '->'. /// diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 17ec755b21990..060a8364a635a 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -618,14 +618,6 @@ static StringRef getDumpString(FunctionRefInfo::ApplyLevel applyLevel) { return "double_apply"; } } -static StringRef getDumpString(ExecutionKind kind) { - switch (kind) { - case ExecutionKind::Concurrent: - return "concurrent"; - case ExecutionKind::Caller: - return "caller"; - } -} static StringRef getDumpString(ExplicitSafety safety) { switch (safety) { case ExplicitSafety::Unspecified: @@ -2391,6 +2383,8 @@ namespace { VD->getAttrs().getAttribute()) { if (nonisolatedAttr->isUnsafe()) { printFlag(true, "nonisolated(unsafe)", DeclModifierColor); + } else if (nonisolatedAttr->isNonSending()) { + printFlag(true, "nonisolated(nonsending)", DeclModifierColor); } else { printFlag(true, "nonisolated", DeclModifierColor); } @@ -4646,6 +4640,12 @@ class PrintTypeRepr : public TypeReprVisitor, printFoot(); } + void visitCallerIsolatedTypeRepr(CallerIsolatedTypeRepr *T, Label label) { + printCommon("caller_isolated", label); + printRec(T->getBase(), Label::optional("base")); + printFoot(); + } + void visitCompileTimeLiteralTypeRepr(CompileTimeLiteralTypeRepr *T, Label label) { printCommon("_const", label); printRec(T->getBase(), Label::optional("base")); @@ -4926,14 +4926,10 @@ class PrintAttribute : public AttributeVisitor, TRIVIAL_ATTR_PRINTER(WarnUnqualifiedAccess, warn_unqualified_access) TRIVIAL_ATTR_PRINTER(WeakLinked, weak_linked) TRIVIAL_ATTR_PRINTER(Extensible, extensible) + TRIVIAL_ATTR_PRINTER(Concurrent, concurrent) #undef TRIVIAL_ATTR_PRINTER - void visitExecutionAttr(ExecutionAttr *Attr, Label label) { - printCommon(Attr, "execution_attr", label); - printField(Attr->getBehavior(), Label::always("behavior")); - printFoot(); - } void visitABIAttr(ABIAttr *Attr, Label label) { printCommon(Attr, "abi_attr", label); printRec(Attr->abiDecl, Label::always("decl")); @@ -5184,6 +5180,7 @@ class PrintAttribute : public AttributeVisitor, void visitNonisolatedAttr(NonisolatedAttr *Attr, Label label) { printCommon(Attr, "nonisolated_attr", label); printFlag(Attr->isUnsafe(), "unsafe"); + printFlag(Attr->isNonSending(), "nonsending"); printFoot(); } void visitObjCAttr(ObjCAttr *Attr, Label label) { @@ -6341,7 +6338,7 @@ namespace { printFlag("@isolated(any)"); break; case FunctionTypeIsolation::Kind::NonIsolatedCaller: - printFlag("@execution(caller)"); + printFlag("nonisolated(nonsending)"); break; } } diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index d4c08b5a43d91..047c29ee7b42e 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3302,14 +3302,6 @@ suppressingFeatureAddressableTypes(PrintOptions &options, action(); } -static void -suppressingFeatureExecutionAttribute(PrintOptions &options, - llvm::function_ref action) { - llvm::SaveAndRestore scope1(options.SuppressExecutionAttribute, true); - ExcludeAttrRAII scope2(options.ExcludeAttrList, DeclAttrKind::Execution); - action(); -} - /// Suppress the printing of a particular feature. static void suppressingFeature(PrintOptions &options, Feature feature, llvm::function_ref action) { @@ -6509,8 +6501,7 @@ class TypePrinter : public TypeVisitor { break; case FunctionTypeIsolation::Kind::NonIsolatedCaller: - if (!Options.SuppressExecutionAttribute) - Printer << "@execution(caller) "; + Printer << "nonisolated(nonsending) "; break; } diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 01d995e22156e..31a8e44f921ee 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -2324,6 +2324,10 @@ bool Traversal::visitSendingTypeRepr(SendingTypeRepr *T) { return doIt(T->getBase()); } +bool Traversal::visitCallerIsolatedTypeRepr(CallerIsolatedTypeRepr *T) { + return doIt(T->getBase()); +} + bool Traversal::visitCompileTimeLiteralTypeRepr(CompileTimeLiteralTypeRepr *T) { return doIt(T->getBase()); } diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 61b992437d66c..12631530028cb 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -304,26 +304,6 @@ void IsolatedTypeAttr::printImpl(ASTPrinter &printer, printer.printStructurePost(PrintStructureKind::BuiltinAttribute); } -void ExecutionTypeAttr::printImpl(ASTPrinter &printer, - const PrintOptions &options) const { - if (options.SuppressExecutionAttribute) - return; - - printer.callPrintStructurePre(PrintStructureKind::BuiltinAttribute); - printer.printAttrName("@execution"); - printer << "("; - switch (getBehavior()) { - case ExecutionKind::Concurrent: - printer << "concurrent"; - break; - case ExecutionKind::Caller: - printer << "caller"; - break; - } - printer << ")"; - printer.printStructurePost(PrintStructureKind::BuiltinAttribute); -} - /// Given a name like "inline", return the decl attribute ID that corresponds /// to it. Note that this is a many-to-one mapping, and that the identifier /// passed in may only be the first portion of the attribute (e.g. in the case @@ -1538,8 +1518,15 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, case DeclAttrKind::Nonisolated: { Printer.printAttrName("nonisolated"); - if (cast(this)->isUnsafe()) { + switch (cast(this)->getModifier()) { + case NonIsolatedModifier::None: + break; + case NonIsolatedModifier::Unsafe: Printer << "(unsafe)"; + break; + case NonIsolatedModifier::NonSending: + Printer << "(nonsending)"; + break; } break; } @@ -1722,19 +1709,6 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, break; } - case DeclAttrKind::Execution: { - auto *attr = cast(this); - switch (attr->getBehavior()) { - case ExecutionKind::Concurrent: - Printer << "@execution(concurrent)"; - break; - case ExecutionKind::Caller: - Printer << "@execution(caller)"; - break; - } - break; - } - #define SIMPLE_DECL_ATTR(X, CLASS, ...) case DeclAttrKind::CLASS: #include "swift/AST/DeclAttr.def" llvm_unreachable("handled above"); @@ -1931,10 +1905,13 @@ StringRef DeclAttribute::getAttrName() const { case DeclAttrKind::Documentation: return "_documentation"; case DeclAttrKind::Nonisolated: - if (cast(this)->isUnsafe()) { - return "nonisolated(unsafe)"; - } else { - return "nonisolated"; + switch (cast(this)->getModifier()) { + case NonIsolatedModifier::None: + return "nonisolated"; + case NonIsolatedModifier::Unsafe: + return "nonisolated(unsafe)"; + case NonIsolatedModifier::NonSending: + return "nonisolated(nonsending)"; } case DeclAttrKind::MacroRole: switch (cast(this)->getMacroSyntax()) { @@ -1956,15 +1933,6 @@ StringRef DeclAttribute::getAttrName() const { } case DeclAttrKind::Lifetime: return "lifetime"; - case DeclAttrKind::Execution: { - switch (cast(this)->getBehavior()) { - case ExecutionKind::Concurrent: - return "execution(concurrent)"; - case ExecutionKind::Caller: - return "execution(caller)"; - } - llvm_unreachable("Invalid execution kind"); - } } llvm_unreachable("bad DeclAttrKind"); } diff --git a/lib/AST/Bridging/DeclAttributeBridging.cpp b/lib/AST/Bridging/DeclAttributeBridging.cpp index 1cb1165bf470b..a9a6654dc2342 100644 --- a/lib/AST/Bridging/DeclAttributeBridging.cpp +++ b/lib/AST/Bridging/DeclAttributeBridging.cpp @@ -627,12 +627,26 @@ BridgedNonSendableAttr BridgedNonSendableAttr_createParsed( NonSendableAttr(cAtLoc.unbridged(), cRange.unbridged(), unbridged(cKind)); } +static NonIsolatedModifier unbridged(BridgedNonIsolatedModifier modifier) { + switch (modifier) { + case BridgedNonIsolatedModifierNone: + return NonIsolatedModifier::None; + case BridgedNonIsolatedModifierUnsafe: + return NonIsolatedModifier::Unsafe; + case BridgedNonIsolatedModifierNonSending: + return NonIsolatedModifier::NonSending; + } + llvm_unreachable("unhandled enum value"); +} + BridgedNonisolatedAttr BridgedNonisolatedAttr_createParsed(BridgedASTContext cContext, BridgedSourceLoc cAtLoc, - BridgedSourceRange cRange, bool isUnsafe) { + BridgedSourceRange cRange, + BridgedNonIsolatedModifier modifier) { return new (cContext.unbridged()) NonisolatedAttr( - cAtLoc.unbridged(), cRange.unbridged(), isUnsafe, /*implicit=*/false); + cAtLoc.unbridged(), cRange.unbridged(), unbridged(modifier), + /*implicit=*/false); } BridgedObjCAttr @@ -885,22 +899,4 @@ BridgedUnavailableFromAsyncAttr BridgedUnavailableFromAsyncAttr_createParsed( return new (cContext.unbridged()) UnavailableFromAsyncAttr(cMessage.unbridged(), cAtLoc.unbridged(), cRange.unbridged(), /*implicit=*/false); -} - -static ExecutionKind unbridged(BridgedExecutionKind kind) { - switch (kind) { - case BridgedExecutionKindConcurrent: - return ExecutionKind::Concurrent; - case BridgedExecutionKindCaller: - return ExecutionKind::Caller; - } - llvm_unreachable("unhandled enum value"); -} - -BridgedExecutionAttr BridgedExecutionAttr_createParsed( - BridgedASTContext cContext, BridgedSourceLoc atLoc, - BridgedSourceRange range, BridgedExecutionKind behavior) { - return new (cContext.unbridged()) - ExecutionAttr(atLoc.unbridged(), range.unbridged(), - unbridged(behavior), /*implicit=*/false); -} +} \ No newline at end of file diff --git a/lib/AST/Bridging/TypeAttributeBridging.cpp b/lib/AST/Bridging/TypeAttributeBridging.cpp index 8f8e92537ea30..1cc5050d13f90 100644 --- a/lib/AST/Bridging/TypeAttributeBridging.cpp +++ b/lib/AST/Bridging/TypeAttributeBridging.cpp @@ -87,25 +87,6 @@ BridgedDifferentiableTypeAttr BridgedDifferentiableTypeAttr_createParsed( {unbridged(cKind), cKindLoc.unbridged()}); } -BridgedExecutionTypeAttr BridgedExecutionTypeAttr_createParsed( - BridgedASTContext cContext, BridgedSourceLoc cAtLoc, - BridgedSourceLoc cNameLoc, BridgedSourceRange cParensRange, - BridgedExecutionTypeAttrExecutionKind behavior, - BridgedSourceLoc cBehaviorLoc) { - auto behaviorKind = [=] { - switch (behavior) { - case BridgedExecutionTypeAttrExecutionKind_Concurrent: - return ExecutionKind::Concurrent; - case BridgedExecutionTypeAttrExecutionKind_Caller: - return ExecutionKind::Caller; - } - llvm_unreachable("bad kind"); - }(); - return new (cContext.unbridged()) ExecutionTypeAttr( - cAtLoc.unbridged(), cNameLoc.unbridged(), cParensRange.unbridged(), - {behaviorKind, cBehaviorLoc.unbridged()}); -} - BridgedIsolatedTypeAttr BridgedIsolatedTypeAttr_createParsed( BridgedASTContext cContext, BridgedSourceLoc cAtLoc, BridgedSourceLoc cNameLoc, BridgedSourceRange cParensRange, diff --git a/lib/AST/Bridging/TypeReprBridging.cpp b/lib/AST/Bridging/TypeReprBridging.cpp index e87a215fa363f..ea72e40ccda31 100644 --- a/lib/AST/Bridging/TypeReprBridging.cpp +++ b/lib/AST/Bridging/TypeReprBridging.cpp @@ -211,6 +211,14 @@ BridgedSendingTypeRepr_createParsed(BridgedASTContext cContext, SendingTypeRepr(base.unbridged(), cSpecifierLoc.unbridged()); } +BridgedCallerIsolatedTypeRepr +BridgedCallerIsolatedTypeRepr_createParsed(BridgedASTContext cContext, + BridgedTypeRepr base, + BridgedSourceLoc cSpecifierLoc) { + return new (cContext.unbridged()) + CallerIsolatedTypeRepr(base.unbridged(), cSpecifierLoc.unbridged()); +} + BridgedVarargTypeRepr BridgedVarargTypeRepr_createParsed(BridgedASTContext cContext, BridgedTypeRepr base, diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index ac9b1d0af9040..91c7b3378b7a5 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -8756,14 +8756,6 @@ void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const { } } -std::optional -AbstractFunctionDecl::getExecutionBehavior() const { - auto *attr = getAttrs().getAttribute(); - if (!attr) - return {}; - return attr->getBehavior(); -} - clang::PointerAuthQualifier VarDecl::getPointerAuthQualifier() const { if (auto *clangDecl = getClangDecl()) { if (auto *valueDecl = dyn_cast(clangDecl)) { diff --git a/lib/AST/FeatureSet.cpp b/lib/AST/FeatureSet.cpp index 2912d9eb5c292..b17039fa98489 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -502,42 +502,52 @@ static bool usesFeatureBuiltinEmplaceTypedThrows(Decl *decl) { return false; } -static bool usesFeatureExecutionAttribute(Decl *decl) { - if (!DeclAttribute::canAttributeAppearOnDecl(DeclAttrKind::Execution, decl)) { - return false; - } - - if (decl->getAttrs().hasAttribute()) +static bool usesFeatureAsyncExecutionBehaviorAttributes(Decl *decl) { + // Explicit `@concurrent` attribute on the declaration. + if (decl->getAttrs().hasAttribute()) return true; - auto hasExecutionAttr = [](TypeRepr *R) { + // Explicit `nonisolated(nonsending)` attribute on the declaration. + if (auto *nonisolated = decl->getAttrs().getAttribute()) { + if (nonisolated->isNonSending()) + return true; + } + + auto hasCallerIsolatedAttr = [](TypeRepr *R) { if (!R) return false; return R->findIf([](TypeRepr *repr) { - if (auto *AT = dyn_cast(repr)) { - return llvm::any_of(AT->getAttrs(), [](TypeOrCustomAttr attr) { - if (auto *TA = attr.dyn_cast()) { - return isa(TA); - } - return false; - }); - } + if (isa(repr)) + return true; + + // We don't check for @concurrent here because it's + // not printed in type positions since it indicates + // old "nonisolated" state. + return false; }); }; - auto *VD = cast(decl); + auto *VD = dyn_cast(decl); + if (!VD) + return false; + + // The declaration is going to be printed with `nonisolated(nonsending)` + // attribute. + if (getActorIsolation(VD).isCallerIsolationInheriting()) + return true; - // Check if any parameters that have `@execution` attribute. + // Check if any parameters that have `nonisolated(nonsending)` attribute. if (auto *PL = VD->getParameterList()) { - for (auto *P : *PL) { - if (hasExecutionAttr(P->getTypeRepr())) - return true; - } + if (llvm::any_of(*PL, [&](const ParamDecl *P) { + return hasCallerIsolatedAttr(P->getTypeRepr()); + })) + return true; } - if (hasExecutionAttr(VD->getResultTypeRepr())) + // Check if result type has explicit `nonisolated(nonsending)` attribute. + if (hasCallerIsolatedAttr(VD->getResultTypeRepr())) return true; return false; diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index d9d81f5644ecf..18aee3dde45f4 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -3209,6 +3209,12 @@ directReferencesForTypeRepr(Evaluator &evaluator, ASTContext &ctx, isolated->getBase(), dc, options); } + case TypeReprKind::CallerIsolated: { + auto callerIsolated = cast(typeRepr); + return directReferencesForTypeRepr(evaluator, ctx, + callerIsolated->getBase(), dc, options); + } + case TypeReprKind::Composition: { auto composition = cast(typeRepr); for (auto component : composition->getTypes()) { diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp index 0980e8dacfa50..318a9214013cf 100644 --- a/lib/AST/TypeRepr.cpp +++ b/lib/AST/TypeRepr.cpp @@ -923,6 +923,11 @@ ValueOwnership OwnershipTypeRepr::getValueOwnership() const { return ParamDecl::getValueOwnershipForSpecifier(getSpecifier()); } +void CallerIsolatedTypeRepr::printImpl(ASTPrinter &Printer, + const PrintOptions &Opts) const { + Printer.printKeyword("nonisolated(nonsending)", Opts); +} + void PlaceholderTypeRepr::printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const { Printer.printText("_"); diff --git a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift index b409845e7ede3..d82d391df629d 100644 --- a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift @@ -117,8 +117,6 @@ extension ASTGenVisitor { let attrName = identTy.name.rawText let attrKind = BridgedDeclAttrKind(from: attrName.bridged) switch attrKind { - case .execution: - return handle(self.generateExecutionAttr(attribute: node)?.asDeclAttribute) case .ABI: return handle(self.generateABIAttr(attribute: node)?.asDeclAttribute) case .alignment: @@ -197,6 +195,8 @@ extension ASTGenVisitor { return handle(self.generateSimpleDeclAttr(attribute: node, kind: .atReasync)) case .rethrows: return handle(self.generateSimpleDeclAttr(attribute: node, kind: .atRethrows)) + case .concurrent: + return handle(self.generateSimpleDeclAttr(attribute: node, kind: .concurrent)) case .none where attrName == "_unavailableInEmbedded": return handle(self.generateUnavailableInEmbeddedAttr(attribute: node)?.asDeclAttribute) @@ -359,33 +359,6 @@ extension ASTGenVisitor { return handle(self.generateCustomAttr(attribute: node)?.asDeclAttribute) } - /// E.g.: - /// ``` - /// @execution(concurrent) - /// @execution(caller) - /// ``` - func generateExecutionAttr(attribute node: AttributeSyntax) -> BridgedExecutionAttr? { - let behavior: BridgedExecutionKind? = self.generateSingleAttrOption( - attribute: node, - { - switch $0.rawText { - case "concurrent": return .concurrent - case "caller": return .caller - default: return nil - } - } - ) - guard let behavior else { - return nil - } - return .createParsed( - self.ctx, - atLoc: self.generateSourceLoc(node.atSign), - range: self.generateAttrSourceRange(node), - behavior: behavior - ) - } - /// E.g.: /// ``` /// @abi(func fn()) @@ -1415,27 +1388,25 @@ extension ASTGenVisitor { // FIXME: This is a decl modifier func generateNonisolatedAttr(attribute node: AttributeSyntax) -> BridgedNonisolatedAttr? { - let isUnsafe = self.generateSingleAttrOption( + let modifier: BridgedNonIsolatedModifier? = self.generateSingleAttrOption( attribute: node, { switch $0.rawText { - case "unsafe": - return true - default: - // FIXME: Diagnose. - return nil + case "unsafe": return .unsafe + case "nonsending": return .nonSending + default: return nil } }, - valueIfOmitted: false + valueIfOmitted: BridgedNonIsolatedModifier.none ) - guard let isUnsafe else { + guard let modifier else { return nil } return .createParsed( self.ctx, atLoc: self.generateSourceLoc(node.atSign), range: self.generateAttrSourceRange(node), - isUnsafe: isUnsafe + modifier: modifier ) } @@ -2409,12 +2380,14 @@ extension ASTGenVisitor { } func generateNonisolatedAttr(declModifier node: DeclModifierSyntax) -> BridgedNonisolatedAttr? { - let isUnsafe: Bool + let modifier: BridgedNonIsolatedModifier switch node.detail?.detail.rawText { case "unsafe": - isUnsafe = true + modifier = .unsafe + case "nonsending": + modifier = .nonSending case nil: - isUnsafe = false + modifier = .none case let text?: // TODO: Diagnose _ = text @@ -2425,7 +2398,7 @@ extension ASTGenVisitor { self.ctx, atLoc: nil, range: self.generateSourceRange(node), - isUnsafe: isUnsafe + modifier: modifier ) } diff --git a/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift b/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift index 0aea4fe145ca4..ede0bb3fb31e4 100644 --- a/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift @@ -42,6 +42,7 @@ extension ASTGenVisitor { // Simple type attributes. case .autoclosure, .addressable, + .concurrent, .escaping, .noEscape, .noDerivative, @@ -75,9 +76,6 @@ extension ASTGenVisitor { case .differentiable: return (self.generateDifferentiableTypeAttr(attribute: node)?.asTypeAttribute) .map(BridgedTypeOrCustomAttr.typeAttr(_:)) - case .execution: - return (self.generateExecutionTypeAttr(attribute: node)?.asTypeAttribute) - .map(BridgedTypeOrCustomAttr.typeAttr(_:)) case .opaqueReturnTypeOf: return (self.generateOpaqueReturnTypeOfTypeAttr(attribute: node)?.asTypeAttribute) .map(BridgedTypeOrCustomAttr.typeAttr(_:)) @@ -239,34 +237,6 @@ extension ASTGenVisitor { kindLoc: differentiabilityLoc ) } - - func generateExecutionTypeAttr(attribute node: AttributeSyntax) -> BridgedExecutionTypeAttr? { - let behaviorLoc = self.generateSourceLoc(node.arguments) - let behavior: BridgedExecutionTypeAttrExecutionKind? = self.generateSingleAttrOption( - attribute: node, - { - switch $0.rawText { - case "concurrent": return .concurrent - case "caller": return .caller - default: - // TODO: Diagnose. - return nil - } - } - ) - guard let behavior else { - return nil - } - - return .createParsed( - self.ctx, - atLoc: self.generateSourceLoc(node.atSign), - nameLoc: self.generateSourceLoc(node.attributeName), - parensRange: self.generateAttrParensRange(attribute: node), - behavior: behavior, - behaviorLoc: behaviorLoc - ) - } func generateIsolatedTypeAttr(attribute node: AttributeSyntax) -> BridgedIsolatedTypeAttr? { let isolationKindLoc = self.generateSourceLoc(node.arguments) diff --git a/lib/ASTGen/Sources/ASTGen/Types.swift b/lib/ASTGen/Sources/ASTGen/Types.swift index a0cd884131f0b..2aba9eb2c0959 100644 --- a/lib/ASTGen/Sources/ASTGen/Types.swift +++ b/lib/ASTGen/Sources/ASTGen/Types.swift @@ -362,6 +362,7 @@ extension ASTGenVisitor { var constLoc: BridgedSourceLoc = nil var sendingLoc: BridgedSourceLoc = nil var lifetimeEntry: BridgedLifetimeEntry? = nil + var nonisolatedLoc: BridgedSourceLoc = nil // TODO: Diagnostics for duplicated specifiers, and ordering. for node in node.specifiers { @@ -398,6 +399,8 @@ extension ASTGenVisitor { ), sources: node.arguments.lazy.compactMap(self.generateLifetimeDescriptor(lifetimeSpecifierArgument:)).bridgedArray(in: self) ) + case .nonisolatedTypeSpecifier(_): + nonisolatedLoc = loc } } @@ -454,6 +457,14 @@ extension ASTGenVisitor { ).asTypeRepr } + if nonisolatedLoc.isValid { + type = BridgedCallerIsolatedTypeRepr.createParsed( + self.ctx, + base: type, + specifierLoc: nonisolatedLoc + ).asTypeRepr + } + return type } } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 8920b209dfd02..8cc8e1bf8d4ff 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -8837,8 +8837,7 @@ ClangImporter::Implementation::importSwiftAttrAttributes(Decl *MappedDecl) { // Hard-code @actorIndependent, until Objective-C clients start // using nonisolated. if (swiftAttr->getAttribute() == "@actorIndependent") { - auto attr = new (SwiftContext) - NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true); + auto attr = NonisolatedAttr::createImplicit(SwiftContext); MappedDecl->getAttrs().add(attr); continue; } @@ -8971,8 +8970,8 @@ ClangImporter::Implementation::importSwiftAttrAttributes(Decl *MappedDecl) { auto *mappedVar = cast(MappedDecl); if (mappedVar->isStatic() && mappedVar->isLet() && isNSNotificationName(cast(ClangDecl)->getType())) { - MappedDecl->getAttrs().add(new (SwiftContext) NonisolatedAttr( - /*unsafe=*/false, /*implicit=*/true)); + MappedDecl->getAttrs().add( + NonisolatedAttr::createImplicit(SwiftContext)); } } } diff --git a/lib/ClangImporter/SwiftDeclSynthesizer.cpp b/lib/ClangImporter/SwiftDeclSynthesizer.cpp index 9f6762e0107a0..9b33324c55aca 100644 --- a/lib/ClangImporter/SwiftDeclSynthesizer.cpp +++ b/lib/ClangImporter/SwiftDeclSynthesizer.cpp @@ -436,9 +436,7 @@ ValueDecl *SwiftDeclSynthesizer::createConstant(Identifier name, // Mark the function transparent so that we inline it away completely. func->getAttrs().add(new (C) TransparentAttr(/*implicit*/ true)); - auto nonisolatedAttr = - new (C) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true); - var->getAttrs().add(nonisolatedAttr); + var->getAttrs().add(NonisolatedAttr::createImplicit(C)); // Set the function up as the getter. ImporterImpl.makeComputed(var, func, nullptr); diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index 15a268e8b2f83..f2799cd799507 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -3142,7 +3142,7 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth, Printer << "@isolated(any) "; return nullptr; case Node::Kind::NonIsolatedCallerFunctionType: - Printer << "@execution(caller) "; + Printer << "nonisolated(nonsending) "; return nullptr; case Node::Kind::SendingResultFunctionType: Printer << "sending "; diff --git a/lib/Migrator/APIDiffMigratorPass.cpp b/lib/Migrator/APIDiffMigratorPass.cpp index 042a6e13bc1a0..627f5fb5c1367 100644 --- a/lib/Migrator/APIDiffMigratorPass.cpp +++ b/lib/Migrator/APIDiffMigratorPass.cpp @@ -162,6 +162,10 @@ class ChildIndexFinder : public TypeReprVisitor { return visit(T->getBase()); } + FoundResult visitCallerIsolatedTypeRepr(CallerIsolatedTypeRepr *T) { + return visit(T->getBase()); + } + FoundResult visitArrayTypeRepr(ArrayTypeRepr *T) { return handleParent(T, T->getBase()); } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index f778dea293b23..c2903b5cd681a 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3744,19 +3744,20 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, } case DeclAttrKind::Nonisolated: { AttrRange = Loc; - std::optional isUnsafe(false); + std::optional Modifier(NonIsolatedModifier::None); if (EnableParameterizedNonisolated) { - isUnsafe = - parseSingleAttrOption(*this, Loc, AttrRange, AttrName, DK, - {{Context.Id_unsafe, true}}, *isUnsafe, - ParameterizedDeclAttributeKind::Nonisolated); - if (!isUnsafe) { + Modifier = parseSingleAttrOption( + *this, Loc, AttrRange, AttrName, DK, + {{Context.Id_unsafe, NonIsolatedModifier::Unsafe}, + {Context.Id_nonsending, NonIsolatedModifier::NonSending}}, + *Modifier, ParameterizedDeclAttributeKind::Nonisolated); + if (!Modifier) { return makeParserSuccess(); } } if (!DiscardAttribute) { - Attributes.add(new (Context) NonisolatedAttr(AtLoc, AttrRange, *isUnsafe, + Attributes.add(new (Context) NonisolatedAttr(AtLoc, AttrRange, *Modifier, /*implicit*/ false)); } break; @@ -3946,21 +3947,6 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, Attributes.add(Attr.get()); break; } - - case DeclAttrKind::Execution: { - auto behavior = parseSingleAttrOption( - *this, Loc, AttrRange, AttrName, DK, - {{Context.Id_concurrent, ExecutionKind::Concurrent}, - {Context.Id_caller, ExecutionKind::Caller}}); - if (!behavior) - return makeParserSuccess(); - - if (!DiscardAttribute) - Attributes.add(new (Context) ExecutionAttr(AtLoc, AttrRange, *behavior, - /*Implicit*/ false)); - - break; - } } if (DuplicateAttribute) { @@ -4246,10 +4232,6 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes, checkInvalidAttrName("_functionBuilder", "resultBuilder", DeclAttrKind::ResultBuilder, diag::attr_renamed_warning); - // Historical name for @Sendable. - checkInvalidAttrName("concurrent", "Sendable", DeclAttrKind::Sendable, - diag::attr_renamed_warning); - // Historical name for 'nonisolated'. if (!DK && Tok.getText() == "actorIndependent") { diagnose( @@ -4603,23 +4585,6 @@ ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result, // Determine which attribute it is, and diagnose it if unknown. auto optAttr = TypeAttribute::getAttrKindFromString(Tok.getText()); - auto checkInvalidAttrName = - [&](StringRef invalidName, StringRef correctName, TypeAttrKind kind, - std::optional> diag = std::nullopt) { - if (!optAttr && Tok.getText() == invalidName) { - optAttr = kind; - - if (diag) { - diagnose(Tok, *diag, invalidName, correctName) - .fixItReplace(Tok.getLoc(), correctName); - } - } - }; - - // Historical name for @Sendable. - checkInvalidAttrName("concurrent", "Sendable", TypeAttrKind::Sendable, - diag::attr_renamed_warning); - if (!optAttr) { auto declAttrID = DeclAttribute::getAttrKindFromString(Tok.getText()); if (declAttrID) { @@ -4769,56 +4734,6 @@ ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result, return makeParserSuccess(); } - case TypeAttrKind::Execution: { - if (!Context.LangOpts.hasFeature(Feature::ExecutionAttribute)) { - diagnose(Tok, diag::requires_experimental_feature, "@execution", false, - Feature::ExecutionAttribute.getName()); - return makeParserError(); - } - - SourceLoc lpLoc = Tok.getLoc(), behaviorLoc, rpLoc; - if (!consumeIfNotAtStartOfLine(tok::l_paren)) { - if (!justChecking) { - diagnose(Tok, diag::attr_execution_expected_lparen); - // TODO: should we suggest removing the `@`? - } - return makeParserError(); - } - - bool invalid = false; - std::optional behavior; - if (isIdentifier(Tok, "concurrent")) { - behaviorLoc = consumeToken(tok::identifier); - behavior = ExecutionKind::Concurrent; - } else if (isIdentifier(Tok, "caller")) { - behaviorLoc = consumeToken(tok::identifier); - behavior = ExecutionKind::Caller; - } else { - if (!justChecking) { - diagnose(Tok, diag::attr_execution_expected_kind); - } - invalid = true; - consumeIf(tok::identifier); - } - - if (justChecking && !Tok.is(tok::r_paren)) - return makeParserError(); - if (parseMatchingToken(tok::r_paren, rpLoc, - diag::attr_execution_expected_rparen, - lpLoc)) - return makeParserError(); - - if (invalid) - return makeParserError(); - assert(behavior); - - if (!justChecking) { - result = new (Context) ExecutionTypeAttr(AtLoc, attrLoc, {lpLoc, rpLoc}, - {*behavior, behaviorLoc}); - } - return makeParserSuccess(); - } - case TypeAttrKind::Opened: { // Parse the opened existential ID string in parens SourceLoc beginLoc = Tok.getLoc(), idLoc, endLoc; @@ -5321,6 +5236,7 @@ ParserStatus Parser::parseDeclModifierList(DeclAttributes &Attributes, /// '__shared' attribute-list-clause attribute-list /// '__owned' attribute-list-clause attribute-list /// 'some' attribute-list-clause attribute-list +/// 'nonisolated(nonsending)' attribute-list-clause attribute-list /// attribute-list-clause: /// '@' attribute /// '@' attribute attribute-list-clause @@ -5347,6 +5263,43 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) { continue; } + // nonisolated(nonsending) + if (Tok.isContextualKeyword("nonisolated")) { + Tok.setKind(tok::contextual_keyword); + + auto kwLoc = P.consumeToken(); + + if (CallerIsolatedLoc.isValid()) { + P.diagnose(kwLoc, diag::nonisolated_nonsending_repeated) + .fixItRemove(SpecifierLoc); + } + + // '(' + if (!P.consumeIfAttributeLParen()) { + P.diagnose(Tok, diag::nonisolated_nonsending_expected_lparen); + status.setIsParseError(); + continue; + } + + if (!Tok.isContextualKeyword("nonsending")) { + P.diagnose(Tok, diag::nonisolated_nonsending_incorrect_modifier); + status.setIsParseError(); + continue; + } + + (void)P.consumeToken(); + + // ')' + if (!P.consumeIf(tok::r_paren)) { + P.diagnose(Tok, diag::nonisolated_nonsending_expected_rparen); + status.setIsParseError(); + continue; + } + + CallerIsolatedLoc = kwLoc; + continue; + } + // Perform an extra check for 'sending'. Since it is a specifier, we use // the actual parsing logic below. if (Tok.isContextualKeyword("sending")) { @@ -5685,9 +5638,10 @@ static bool consumeIfParenthesizedUnowned(Parser &P) { } /// Given a current token of 'nonisolated', check to see if it is followed by an -/// "(unsafe)" specifier and consumes if it is. +/// "(unsafe)" or "(nonsending)" specifier and consumes if it is. static bool consumeIfParenthesizedNonisolated(Parser &P) { - return consumeIfParenthesizedModifier(P, "nonisolated", {"unsafe"}); + return consumeIfParenthesizedModifier(P, "nonisolated", + {"unsafe", "nonsending"}); } static void skipAttribute(Parser &P) { diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 9fa9e8100d8b2..75b068bacb379 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -542,8 +542,9 @@ ParserResult Parser::parseExprSequenceElement(Diag<> message, consumeToken(); } - // Try to parse '@' sign or 'inout' as a attributed typerepr. - if (Tok.isAny(tok::at_sign, tok::kw_inout)) { + // Try to parse '@' sign, 'inout' or 'nonisolated' as a attributed typerepr. + if (Tok.isAny(tok::at_sign, tok::kw_inout) || + Tok.isContextualKeyword("nonisolated")) { bool isType = false; { BacktrackingScope backtrack(*this); diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 414b6056bac9d..b2376063d9b01 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -59,6 +59,10 @@ Parser::ParsedTypeAttributeList::applyAttributesToType(Parser &p, ty = new (p.Context) SendingTypeRepr(ty, SendingLoc); } + if (CallerIsolatedLoc.isValid()) { + ty = new (p.Context) CallerIsolatedTypeRepr(ty, CallerIsolatedLoc); + } + if (lifetimeEntry) { ty = LifetimeDependentTypeRepr::create(p.Context, ty, lifetimeEntry); } @@ -1730,6 +1734,36 @@ bool Parser::canParseTypeSimpleOrComposition() { return true; } +bool Parser::canParseNonisolatedAsTypeModifier() { + assert(Tok.isContextualKeyword("nonisolated")); + + BacktrackingScope scope(*this); + + // Consume 'nonisolated' + consumeToken(); + + // Something like: + // + // nonisolated + // (42) + if (Tok.isAtStartOfLine()) + return false; + + // Always requires `(nonsending)`, together + // we don't want eagerly interpret something + // like `nonisolated(0)` as a modifier. + + if (!consumeIf(tok::l_paren)) + return false; + + if (!Tok.isContextualKeyword("nonsending")) + return false; + + consumeToken(); + + return consumeIf(tok::r_paren); +} + bool Parser::canParseTypeScalar() { // Accept 'inout' at for better recovery. consumeIf(tok::kw_inout); @@ -1737,6 +1771,16 @@ bool Parser::canParseTypeScalar() { if (Tok.isContextualKeyword("sending")) consumeToken(); + if (Tok.isContextualKeyword("nonisolated")) { + if (!canParseNonisolatedAsTypeModifier()) + return false; + + // consume 'nonisolated' + consumeToken(); + // skip '(nonsending)' + skipSingle(); + } + if (!canParseTypeSimpleOrComposition()) return false; diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 7721209473c18..a52a1608532bd 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -2622,19 +2622,23 @@ static CanSILFunctionType getSILFunctionType( { std::optional actorIsolation; if (constant) { + // TODO: It should to be possible to `getActorIsolation` if + // reference is to a decl instead of trying to get isolation + // from the reference kind, the attributes, or the context. + if (constant->kind == SILDeclRef::Kind::Deallocator) { actorIsolation = ActorIsolation::forNonisolated(false); - } else if (auto *decl = constant->getAbstractFunctionDecl(); - decl && decl->getExecutionBehavior().has_value()) { - switch (*decl->getExecutionBehavior()) { - case ExecutionKind::Concurrent: + } else if (auto *decl = constant->getAbstractFunctionDecl()) { + if (auto *nonisolatedAttr = + decl->getAttrs().getAttribute()) { + if (nonisolatedAttr->isNonSending()) + actorIsolation = ActorIsolation::forCallerIsolationInheriting(); + } else if (decl->getAttrs().hasAttribute()) { actorIsolation = ActorIsolation::forNonisolated(false /*unsafe*/); - break; - case ExecutionKind::Caller: - actorIsolation = ActorIsolation::forCallerIsolationInheriting(); - break; } - } else { + } + + if (!actorIsolation) { actorIsolation = getActorIsolationOfContext(constant->getInnermostDeclContext()); } diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 4341c4d024efd..ce1285dfb2ef1 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -489,11 +489,11 @@ namespace { SGFContext C); /// Helper method for handling function conversion expr to - /// @execution(caller). Returns an empty RValue on failure. + /// nonisolated(nonsending). Returns an empty RValue on failure. RValue emitFunctionCvtToExecutionCaller(FunctionConversionExpr *E, SGFContext C); /// Helper method for handling function conversion expr to a global actor - /// from an @execution(caller) function. + /// from an nonisolated(nonsending) function. RValue emitFunctionCvtFromExecutionCallerToGlobalActor(FunctionConversionExpr *E, SGFContext C); @@ -1968,17 +1968,17 @@ RValueEmitter::emitFunctionCvtToExecutionCaller(FunctionConversionExpr *e, // // Swift 6: // - // (fn_cvt_expr type="@execution(caller) () async -> ()" - // (fn_cvt_expr type="@execution(caller) @Sendable () async -> ()" + // (fn_cvt_expr type="nonisolated(nonsending) () async -> ()" + // (fn_cvt_expr type="nonisolated(nonsending) @Sendable () async -> ()" // (declref_expr type="() async -> ()" // // Swift 5: // - // (fn_cvt_expr type="@execution(caller) () async -> ()" + // (fn_cvt_expr type="nonisolated(nonsending) () async -> ()" // (declref_expr type="() async -> ()" // // The @Sendable in Swift 6 mode is due to us not representing - // @execution(caller) or @Sendable in the constraint evaluator. + // nonisolated(nonsending) or @Sendable in the constraint evaluator. // // The reason why we need to evaluate this especially is that otherwise we // generate multiple @@ -2038,7 +2038,7 @@ RValue RValueEmitter::emitFunctionCvtFromExecutionCallerToGlobalActor( // We are pattern matching a conversion sequence like the following: // // (fn_cvt_expr implicit type="@GlobalActor @Sendable () async -> () - // (fn_cvt_expr implicit type="@execution(caller) @Sendable () async -> ()" + // (fn_cvt_expr implicit type="nonisolated(nonsending) @Sendable () async -> ()" // (declref_expr type="() async -> ()" // // Where the declref referred to by the declref_expr has execution(caller) @@ -2047,9 +2047,9 @@ RValue RValueEmitter::emitFunctionCvtFromExecutionCallerToGlobalActor( // fix it up later. // // What we want to emit first a direct reference to the caller as an - // @execution(caller) function, then we convert it to @execution(caller) - // @Sendable. Finally, we thunk @execution(caller) to @GlobalActor. The - // thunking is important so that we can ensure that @execution(caller) runs on + // nonisolated(nonsending) function, then we convert it to nonisolated(nonsending) + // @Sendable. Finally, we thunk nonisolated(nonsending) to @GlobalActor. The + // thunking is important so that we can ensure that nonisolated(nonsending) runs on // that specific @GlobalActor. CanAnyFunctionType destType = @@ -2201,13 +2201,13 @@ RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e, } } - // Check if we are converting a function to an @execution(caller) from a - // declref that is also @execution(caller). In such a case, this was a case + // Check if we are converting a function to an nonisolated(nonsending) from a + // declref that is also nonisolated(nonsending). In such a case, this was a case // that was put in by Sema. We do not need a thunk, but just need to recognize // this case and elide the conversion. The reason why we need to do this is - // that otherwise, we put in extra thunks that convert @execution(caller) to - // @execution(concurrent) back to @execution(caller). This is done b/c we do - // not represent @execution(caller) in interface types, so the actual decl ref + // that otherwise, we put in extra thunks that convert nonisolated(nonsending) to + // @concurrent back to nonisolated(nonsending). This is done b/c we do + // not represent nonisolated(nonsending) in interface types, so the actual decl ref // will be viewed as @async () -> (). if (destType->getIsolation().isNonIsolatedCaller()) { if (RValue rv = emitFunctionCvtToExecutionCaller(e, C)) diff --git a/lib/Sema/AsyncCallerExecutionMigration.cpp b/lib/Sema/AsyncCallerExecutionMigration.cpp index 5385d386cfd93..323b2b901e316 100644 --- a/lib/Sema/AsyncCallerExecutionMigration.cpp +++ b/lib/Sema/AsyncCallerExecutionMigration.cpp @@ -50,8 +50,8 @@ class AsyncCallerExecutionMigrationTarget { : ctx(ctx), node(repr), isolation(isolation) {} /// Warns that the behavior of nonisolated async functions will change under - /// `AsyncCallerExecution` and suggests `@execution(concurrent)` to preserve - /// the current behavior. + /// `AsyncCallerExecution` and suggests `@concurrent` to preserve the current + /// behavior. void diagnose() const; }; } // end anonymous namespace @@ -74,7 +74,7 @@ void AsyncCallerExecutionMigrationTarget::diagnose() const { // If the attribute cannot appear on this kind of declaration, we can't // diagnose it. - if (!DeclAttribute::canAttributeAppearOnDecl(DeclAttrKind::Execution, + if (!DeclAttribute::canAttributeAppearOnDecl(DeclAttrKind::Concurrent, decl)) { return; } @@ -121,8 +121,14 @@ void AsyncCallerExecutionMigrationTarget::diagnose() const { attrs = &closure->getAttrs(); } - if (attrs && attrs->hasAttribute()) { - return; + if (attrs) { + if (attrs->hasAttribute()) + return; + + if (auto *nonisolated = attrs->getAttribute()) { + if (nonisolated->isNonSending()) + return; + } } } @@ -142,7 +148,7 @@ void AsyncCallerExecutionMigrationTarget::diagnose() const { } } - const ExecutionAttr attr(ExecutionKind::Concurrent, /*implicit=*/true); + const ConcurrentAttr attr(/*implicit=*/true); const auto featureName = feature.getName(); if (decl) { diff --git a/lib/Sema/AsyncCallerExecutionMigration.h b/lib/Sema/AsyncCallerExecutionMigration.h index 31a3218c18b66..9086f90d3de43 100644 --- a/lib/Sema/AsyncCallerExecutionMigration.h +++ b/lib/Sema/AsyncCallerExecutionMigration.h @@ -29,21 +29,21 @@ class ValueDecl; class AbstractClosureExpr; /// Warns that the behavior of nonisolated async functions will change under -/// `AsyncCallerExecution` and suggests `@execution(concurrent)` to preserve -/// the current behavior. +/// `AsyncCallerExecution` and suggests `@concurrent` to preserve the current +/// behavior. void warnAboutNewNonisolatedAsyncExecutionBehavior( ASTContext &ctx, FunctionTypeRepr *node, FunctionTypeIsolation isolation); /// Warns that the behavior of nonisolated async functions will change under -/// `AsyncCallerExecution` and suggests `@execution(concurrent)` to preserve -/// the current behavior. +/// `AsyncCallerExecution` and suggests `@concurrent` to preserve the current +/// behavior. void warnAboutNewNonisolatedAsyncExecutionBehavior(ASTContext &ctx, ValueDecl *node, ActorIsolation isolation); /// Warns that the behavior of nonisolated async functions will change under -/// `AsyncCallerExecution` and suggests `@execution(concurrent)` to preserve -/// the current behavior. +/// `AsyncCallerExecution` and suggests `@concurrent` to preserve the current +/// behavior. void warnAboutNewNonisolatedAsyncExecutionBehavior(ASTContext &ctx, AbstractClosureExpr *node, ActorIsolation isolation); diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index d72f5621a505e..e3b267dadbab9 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2584,14 +2584,8 @@ namespace { return FunctionTypeIsolation::forGlobalActor(actorType); } - if (auto *execution = - closure->getAttrs().getAttribute()) { - switch (execution->getBehavior()) { - case ExecutionKind::Caller: - return FunctionTypeIsolation::forNonIsolatedCaller(); - case ExecutionKind::Concurrent: - return FunctionTypeIsolation::forNonIsolated(); - } + if (closure->getAttrs().hasAttribute()) { + return FunctionTypeIsolation::forNonIsolated(); } return FunctionTypeIsolation::forNonIsolated(); @@ -4591,8 +4585,8 @@ generateForEachStmtConstraints(ConstraintSystem &cs, DeclContext *dc, // non-`Sendable` state across the isolation boundary. `next()` should // inherit the isolation of the caller, but for now, use the opt out. if (isAsync) { - auto *nonisolated = new (ctx) - NonisolatedAttr(/*unsafe=*/true, /*implicit=*/true); + auto *nonisolated = + NonisolatedAttr::createImplicit(ctx, NonIsolatedModifier::Unsafe); makeIteratorVar->getAttrs().add(nonisolated); } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index ea4632232da0b..6b17d69da49d5 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -3303,14 +3303,14 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2, SmallVector func2Params; func2Params.append(func2->getParams().begin(), func2->getParams().end()); - // Support conversion from `@execution(caller)` to a function type + // Support conversion from `nonisolated(nonsending)` to a function type // with an isolated parameter. if (subKind == ConstraintKind::Subtype && func1->getIsolation().isNonIsolatedCaller() && func2->getIsolation().isParameter()) { - // `@execution(caller)` function gets an implicit isolation parameter - // introduced during SILGen and thunk is going to forward an isolation - // from the caller to it. + // `nonisolated(nonsending)` function gets an implicit isolation parameter + // introduced during SILGen and thunk is going to forward an isolation from + // the caller to it. // Let's remove the isolated parameter from consideration, function // types have to match on everything else. llvm::erase_if(func2Params, [](const AnyFunctionType::Param ¶m) { diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 2a16ded2740b2..91b0b36b9c620 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -1738,8 +1738,7 @@ bool swift::addNonIsolatedToSynthesized(NominalTypeDecl *nominal, return false; ASTContext &ctx = nominal->getASTContext(); - value->getAttrs().add( - new (ctx) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true)); + value->getAttrs().add(NonisolatedAttr::createImplicit(ctx)); return true; } diff --git a/lib/Sema/CodeSynthesisDistributedActor.cpp b/lib/Sema/CodeSynthesisDistributedActor.cpp index 637a5b1ad3192..591e26b5c1867 100644 --- a/lib/Sema/CodeSynthesisDistributedActor.cpp +++ b/lib/Sema/CodeSynthesisDistributedActor.cpp @@ -110,8 +110,7 @@ static VarDecl *addImplicitDistributedActorIDProperty( nominal); // mark as nonisolated, allowing access to it from everywhere - propDecl->getAttrs().add( - new (C) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true)); + propDecl->getAttrs().add(NonisolatedAttr::createImplicit(C)); // mark as @_compilerInitialized, since we synthesize the initializing // assignment during SILGen. propDecl->getAttrs().add( @@ -161,8 +160,7 @@ static VarDecl *addImplicitDistributedActorActorSystemProperty( nominal); // mark as nonisolated, allowing access to it from everywhere - propDecl->getAttrs().add( - new (C) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true)); + propDecl->getAttrs().add(NonisolatedAttr::createImplicit(C)); auto idProperty = nominal->getDistributedActorIDProperty(); // If the id was not yet synthesized, we need to ensure that eventually @@ -739,8 +737,7 @@ static FuncDecl *createSameSignatureDistributedThunkDecl(DeclContext *DC, thunk->setSynthesized(true); thunk->setDistributedThunk(true); - thunk->getAttrs().add( - new (C) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true)); + thunk->getAttrs().add(NonisolatedAttr::createImplicit(C)); return thunk; } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 1a6bb0ee54208..a4d1b99dd4603 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -1414,8 +1414,8 @@ FunctionType::ExtInfo ClosureEffectsRequest::evaluate( bool async = expr->getAsyncLoc().isValid(); bool sendable = expr->getAttrs().hasAttribute(); - // `@execution(...)` attribute is only valid on asynchronous function types. - if (expr->getAttrs().hasAttribute()) { + // `@concurrent` attribute is only valid on asynchronous function types. + if (expr->getAttrs().hasAttribute()) { async = true; } diff --git a/lib/Sema/DerivedConformance/DerivedConformanceActor.cpp b/lib/Sema/DerivedConformance/DerivedConformanceActor.cpp index 7fdcb683096fa..24066b7ddb8a0 100644 --- a/lib/Sema/DerivedConformance/DerivedConformanceActor.cpp +++ b/lib/Sema/DerivedConformance/DerivedConformanceActor.cpp @@ -147,8 +147,7 @@ static ValueDecl *deriveActor_unownedExecutor(DerivedConformance &derived) { property->getAttrs().add(new (ctx) SemanticsAttr(SEMANTICS_DEFAULT_ACTOR, SourceLoc(), SourceRange(), /*implicit*/ true)); - property->getAttrs().add( - new (ctx) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true)); + property->getAttrs().add(NonisolatedAttr::createImplicit(ctx)); // Make the property implicitly final. property->getAttrs().add(new (ctx) FinalAttr(/*IsImplicit=*/true)); diff --git a/lib/Sema/DerivedConformance/DerivedConformanceCaseIterable.cpp b/lib/Sema/DerivedConformance/DerivedConformanceCaseIterable.cpp index dfdb509013b70..625032b92cd1c 100644 --- a/lib/Sema/DerivedConformance/DerivedConformanceCaseIterable.cpp +++ b/lib/Sema/DerivedConformance/DerivedConformanceCaseIterable.cpp @@ -105,8 +105,7 @@ ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) { SynthesizedIntroducer::Var, Context.Id_allCases, returnTy, /*isStatic=*/true, /*isFinal=*/true); - propDecl->getAttrs().add( - new (C) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true)); + propDecl->getAttrs().add(NonisolatedAttr::createImplicit(C)); // Define the getter. auto *getterDecl = addGetterToReadOnlyDerivedProperty(propDecl); diff --git a/lib/Sema/DerivedConformance/DerivedConformanceDistributedActor.cpp b/lib/Sema/DerivedConformance/DerivedConformanceDistributedActor.cpp index 2dc2831712d06..c7b0fc44fd114 100644 --- a/lib/Sema/DerivedConformance/DerivedConformanceDistributedActor.cpp +++ b/lib/Sema/DerivedConformance/DerivedConformanceDistributedActor.cpp @@ -465,8 +465,7 @@ static ValueDecl *deriveDistributedActor_id(DerivedConformance &derived) { /*isStatic=*/false, /*isFinal=*/true); // mark as nonisolated, allowing access to it from everywhere - propDecl->getAttrs().add( - new (C) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true)); + propDecl->getAttrs().add(NonisolatedAttr::createImplicit(C)); derived.addMemberToConformanceContext(pbDecl, /*insertAtHead=*/true); derived.addMemberToConformanceContext(propDecl, /*insertAtHead=*/true); @@ -496,8 +495,7 @@ static ValueDecl *deriveDistributedActor_actorSystem( propertyType, /*isStatic=*/false, /*isFinal=*/true); // mark as nonisolated, allowing access to it from everywhere - propDecl->getAttrs().add( - new (C) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true)); + propDecl->getAttrs().add(NonisolatedAttr::createImplicit(C)); // IMPORTANT: `id` MUST be the first field of a distributed actor, and // `actorSystem` MUST be the second field, because for a remote instance @@ -795,8 +793,7 @@ static ValueDecl *deriveDistributedActor_unownedExecutor(DerivedConformance &der property->getAttrs().add(new (ctx) SemanticsAttr(SEMANTICS_DEFAULT_ACTOR, SourceLoc(), SourceRange(), /*implicit*/ true)); - property->getAttrs().add( - new (ctx) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true)); + property->getAttrs().add(NonisolatedAttr::createImplicit(ctx)); // Make the property implicitly final. property->getAttrs().add(new (ctx) FinalAttr(/*IsImplicit=*/true)); diff --git a/lib/Sema/DerivedConformance/DerivedConformanceEquatableHashable.cpp b/lib/Sema/DerivedConformance/DerivedConformanceEquatableHashable.cpp index 45021cf1f21e3..d8b0cb8a61440 100644 --- a/lib/Sema/DerivedConformance/DerivedConformanceEquatableHashable.cpp +++ b/lib/Sema/DerivedConformance/DerivedConformanceEquatableHashable.cpp @@ -555,8 +555,7 @@ deriveHashable_hashInto( // The derived hash(into:) for an actor must be non-isolated. if (!addNonIsolatedToSynthesized(derived, hashDecl) && derived.Nominal->isActor()) - hashDecl->getAttrs().add( - new (C) NonisolatedAttr(/*unsafe*/ false, /*implicit*/ true)); + hashDecl->getAttrs().add(NonisolatedAttr::createImplicit(C)); derived.addMembersToConformanceContext({hashDecl}); @@ -912,8 +911,7 @@ static ValueDecl *deriveHashable_hashValue(DerivedConformance &derived) { // The derived hashValue of an actor must be nonisolated. if (!addNonIsolatedToSynthesized(derived, hashValueDecl) && derived.Nominal->isActor()) - hashValueDecl->getAttrs().add( - new (C) NonisolatedAttr(/*unsafe*/ false, /*implicit*/ true)); + hashValueDecl->getAttrs().add(NonisolatedAttr::createImplicit(C)); Pattern *hashValuePat = NamedPattern::createImplicit(C, hashValueDecl, intType); diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 4b4b337fb08eb..656db55f364ef 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -198,7 +198,7 @@ class AttributeChecker : public AttributeVisitor { TypeChecker::checkDeclABIAttribute(D, attr); } - void visitExecutionAttr(ExecutionAttr *attr) { + void checkExecutionBehaviorAttribute(DeclAttribute *attr) { auto *const decl = cast(D); auto *const storage = dyn_cast(decl); @@ -208,7 +208,8 @@ class AttributeChecker : public AttributeVisitor { } if (!decl->isAsync()) { - diagnoseAndRemoveAttr(attr, diag::attr_execution_only_on_async, decl); + diagnoseAndRemoveAttr(attr, diag::execution_behavior_only_on_async, attr, + decl); return; } @@ -224,8 +225,8 @@ class AttributeChecker : public AttributeVisitor { // isolated parameters affect isolation of the function itself if (isa(repr)) { diagnoseAndRemoveAttr( - attr, diag::attr_execution_incompatible_isolated_parameter, decl, - P); + attr, diag::execution_behavior_incompatible_isolated_parameter, + attr, decl, P); return; } @@ -233,8 +234,9 @@ class AttributeChecker : public AttributeVisitor { if (attrType->has(TypeAttrKind::Isolated)) { diagnoseAndRemoveAttr( attr, - diag::attr_execution_incompatible_dynamically_isolated_parameter, - decl, P); + diag:: + execution_behavior_incompatible_dynamically_isolated_parameter, + attr, decl, P); return; } } @@ -256,6 +258,16 @@ class AttributeChecker : public AttributeVisitor { } } + void visitConcurrentAttr(ConcurrentAttr *attr) { + checkExecutionBehaviorAttribute(attr); + + if (auto *nonisolated = D->getAttrs().getAttribute()) { + if (nonisolated->isNonSending()) + diagnoseAndRemoveAttr(attr, diag::actor_isolation_multiple_attr_2, D, + attr, nonisolated); + } + } + void visitAlignmentAttr(AlignmentAttr *attr) { // Alignment must be a power of two. auto value = attr->getValue(); @@ -4313,7 +4325,7 @@ static void checkGlobalActorAttr( std::pair &globalActorAttr) { auto isolatedAttr = decl->getAttrs().getAttribute(); auto nonisolatedAttr = decl->getAttrs().getAttribute(); - auto executionAttr = decl->getAttrs().getAttribute(); + auto concurrentAttr = decl->getAttrs().getAttribute(); llvm::SmallVector attributes; @@ -4325,10 +4337,9 @@ static void checkGlobalActorAttr( if (nonisolatedAttr) { attributes.push_back(nonisolatedAttr); } - if (executionAttr) { - attributes.push_back(executionAttr); + if (concurrentAttr) { + attributes.push_back(concurrentAttr); } - if (attributes.size() == 1) return; @@ -7529,6 +7540,19 @@ void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) { // that do not have storage. auto dc = D->getDeclContext(); + if (attr->isNonSending()) { + // Just like `@concurrent` this form of `nonisolated` is only + // applicable to certain declarations. + if (!DeclAttribute::canAttributeAppearOnDecl(DeclAttrKind::Concurrent, D)) { + diagnoseAndRemoveAttr( + attr, diag::cannot_specify_execution_behavior_for_decl, attr); + return; + } + + checkExecutionBehaviorAttribute(attr); + return; + } + if (auto var = dyn_cast(D)) { // stored properties have limitations as to when they can be nonisolated. auto type = var->getTypeInContext(); @@ -8143,18 +8167,13 @@ class ClosureAttributeChecker // Nothing else to check. } - void visitExecutionAttr(ExecutionAttr *attr) { - if (!ctx.LangOpts.hasFeature(Feature::ExecutionAttribute)) { - visitDeclAttribute(attr); - return; - } - - // `@execution(...)` implies `async`. + void checkExecutionBehaviorAttribute(DeclAttribute *attr) { + // execution behavior attribute implies `async`. if (closure->hasExplicitResultType() && closure->getAsyncLoc().isInvalid()) { ctx.Diags .diagnose(attr->getLocation(), - diag::attr_execution_only_on_async_closure) + diag::execution_behavior_only_on_async_closure, attr) .fixItRemove(attr->getRangeWithAt()); attr->setInvalid(); } @@ -8163,8 +8182,8 @@ class ClosureAttributeChecker ctx.Diags .diagnose( attr->getLocation(), - diag::attr_execution_type_attr_incompatible_with_global_isolation, - actorType) + diag::execution_behavior_attr_incompatible_with_global_isolation, + attr, actorType) .fixItRemove(attr->getRangeWithAt()); attr->setInvalid(); } @@ -8174,13 +8193,18 @@ class ClosureAttributeChecker ctx.Diags .diagnose( attr->getLocation(), - diag::attr_execution_type_attr_incompatible_with_isolated_param) + diag::execution_behavior_attr_incompatible_with_isolated_param, + attr) .fixItRemove(attr->getRangeWithAt()); attr->setInvalid(); } } } + void visitConcurrentAttr(ConcurrentAttr *attr) { + checkExecutionBehaviorAttribute(attr); + } + void visitNonisolatedAttr(NonisolatedAttr *attr) { if (attr->isUnsafe() || !ctx.LangOpts.hasFeature(Feature::ClosureIsolation)) { diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 006c6652f4eae..7de922e041531 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -2712,16 +2712,16 @@ namespace { return; switch (toIsolation.getKind()) { - // Converting to `@execution(caller)` function type + // Converting to `nonisolated(nonsending)` function type case FunctionTypeIsolation::Kind::NonIsolatedCaller: { switch (fromIsolation.getKind()) { case FunctionTypeIsolation::Kind::NonIsolated: { - // nonisolated -> @execution(caller) doesn't cross + // nonisolated -> nonisolated(nonsending) doesn't cross // an isolation boundary. if (!fromFnType->isAsync()) break; - // @execution(concurrent) -> @execution(caller) + // @concurrent -> nonisolated(nonsending) // crosses an isolation boundary. LLVM_FALLTHROUGH; } @@ -2744,9 +2744,9 @@ namespace { break; } - // Converting to nonisolated synchronous or @execution(concurrent) - // asynchronous function type could require crossing an isolation - // boundary. + // Converting to nonisolated synchronous or @concurrent + // asynchronous function type could require crossing an + // isolation boundary. case FunctionTypeIsolation::Kind::NonIsolated: { switch (fromIsolation.getKind()) { case FunctionTypeIsolation::Kind::Parameter: @@ -2762,7 +2762,7 @@ namespace { } case FunctionTypeIsolation::Kind::NonIsolated: { - // nonisolated synchronous <-> @execution(concurrent) + // nonisolated synchronous <-> @concurrent if (fromFnType->isAsync() != toFnType->isAsync()) { diagnoseNonSendableParametersAndResult( toFnType, /*downgradeToWarning=*/true); @@ -2784,10 +2784,10 @@ namespace { break; case FunctionTypeIsolation::Kind::NonIsolated: { - // Since @execution(concurrent) as an asynchronous - // function it would mean that without Sendable - // check it would be possible for non-Sendable state - // to escape from actor isolation. + // Since @concurrent as an asynchronous function it + // would mean that without Sendable check it would + // be possible for non-Sendable state to escape from + // actor isolation. if (fromFnType->isAsync()) { diagnoseNonSendableParametersAndResult( toFnType, /*downgradeToWarning=*/true); @@ -4889,7 +4889,7 @@ getIsolationFromAttributes(const Decl *decl, bool shouldDiagnose = true, auto isolatedAttr = decl->getAttrs().getAttribute(); auto nonisolatedAttr = decl->getAttrs().getAttribute(); auto globalActorAttr = decl->getGlobalActorAttr(); - auto concurrentExecutionAttr = decl->getAttrs().getAttribute(); + auto concurrentAttr = decl->getAttrs().getAttribute(); // Remove implicit attributes if we only care about explicit ones. if (onlyExplicit) { @@ -4899,13 +4899,13 @@ getIsolationFromAttributes(const Decl *decl, bool shouldDiagnose = true, isolatedAttr = nullptr; if (globalActorAttr && globalActorAttr->first->isImplicit()) globalActorAttr = std::nullopt; - if (concurrentExecutionAttr && concurrentExecutionAttr->isImplicit()) - concurrentExecutionAttr = nullptr; + if (concurrentAttr && concurrentAttr->isImplicit()) + concurrentAttr = nullptr; } unsigned numIsolationAttrs = (isolatedAttr ? 1 : 0) + (nonisolatedAttr ? 1 : 0) + - (globalActorAttr ? 1 : 0) + (concurrentExecutionAttr ? 1 : 0); + (globalActorAttr ? 1 : 0) + (concurrentAttr ? 1 : 0); if (numIsolationAttrs == 0) { if (isa(decl) && !decl->isImplicit()) { return ActorIsolation::forNonisolated(false); @@ -4913,28 +4913,18 @@ getIsolationFromAttributes(const Decl *decl, bool shouldDiagnose = true, return std::nullopt; } - // If the declaration is explicitly marked with 'execution', return the - // appropriate isolation. - // - // NOTE: This needs to occur before we handle an explicit nonisolated attr, - // since if @execution and nonisolated are used together, we want to ensure - // that @execution takes priority. This ensures that if we import code from a - // module that was compiled with a different value for AsyncCallerExecution, - // we get the semantics of the source module. - if (concurrentExecutionAttr) { - switch (concurrentExecutionAttr->getBehavior()) { - case ExecutionKind::Concurrent: - return ActorIsolation::forNonisolated(false /*is unsafe*/); - case ExecutionKind::Caller: - return ActorIsolation::forCallerIsolationInheriting(); - } - } + if (concurrentAttr) + return ActorIsolation::forNonisolated(/*is unsafe*/ false); // If the declaration is explicitly marked 'nonisolated', report it as // independent. if (nonisolatedAttr) { - // If the nonisolated async inherits isolation from context is set, return - // caller isolation inheriting. + // 'nonisolated(nonsending)' modifier is set on the decl. + if (nonisolatedAttr->isNonSending()) + return ActorIsolation::forCallerIsolationInheriting(); + + // If the nonisolated async inherits isolation from context, + // return caller isolation inheriting. if (decl->getASTContext().LangOpts.hasFeature( Feature::AsyncCallerExecution)) { if (auto *func = dyn_cast(decl); @@ -5695,13 +5685,16 @@ static void addAttributesForActorIsolation(ValueDecl *value, ASTContext &ctx = value->getASTContext(); switch (isolation) { case ActorIsolation::CallerIsolationInheriting: - value->getAttrs().add(new (ctx) ExecutionAttr(ExecutionKind::Caller, - /*implicit=*/true)); + value->getAttrs().add(new (ctx) NonisolatedAttr( + /*atLoc=*/{}, /*range=*/{}, NonIsolatedModifier::NonSending, + /*implicit=*/true)); break; case ActorIsolation::Nonisolated: case ActorIsolation::NonisolatedUnsafe: { - value->getAttrs().add(new (ctx) NonisolatedAttr( - isolation == ActorIsolation::NonisolatedUnsafe, /*implicit=*/true)); + value->getAttrs().add(NonisolatedAttr::createImplicit( + ctx, isolation == ActorIsolation::NonisolatedUnsafe + ? NonIsolatedModifier::Unsafe + : NonIsolatedModifier::None)); break; } case ActorIsolation::GlobalActor: { @@ -5889,10 +5882,12 @@ static InferredActorIsolation computeActorIsolation(Evaluator &evaluator, // as nonisolated but since AsyncCallerExecution is enabled, we return // CallerIsolationInheriting. if (isolationFromAttr && isolationFromAttr->getKind() == - ActorIsolation::CallerIsolationInheriting && - !value->getAttrs().hasAttribute()) { - value->getAttrs().add(new (ctx) ExecutionAttr(ExecutionKind::Caller, - /*implicit=*/true)); + ActorIsolation::CallerIsolationInheriting) { + auto nonisolated = value->getAttrs().getAttribute(); + if (!nonisolated || !nonisolated->isNonSending()) + value->getAttrs().add(new (ctx) NonisolatedAttr( + /*atLoc*/ {}, /*range=*/{}, NonIsolatedModifier::NonSending, + /*implicit=*/true)); } if (auto *fd = dyn_cast(value)) { diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 4aeeeec1f98cf..0089ccc9da1a1 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2272,6 +2272,10 @@ ParamSpecifierRequest::evaluate(Evaluator &evaluator, nestedRepr = lifetime->getBase(); } + if (auto callerIsolated = dyn_cast(nestedRepr)) { + nestedRepr = callerIsolated->getBase(); + } + if (auto sending = dyn_cast(nestedRepr)) { // If we do not have an Ownership Repr and do not have a no escape type, // return implicit copyable consuming. @@ -2294,7 +2298,7 @@ ParamSpecifierRequest::evaluate(Evaluator &evaluator, } return ownershipRepr->getSpecifier(); } - + return ParamSpecifier::Default; } diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index 7218b3c0aee9f..62a7ea1797b99 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1588,13 +1588,13 @@ namespace { UNINTERESTING_ATTR(Borrowed) UNINTERESTING_ATTR(Borrowing) UNINTERESTING_ATTR(CDecl) + UNINTERESTING_ATTR(Concurrent) UNINTERESTING_ATTR(Consuming) UNINTERESTING_ATTR(Documentation) UNINTERESTING_ATTR(Dynamic) UNINTERESTING_ATTR(DynamicCallable) UNINTERESTING_ATTR(DynamicMemberLookup) UNINTERESTING_ATTR(SILGenName) - UNINTERESTING_ATTR(Execution) UNINTERESTING_ATTR(Exported) UNINTERESTING_ATTR(ForbidSerializingReference) UNINTERESTING_ATTR(GKInspectable) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index d1432534b11db..bac339da6ef9d 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -2324,6 +2324,8 @@ namespace { TypeResolutionOptions options); NeverNullType resolveSendingTypeRepr(SendingTypeRepr *repr, TypeResolutionOptions options); + NeverNullType resolveCallerIsolatedTypeRepr(CallerIsolatedTypeRepr *repr, + TypeResolutionOptions options); NeverNullType resolveCompileTimeLiteralTypeRepr(CompileTimeLiteralTypeRepr *repr, TypeResolutionOptions options); @@ -2730,7 +2732,8 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr, !isa(repr) && !isa(repr) && !isa(repr) && !isa(repr) && !isa(repr) && !isa(repr) && - !isa(repr)) { + !isa(repr) && + !isa(repr)) { options.setContext(std::nullopt); } @@ -2753,6 +2756,9 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr, return resolveIsolatedTypeRepr(cast(repr), options); case TypeReprKind::Sending: return resolveSendingTypeRepr(cast(repr), options); + case TypeReprKind::CallerIsolated: + return resolveCallerIsolatedTypeRepr(cast(repr), + options); case TypeReprKind::CompileTimeLiteral: return resolveCompileTimeLiteralTypeRepr(cast(repr), options); @@ -4195,10 +4201,11 @@ NeverNullType TypeResolver::resolveASTFunctionType( } } - if (auto executionAttr = claim(attrs)) { + auto checkExecutionBehaviorAttribute = [&](TypeAttribute *attr) { if (!repr->isAsync()) { - diagnoseInvalid(repr, executionAttr->getAtLoc(), - diag::attr_execution_type_attr_only_on_async); + diagnoseInvalid(repr, attr->getAttrLoc(), + diag::execution_behavior_type_attr_only_on_async, + attr->getAttrName()); } switch (isolation.getKind()) { @@ -4207,38 +4214,36 @@ NeverNullType TypeResolver::resolveASTFunctionType( case FunctionTypeIsolation::Kind::GlobalActor: diagnoseInvalid( - repr, executionAttr->getAtLoc(), - diag::attr_execution_type_attr_incompatible_with_global_isolation, - isolation.getGlobalActorType()); + repr, attr->getAttrLoc(), + diag::execution_behavior_type_attr_incompatible_with_global_isolation, + attr->getAttrName(), isolation.getGlobalActorType()); break; case FunctionTypeIsolation::Kind::Parameter: diagnoseInvalid( - repr, executionAttr->getAtLoc(), - diag::attr_execution_type_attr_incompatible_with_isolated_param); + repr, attr->getAttrLoc(), + diag::execution_behavior_type_attr_incompatible_with_isolated_param, + attr->getAttrName()); break; case FunctionTypeIsolation::Kind::Erased: diagnoseInvalid( - repr, executionAttr->getAtLoc(), - diag::attr_execution_type_attr_incompatible_with_isolated_any); + repr, attr->getAttrLoc(), + diag::execution_behavior_type_attr_incompatible_with_isolated_any, + attr->getAttrName()); break; case FunctionTypeIsolation::Kind::NonIsolatedCaller: - llvm_unreachable("cannot happen because multiple @execution attributes " - "aren't allowed."); + llvm_unreachable( + "cannot happen because multiple execution behavior attributes " + "aren't allowed."); } + }; - if (!repr->isInvalid()) { - switch (executionAttr->getBehavior()) { - case ExecutionKind::Concurrent: - isolation = FunctionTypeIsolation::forNonIsolated(); - break; - case ExecutionKind::Caller: - isolation = FunctionTypeIsolation::forNonIsolatedCaller(); - break; - } - } + if (auto concurrentAttr = claim(attrs)) { + checkExecutionBehaviorAttribute(concurrentAttr); + if (!repr->isInvalid()) + isolation = FunctionTypeIsolation::forNonIsolated(); } else { if (ctx.LangOpts.getFeatureState(Feature::AsyncCallerExecution) .isEnabledForAdoption()) { @@ -5267,6 +5272,69 @@ TypeResolver::resolveSendingTypeRepr(SendingTypeRepr *repr, return resolveType(repr->getBase(), options); } +NeverNullType +TypeResolver::resolveCallerIsolatedTypeRepr(CallerIsolatedTypeRepr *repr, + TypeResolutionOptions options) { + Type type = resolveType(repr->getBase(), options); + if (type->hasError()) + return ErrorType::get(getASTContext()); + + auto *fnType = dyn_cast(type.getPointer()); + if (!fnType) { + diagnoseInvalid(repr, repr->getStartLoc(), + diag::nonisolated_nonsending_only_on_function_types, repr); + return ErrorType::get(getASTContext()); + } + + if (!fnType->isAsync()) { + diagnoseInvalid(repr, repr->getStartLoc(), + diag::nonisolated_nonsending_only_on_async, repr); + } + + if (auto *ATR = dyn_cast(repr->getBase())) { + if (ATR->get(TypeAttrKind::Concurrent)) { + diagnoseInvalid( + repr, repr->getStartLoc(), + diag::cannot_use_nonisolated_nonsending_together_with_concurrent, + repr); + } + } + + switch (fnType->getIsolation().getKind()) { + case FunctionTypeIsolation::Kind::NonIsolated: + break; + + case FunctionTypeIsolation::Kind::GlobalActor: + diagnoseInvalid( + repr, repr->getStartLoc(), + diag::nonisolated_nonsending_incompatible_with_global_isolation, repr, + fnType->getIsolation().getGlobalActorType()); + break; + + case FunctionTypeIsolation::Kind::Parameter: + diagnoseInvalid( + repr, repr->getStartLoc(), + diag::nonisolated_nonsending_incompatible_with_isolated_param, repr); + break; + + case FunctionTypeIsolation::Kind::Erased: + diagnoseInvalid(repr, repr->getStartLoc(), + diag::nonisolated_nonsending_incompatible_with_isolated_any, + repr); + break; + + case FunctionTypeIsolation::Kind::NonIsolatedCaller: + llvm_unreachable( + "cannot happen because multiple nonisolated(nonsending) attributes " + "aren't allowed."); + } + + if (repr->isInvalid()) + return ErrorType::get(getASTContext()); + + return fnType->withIsolation(FunctionTypeIsolation::forNonIsolatedCaller()); +} + NeverNullType TypeResolver::resolveCompileTimeLiteralTypeRepr(CompileTimeLiteralTypeRepr *repr, TypeResolutionOptions options) { @@ -6387,6 +6455,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker { case TypeReprKind::PackElement: case TypeReprKind::LifetimeDependent: case TypeReprKind::Integer: + case TypeReprKind::CallerIsolated: return false; } } diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index eac0003ef183e..18b8bec1cf0cd 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -5922,14 +5922,6 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() { DeclAttribute *Attr = nullptr; bool skipAttr = false; switch (recordID) { - case decls_block::Execution_DECL_ATTR: { - unsigned behavior; - serialization::decls_block::ExecutionDeclAttrLayout::readRecord( - scratch, behavior); - Attr = new (ctx) ExecutionAttr(static_cast(behavior), - /*Implicit=*/false); - break; - } case decls_block::ABI_DECL_ATTR: { bool isImplicit; DeclID abiDeclID; @@ -6513,11 +6505,12 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() { } case decls_block::Nonisolated_DECL_ATTR: { - bool isUnsafe{}; + unsigned modifier; bool isImplicit{}; serialization::decls_block::NonisolatedDeclAttrLayout::readRecord( - scratch, isUnsafe, isImplicit); - Attr = new (ctx) NonisolatedAttr(isUnsafe, isImplicit); + scratch, modifier, isImplicit); + Attr = new (ctx) NonisolatedAttr( + {}, {}, static_cast(modifier), isImplicit); break; } diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index eac43d54380bd..b6cdd8baa2c99 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 = 938; // custom AvailabilityDomains +const uint16_t SWIFTMODULE_VERSION_MINOR = 941; // remove @execution attr /// A standard hash seed used for all string hashes in a serialized module. /// @@ -2388,11 +2388,6 @@ namespace decls_block { BCFixed<2> // exclusivity mode >; - using ExecutionDeclAttrLayout = BCRecordLayout< - Execution_DECL_ATTR, - BCFixed<1> // execution behavior kind - >; - using ABIDeclAttrLayout = BCRecordLayout< ABI_DECL_ATTR, BCFixed<1>, // implicit flag @@ -2551,7 +2546,7 @@ namespace decls_block { using NonisolatedDeclAttrLayout = BCRecordLayout, // is the argument (unsafe) + BCFixed<2>, // the modifier (unsafe, nonsending) BCFixed<1> // implicit flag >; diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 742bbb0ff7a12..30cbe6d47a1c4 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -2938,15 +2938,6 @@ class Serializer::DeclSerializer : public DeclVisitor { } #include "swift/AST/DeclAttr.def" - case DeclAttrKind::Execution: { - auto *theAttr = cast(DA); - auto abbrCode = S.DeclTypeAbbrCodes[ExecutionDeclAttrLayout::Code]; - ExecutionDeclAttrLayout::emitRecord( - S.Out, S.ScratchRecord, abbrCode, - static_cast(theAttr->getBehavior())); - return; - } - case DeclAttrKind::ABI: { auto *theAttr = cast(DA); auto abbrCode = S.DeclTypeAbbrCodes[ABIDeclAttrLayout::Code]; @@ -3471,9 +3462,9 @@ class Serializer::DeclSerializer : public DeclVisitor { case DeclAttrKind::Nonisolated: { auto *theAttr = cast(DA); auto abbrCode = S.DeclTypeAbbrCodes[NonisolatedDeclAttrLayout::Code]; - NonisolatedDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, - theAttr->isUnsafe(), - theAttr->isImplicit()); + NonisolatedDeclAttrLayout::emitRecord( + S.Out, S.ScratchRecord, abbrCode, + static_cast(theAttr->getModifier()), theAttr->isImplicit()); return; } diff --git a/test/ASTGen/attrs.swift b/test/ASTGen/attrs.swift index 307dd7770c3b1..39c8f5379eb9c 100644 --- a/test/ASTGen/attrs.swift +++ b/test/ASTGen/attrs.swift @@ -2,7 +2,6 @@ // RUN: %target-swift-frontend-dump-parse \ // RUN: -enable-experimental-feature ABIAttribute \ -// RUN: -enable-experimental-feature ExecutionAttribute \ // RUN: -enable-experimental-feature Extern \ // RUN: -enable-experimental-feature LifetimeDependence \ // RUN: -enable-experimental-feature RawLayout \ @@ -14,7 +13,6 @@ // RUN: %target-swift-frontend-dump-parse \ // RUN: -enable-experimental-feature ABIAttribute \ -// RUN: -enable-experimental-feature ExecutionAttribute \ // RUN: -enable-experimental-feature Extern \ // RUN: -enable-experimental-feature LifetimeDependence \ // RUN: -enable-experimental-feature RawLayout \ @@ -29,7 +27,6 @@ // RUN: -module-abi-name ASTGen \ // RUN: -enable-experimental-feature ParserASTGen \ // RUN: -enable-experimental-feature ABIAttribute \ -// RUN: -enable-experimental-feature ExecutionAttribute \ // RUN: -enable-experimental-feature Extern \ // RUN: -enable-experimental-feature LifetimeDependence \ // RUN: -enable-experimental-feature RawLayout \ @@ -42,7 +39,6 @@ // REQUIRES: swift_swift_parser // REQUIRES: swift_feature_ParserASTGen // REQUIRES: swift_feature_ABIAttribute -// REQUIRES: swift_feature_ExecutionAttribute // REQUIRES: swift_feature_Extern // REQUIRES: swift_feature_LifetimeDependence // REQUIRES: swift_feature_RawLayout @@ -195,19 +191,19 @@ struct StorageRestrctionTest { @_unavailableFromAsync struct UnavailFromAsyncStruct { } // expected-error {{'@_unavailableFromAsync' attribute cannot be applied to this declaration}} @_unavailableFromAsync(message: "foo bar") func UnavailFromAsyncFn() {} -@execution(concurrent) func testGlobal() async { // Ok +@concurrent func testGlobal() async { // Ok } do { - @execution(caller) func testLocal() async {} // Ok + nonisolated(nonsending) func testLocal() async {} // Ok struct Test { - @execution(concurrent) func testMember() async {} // Ok + @concurrent func testMember() async {} // Ok } } typealias testConvention = @convention(c) (Int) -> Int -typealias testExecution = @execution(concurrent) () async -> Void +typealias testExecution = @concurrent () async -> Void typealias testIsolated = @isolated(any) () -> Void protocol OpProto {} diff --git a/test/Concurrency/Runtime/nonisolated_inherits_isolation.swift b/test/Concurrency/Runtime/nonisolated_inherits_isolation.swift index e82c09d1cf49d..e2aff4a4634bc 100644 --- a/test/Concurrency/Runtime/nonisolated_inherits_isolation.swift +++ b/test/Concurrency/Runtime/nonisolated_inherits_isolation.swift @@ -1,4 +1,4 @@ -// RUN: %target-run-simple-swift( -swift-version 6 -g %import-libdispatch -import-objc-header %S/Inputs/RunOnMainActor.h -enable-experimental-feature ExecutionAttribute -enable-experimental-feature AsyncCallerExecution ) +// RUN: %target-run-simple-swift( -swift-version 6 -g %import-libdispatch -import-objc-header %S/Inputs/RunOnMainActor.h -enable-experimental-feature AsyncCallerExecution ) // REQUIRES: executable_test // REQUIRES: concurrency @@ -6,7 +6,6 @@ // REQUIRES: libdispatch // REQUIRES: asserts -// REQUIRES: swift_feature_ExecutionAttribute // REQUIRES: swift_feature_AsyncCallerExecution // UNSUPPORTED: freestanding @@ -34,13 +33,13 @@ struct CustomActor { } } -@execution(caller) +nonisolated(nonsending) func executionCallerIsolation() async { checkIfOnMainQueue() } // Expected to always crash -@execution(concurrent) +@concurrent func executionConcurrentIsolation() async { checkIfOnMainQueue() } diff --git a/test/Concurrency/attr_execution/adoption_mode.swift b/test/Concurrency/attr_execution/adoption_mode.swift index f8cdcad4c3978..6ce3737b4e924 100644 --- a/test/Concurrency/attr_execution/adoption_mode.swift +++ b/test/Concurrency/attr_execution/adoption_mode.swift @@ -1,69 +1,68 @@ -// RUN: %target-typecheck-verify-swift -target %target-swift-5.1-abi-triple -swift-version 5 -enable-experimental-feature ExecutionAttribute -enable-experimental-feature AsyncCallerExecution:adoption -// RUN: %target-typecheck-verify-swift -target %target-swift-5.1-abi-triple -swift-version 6 -enable-experimental-feature ExecutionAttribute -enable-experimental-feature AsyncCallerExecution:adoption +// RUN: %target-typecheck-verify-swift -target %target-swift-5.1-abi-triple -swift-version 5 -enable-experimental-feature AsyncCallerExecution:adoption +// RUN: %target-typecheck-verify-swift -target %target-swift-5.1-abi-triple -swift-version 6 -enable-experimental-feature AsyncCallerExecution:adoption -// REQUIRES: swift_feature_ExecutionAttribute // REQUIRES: swift_feature_AsyncCallerExecution struct G { init(_: T) {} } -@execution(concurrent) func globalAsyncF() async {} +@concurrent func globalAsyncF() async {} // MARK: Functions do { func syncF() {} - @execution(concurrent) func executionConcurrentAsyncF() async {} - @execution(caller) func executionCallerAsyncF() async {} + @concurrent func executionConcurrentAsyncF() async {} + nonisolated(nonsending) func executionCallerAsyncF() async {} @MainActor func mainActorAsyncF() async {} func isolatedParamAsyncF( isolation: isolated (any Actor)? = #isolation ) async {} - // expected-warning@+1:20 {{feature 'AsyncCallerExecution' will cause nonisolated async local function 'asyncF' to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{3-3=@execution(concurrent) }}{{none}} + // expected-warning@+1:20 {{feature 'AsyncCallerExecution' will cause nonisolated async local function 'asyncF' to run on the caller's actor; use @concurrent to preserve behavior}}{{3-3=@concurrent }}{{none}} nonisolated func asyncF() async {} struct S { init(sync: ()) {} - @execution(concurrent) init(executionAsync: ()) async {} + @concurrent init(executionAsync: ()) async {} @MainActor init(mainActorAsync: ()) async {} - // expected-warning@+1:5 {{feature 'AsyncCallerExecution' will cause nonisolated async initializer 'init' to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{5-5=@execution(concurrent) }}{{none}} + // expected-warning@+1:5 {{feature 'AsyncCallerExecution' will cause nonisolated async initializer 'init' to run on the caller's actor; use @concurrent to preserve behavior}}{{5-5=@concurrent }}{{none}} init(async: ()) async {} func syncF() {} - @execution(concurrent) func executionAsyncF() async {} + @concurrent func executionAsyncF() async {} @MainActor func mainActorAsyncF() async {} - // expected-warning@+2:17 {{feature 'AsyncCallerExecution' will cause nonisolated async instance method 'asyncF' to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{-1:5-5=@execution(concurrent) }}{{none}} + // expected-warning@+2:17 {{feature 'AsyncCallerExecution' will cause nonisolated async instance method 'asyncF' to run on the caller's actor; use @concurrent to preserve behavior}}{{-1:5-5=@concurrent }}{{none}} nonisolated public func asyncF() async {} } protocol P { init(sync: ()) - @execution(concurrent) init(executionAsync: ()) async + @concurrent init(executionAsync: ()) async @MainActor init(mainActorAsync: ()) async - // expected-warning@+1:5 {{feature 'AsyncCallerExecution' will cause nonisolated async initializer 'init' to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{5-5=@execution(concurrent) }}{{none}} + // expected-warning@+1:5 {{feature 'AsyncCallerExecution' will cause nonisolated async initializer 'init' to run on the caller's actor; use @concurrent to preserve behavior}}{{5-5=@concurrent }}{{none}} init(async: ()) async func syncF() - @execution(concurrent) func executionAsyncF() async + @concurrent func executionAsyncF() async @MainActor func mainActorAsyncF() async - // expected-warning@+1:10 {{feature 'AsyncCallerExecution' will cause nonisolated async instance method 'asyncF' to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{5-5=@execution(concurrent) }}{{none}} + // expected-warning@+1:10 {{feature 'AsyncCallerExecution' will cause nonisolated async instance method 'asyncF' to run on the caller's actor; use @concurrent to preserve behavior}}{{5-5=@concurrent }}{{none}} func asyncF() async } } protocol Functions {} extension Functions { init(sync: ()) {} - @execution(concurrent) init(executionAsync: ()) async {} + @concurrent init(executionAsync: ()) async {} @MainActor init(mainActorAsync: ()) async {} - // expected-warning@+1:3 {{feature 'AsyncCallerExecution' will cause nonisolated async initializer 'init' to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{3-3=@execution(concurrent) }}{{none}} + // expected-warning@+1:3 {{feature 'AsyncCallerExecution' will cause nonisolated async initializer 'init' to run on the caller's actor; use @concurrent to preserve behavior}}{{3-3=@concurrent }}{{none}} init(async: ()) async {} func syncF() {} - @execution(concurrent) func executionAsyncF() async {} + @concurrent func executionAsyncF() async {} @MainActor func mainActorAsyncF() async {} - // expected-warning@+1:8 {{feature 'AsyncCallerExecution' will cause nonisolated async instance method 'asyncF' to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{3-3=@execution(concurrent) }}{{none}} + // expected-warning@+1:8 {{feature 'AsyncCallerExecution' will cause nonisolated async instance method 'asyncF' to run on the caller's actor; use @concurrent to preserve behavior}}{{3-3=@concurrent }}{{none}} func asyncF() async {} } @@ -76,17 +75,17 @@ do { var syncS: Int { get {} set {} } subscript(syncS _: Int) -> Int { get {} } - @execution(concurrent) var executionAsyncS: Int { get async {} } - @execution(concurrent) subscript(executionAsyncS _: Int) -> Int { get async {} } + @concurrent var executionAsyncS: Int { get async {} } + @concurrent subscript(executionAsyncS _: Int) -> Int { get async {} } @MainActor var mainActorAsyncS: Int { get async {} } @MainActor subscript(mainActorAsyncS _: Int) -> Int { get async {} } - // expected-warning@+2:7 {{feature 'AsyncCallerExecution' will cause nonisolated async getter for property 'asyncS' to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{-1:5-5=@execution(concurrent) }}{{none}} + // expected-warning@+2:7 {{feature 'AsyncCallerExecution' will cause nonisolated async getter for property 'asyncS' to run on the caller's actor; use @concurrent to preserve behavior}}{{-1:5-5=@concurrent }}{{none}} var asyncS: Int { get async {} } - // expected-warning@+2:7 {{feature 'AsyncCallerExecution' will cause nonisolated async getter for subscript 'subscript' to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{-1:5-5=@execution(concurrent) }}{{none}} + // expected-warning@+2:7 {{feature 'AsyncCallerExecution' will cause nonisolated async getter for subscript 'subscript' to run on the caller's actor; use @concurrent to preserve behavior}}{{-1:5-5=@concurrent }}{{none}} subscript(asyncS _: Int) -> Int { get async throws {} } @@ -96,15 +95,15 @@ do { var syncS: Int { get } subscript(syncS _: Int) -> Int { get } - @execution(concurrent) var executionAsyncS: Int { get async } - @execution(concurrent) subscript(executionAsyncS _: Int) -> Int { get async } + @concurrent var executionAsyncS: Int { get async } + @concurrent subscript(executionAsyncS _: Int) -> Int { get async } @MainActor var mainActorAsyncS: Int { get async } @MainActor subscript(mainActorAsyncS _: Int) -> Int { get async } - // expected-warning@+1:23 {{feature 'AsyncCallerExecution' will cause nonisolated async getter for property 'asyncS' to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{5-5=@execution(concurrent) }}{{none}} + // expected-warning@+1:23 {{feature 'AsyncCallerExecution' will cause nonisolated async getter for property 'asyncS' to run on the caller's actor; use @concurrent to preserve behavior}}{{5-5=@concurrent }}{{none}} var asyncS: Int { get async } - // expected-warning@+1:39 {{feature 'AsyncCallerExecution' will cause nonisolated async getter for subscript 'subscript' to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{5-5=@execution(concurrent) }}{{none}} + // expected-warning@+1:39 {{feature 'AsyncCallerExecution' will cause nonisolated async getter for subscript 'subscript' to run on the caller's actor; use @concurrent to preserve behavior}}{{5-5=@concurrent }}{{none}} subscript(asyncS _: Int) -> Int { get async } } } @@ -113,17 +112,17 @@ extension Storage { var syncS: Int { get {} set {} } subscript(syncS _: Int) -> Int { get {} } - @execution(concurrent) var executionAsyncS: Int { get async {} } - @execution(concurrent) subscript(executionAsyncS _: Int) -> Int { get async {} } + @concurrent var executionAsyncS: Int { get async {} } + @concurrent subscript(executionAsyncS _: Int) -> Int { get async {} } @MainActor var mainActorAsyncS: Int { get async {} } @MainActor subscript(mainActorAsyncS _: Int) -> Int { get async {} } - // expected-warning@+2:5 {{feature 'AsyncCallerExecution' will cause nonisolated async getter for property 'asyncS' to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{-1:3-3=@execution(concurrent) }}{{none}} + // expected-warning@+2:5 {{feature 'AsyncCallerExecution' will cause nonisolated async getter for property 'asyncS' to run on the caller's actor; use @concurrent to preserve behavior}}{{-1:3-3=@concurrent }}{{none}} var asyncS: Int { get async {} } - // expected-warning@+2:5 {{feature 'AsyncCallerExecution' will cause nonisolated async getter for subscript 'subscript' to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{-1:3-3=@execution(concurrent) }}{{none}} + // expected-warning@+2:5 {{feature 'AsyncCallerExecution' will cause nonisolated async getter for subscript 'subscript' to run on the caller's actor; use @concurrent to preserve behavior}}{{-1:3-3=@concurrent }}{{none}} subscript(asyncS _: Int) -> Int { get async throws {} } @@ -135,11 +134,11 @@ do { enum E { case esac( sync: () -> Void, - executionAsync: @execution(concurrent) () async -> Void, + executionAsync: @concurrent () async -> Void, mainActorAsync: @MainActor () async -> Void, - // expected-warning@+1:14 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{14-14=@execution(concurrent) }}{{none}} + // expected-warning@+1:14 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @concurrent to preserve behavior}}{{14-14=@concurrent }}{{none}} async: () async -> Void, - // expected-warning@+1:26 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{26-26=@execution(concurrent) }}{{none}} + // expected-warning@+1:26 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @concurrent to preserve behavior}}{{26-26=@concurrent }}{{none}} structuralAsync: G<() async -> Void> ) } @@ -147,11 +146,11 @@ do { struct S { subscript( sync: () -> Void, - executionAsync: @execution(concurrent) () async -> Void, + executionAsync: @concurrent () async -> Void, mainActorAsync: @MainActor () async -> Void, - // expected-warning@+1:14 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{14-14=@execution(concurrent) }}{{none}} + // expected-warning@+1:14 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @concurrent to preserve behavior}}{{14-14=@concurrent }}{{none}} async: () async -> Void, - // expected-warning@+1:26 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{26-26=@execution(concurrent) }}{{none}} + // expected-warning@+1:26 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @concurrent to preserve behavior}}{{26-26=@concurrent }}{{none}} structuralAsync: G<() async -> Void> ) -> Int { 0 @@ -160,21 +159,21 @@ do { func foo( sync: () -> Void, - executionAsync: @execution(concurrent) () async -> Void, + executionAsync: @concurrent () async -> Void, mainActorAsync: @MainActor () async -> Void, - // expected-warning@+1:12 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{12-12=@execution(concurrent) }}{{none}} + // expected-warning@+1:12 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @concurrent to preserve behavior}}{{12-12=@concurrent }}{{none}} async: () async -> Void, - // expected-warning@+1:24 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{24-24=@execution(concurrent) }}{{none}} + // expected-warning@+1:24 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @concurrent to preserve behavior}}{{24-24=@concurrent }}{{none}} structuralAsync: G<() async -> Void> ) {} let _ = { ( sync: () -> Void, - executionAsync: @execution(concurrent) () async -> Void, + executionAsync: @concurrent () async -> Void, mainActorAsync: @MainActor () async -> Void, - // expected-warning@+1:12 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{12-12=@execution(concurrent) }}{{none}} + // expected-warning@+1:12 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @concurrent to preserve behavior}}{{12-12=@concurrent }}{{none}} async: () async -> Void, - // expected-warning@+1:24 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{24-24=@execution(concurrent) }}{{none}} + // expected-warning@+1:24 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @concurrent to preserve behavior}}{{24-24=@concurrent }}{{none}} structuralAsync: G<() async -> Void> ) in } @@ -184,11 +183,11 @@ do { do { struct G { struct Sync where T == () -> Void {} - struct ExecutionAsync where T == @execution(concurrent) () async -> Void {} + struct ExecutionAsync where T == @concurrent () async -> Void {} struct MainActorAsync where T == @MainActor () async -> Void {} - // expected-warning@+1:29 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{29-29=@execution(concurrent) }}{{none}} + // expected-warning@+1:29 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @concurrent to preserve behavior}}{{29-29=@concurrent }}{{none}} struct Async where T == () async -> Void {} - // expected-warning@+1:41 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{41-41=@execution(concurrent) }}{{none}} + // expected-warning@+1:41 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @concurrent to preserve behavior}}{{41-41=@concurrent }}{{none}} struct StructuralAsync where T == G<() async -> Void> {} } } @@ -196,11 +195,11 @@ do { // MARK: Variables do { let _: () -> Void - let _: @execution(concurrent) () async -> Void + let _: @concurrent () async -> Void let _: @MainActor () async -> Void - // expected-warning@+1:10 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{10-10=@execution(concurrent) }}{{none}} + // expected-warning@+1:10 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @concurrent to preserve behavior}}{{10-10=@concurrent }}{{none}} let _: () async -> Void - // expected-warning@+1:12 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{12-12=@execution(concurrent) }}{{none}} + // expected-warning@+1:12 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @concurrent to preserve behavior}}{{12-12=@concurrent }}{{none}} let _: G<() async -> Void> } @@ -209,11 +208,11 @@ do { let anything: Any let _ = anything as? () -> Void - let _ = anything as? @execution(concurrent) () async -> Void + let _ = anything as? @concurrent () async -> Void let _ = anything as? @MainActor () async -> Void - // expected-warning@+1:24 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{24-24=@execution(concurrent) }}{{none}} + // expected-warning@+1:24 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @concurrent to preserve behavior}}{{24-24=@concurrent }}{{none}} let _ = anything as? () async -> Void - // expected-warning@+1:26 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{26-26=@execution(concurrent) }}{{none}} + // expected-warning@+1:26 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @concurrent to preserve behavior}}{{26-26=@concurrent }}{{none}} let _ = anything as? G<() async -> Void> } @@ -223,40 +222,40 @@ do { func nonisolatedF() { let _ = { () -> Void in } - let _ = { @execution(concurrent) () async -> Void in } + let _ = { @concurrent () async -> Void in } let _ = { @MainActor () async -> Void in } - // expected-warning@+1:13 {{feature 'AsyncCallerExecution' will cause nonisolated async closure to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{15-15=@execution(concurrent) }}{{none}} + // expected-warning@+1:13 {{feature 'AsyncCallerExecution' will cause nonisolated async closure to run on the caller's actor; use @concurrent to preserve behavior}}{{15-15=@concurrent }}{{none}} let _ = { () async -> Void in } func takesInts(_: Int...) {} - // expected-warning@+1:13 {{feature 'AsyncCallerExecution' will cause nonisolated async closure to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{14-14= @execution(concurrent) in }}{{none}} + // expected-warning@+1:13 {{feature 'AsyncCallerExecution' will cause nonisolated async closure to run on the caller's actor; use @concurrent to preserve behavior}}{{14-14= @concurrent in }}{{none}} let _ = {await globalAsyncF()} - // expected-warning@+1:13 {{feature 'AsyncCallerExecution' will cause nonisolated async closure to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{14-14= @execution(concurrent) in }}{{none}} + // expected-warning@+1:13 {{feature 'AsyncCallerExecution' will cause nonisolated async closure to run on the caller's actor; use @concurrent to preserve behavior}}{{14-14= @concurrent in }}{{none}} let _ = { await globalAsyncF() } - // expected-warning@+1:13 {{feature 'AsyncCallerExecution' will cause nonisolated async closure to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{14-14= @execution(concurrent) in }}{{none}} + // expected-warning@+1:13 {{feature 'AsyncCallerExecution' will cause nonisolated async closure to run on the caller's actor; use @concurrent to preserve behavior}}{{14-14= @concurrent in }}{{none}} let _ = { await globalAsyncF() takesInts($0, $1, $2) } - // expected-warning@+1:13 {{feature 'AsyncCallerExecution' will cause nonisolated async closure to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{25-25=@execution(concurrent) }}{{none}} + // expected-warning@+1:13 {{feature 'AsyncCallerExecution' will cause nonisolated async closure to run on the caller's actor; use @concurrent to preserve behavior}}{{25-25=@concurrent }}{{none}} let _ = { @Sendable in await globalAsyncF() } - // expected-warning@+2:18 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{18-18=@execution(concurrent) }}{{none}} - // expected-warning@+1:45 {{feature 'AsyncCallerExecution' will cause nonisolated async closure to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{47-47=@execution(concurrent) }}{{none}} + // expected-warning@+2:18 {{feature 'AsyncCallerExecution' will cause nonisolated async function type to be treated as specified to run on the caller's actor; use @concurrent to preserve behavior}}{{18-18=@concurrent }}{{none}} + // expected-warning@+1:45 {{feature 'AsyncCallerExecution' will cause nonisolated async closure to run on the caller's actor; use @concurrent to preserve behavior}}{{47-47=@concurrent }}{{none}} var closure: (Int, Int) async -> Void = { a, b in await globalAsyncF() } - // expected-warning@+1:15 {{feature 'AsyncCallerExecution' will cause nonisolated async closure to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{+1:7-7=@execution(concurrent) }}{{none}} + // expected-warning@+1:15 {{feature 'AsyncCallerExecution' will cause nonisolated async closure to run on the caller's actor; use @concurrent to preserve behavior}}{{+1:7-7=@concurrent }}{{none}} closure = { a, b async in await globalAsyncF() } - // expected-warning@+1:15 {{feature 'AsyncCallerExecution' will cause nonisolated async closure to run on the caller's actor; use @execution(concurrent) to preserve behavior}}{{17-17=@execution(concurrent) }}{{none}} + // expected-warning@+1:15 {{feature 'AsyncCallerExecution' will cause nonisolated async closure to run on the caller's actor; use @concurrent to preserve behavior}}{{17-17=@concurrent }}{{none}} closure = { (a, b) in await globalAsyncF() } diff --git a/test/Concurrency/attr_execution/attr_execution.swift b/test/Concurrency/attr_execution/attr_execution.swift index 23700de37ed86..e7c600789fb67 100644 --- a/test/Concurrency/attr_execution/attr_execution.swift +++ b/test/Concurrency/attr_execution/attr_execution.swift @@ -1,17 +1,16 @@ -// RUN: %target-swift-emit-silgen -enable-experimental-feature ExecutionAttribute -enable-experimental-feature AsyncCallerExecution %s | %FileCheck %s +// RUN: %target-swift-emit-silgen -enable-experimental-feature AsyncCallerExecution %s | %FileCheck %s -// REQUIRES: swift_feature_ExecutionAttribute // REQUIRES: swift_feature_AsyncCallerExecution // CHECK-LABEL: // concurrentTest() // CHECK: // Isolation: nonisolated // CHECK: sil hidden [ossa] @$s14attr_execution14concurrentTestyyYaF : $@convention(thin) @async () -> () { -@execution(concurrent) +@concurrent func concurrentTest() async {} // CHECK-LABEL: // callerTest() // CHECK: // Isolation: caller_isolation_inheriting // CHECK: sil hidden [ossa] @$s14attr_execution10callerTestyyYaF : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () { -@execution(caller) +nonisolated(nonsending) func callerTest() async {} diff --git a/test/Concurrency/attr_execution/conversions.swift b/test/Concurrency/attr_execution/conversions.swift index 3113724468061..75a996f093af9 100644 --- a/test/Concurrency/attr_execution/conversions.swift +++ b/test/Concurrency/attr_execution/conversions.swift @@ -1,69 +1,64 @@ -// RUN: %target-typecheck-verify-swift -target %target-swift-5.1-abi-triple -enable-experimental-feature ExecutionAttribute +// RUN: %target-typecheck-verify-swift -target %target-swift-5.1-abi-triple // REQUIRES: concurrency -// REQUIRES: swift_feature_ExecutionAttribute @globalActor actor MyActor { static let shared = MyActor() } -@execution(concurrent) +@concurrent func concurrentTest() async { } -@execution(caller) +nonisolated(nonsending) func callerTest() async { } @MainActor func actorIsolated() async {} -let _: @execution(caller) () async -> Void = concurrentTest // Ok -let _: @execution(concurrent) () async -> Void = callerTest // Ok +let _: nonisolated(nonsending) () async -> Void = concurrentTest // Ok +let _: @concurrent () async -> Void = callerTest // Ok let _: @MainActor () async -> Void = concurrentTest // Ok let _: @MainActor () async -> Void = callerTest // Ok let _: @isolated(any) () async -> Void = concurrentTest // Ok let _: @isolated(any) () async -> Void = callerTest -// expected-error@-1 {{cannot convert value of type '@execution(caller) () async -> ()' to specified type '@isolated(any) () async -> Void'}} +// expected-error@-1 {{cannot convert value of type 'nonisolated(nonsending) () async -> ()' to specified type '@isolated(any) () async -> Void'}} -let _: @execution(caller) () async -> Void = actorIsolated // Ok -let _: @execution(concurrent) () async -> Void = actorIsolated // Ok +let _: nonisolated(nonsending) () async -> Void = actorIsolated // Ok +let _: @concurrent () async -> Void = actorIsolated // Ok func testIsolationErasure(fn: @escaping @isolated(any) () async -> Void) { - let _: @execution(concurrent) () async -> Void = fn // Ok - let _: @execution(caller) () async -> Void = fn // Ok + let _: @concurrent () async -> Void = fn // Ok + let _: nonisolated(nonsending) () async -> Void = fn // Ok } -func testUpcast(arr: [@execution(caller) () async -> Void]) { +func testUpcast(arr: [nonisolated(nonsending) () async -> Void]) { let _: [() async -> Void] = arr // Ok - collection upcast let _: [String: () async -> Void] = ["": arr] - // expected-error@-1 {{cannot convert value of type '[@execution(caller) () async -> Void]' to expected dictionary value type '() async -> Void'}} + // expected-error@-1 {{cannot convert value of type '[nonisolated(nonsending) () async -> Void]' to expected dictionary value type '() async -> Void'}} } // Isolated parameter -func testParameterIsolation(fn: @escaping (isolated (any Actor)?) async -> Void, caller: @escaping @execution(caller) (String) async -> Void) { - let _: @execution(caller) () async -> Void = fn - // expected-error@-1 {{cannot convert value of type '(isolated (any Actor)?) async -> Void' to specified type '@execution(caller) () async -> Void'}} - let _: @execution(concurrent) () async -> Void = fn +func testParameterIsolation(fn: @escaping (isolated (any Actor)?) async -> Void, caller: nonisolated(nonsending) @escaping (String) async -> Void) { + let _: nonisolated(nonsending) () async -> Void = fn + // expected-error@-1 {{cannot convert value of type '(isolated (any Actor)?) async -> Void' to specified type 'nonisolated(nonsending) () async -> Void'}} + let _: @concurrent () async -> Void = fn // expected-error@-1 {{cannot convert value of type '(isolated (any Actor)?) async -> Void' to specified type '() async -> Void'}} let _: (isolated (any Actor)?) async -> Void = callerTest // Ok let _: (isolated (any Actor)?) -> Void = callerTest - // expected-error@-1 {{invalid conversion from 'async' function of type '@execution(caller) () async -> ()' to synchronous function type '(isolated (any Actor)?) -> Void'}} + // expected-error@-1 {{invalid conversion from 'async' function of type 'nonisolated(nonsending) () async -> ()' to synchronous function type '(isolated (any Actor)?) -> Void'}} let _: (isolated (any Actor)?) async -> Void = concurrentTest // expected-error@-1 {{cannot convert value of type '() async -> ()' to specified type '(isolated (any Actor)?) async -> Void'}} let _: (isolated (any Actor)?, Int) async -> Void = callerTest - // expected-error@-1 {{cannot convert value of type '@execution(caller) () async -> ()' to specified type '(isolated (any Actor)?, Int) async -> Void'}} + // expected-error@-1 {{cannot convert value of type 'nonisolated(nonsending) () async -> ()' to specified type '(isolated (any Actor)?, Int) async -> Void'}} let _: (String, isolated any Actor) async -> Void = caller // Ok let _: (isolated (any Actor)?, String) async -> Void = caller // Ok - - let _: (Int, isolated any Actor) async -> Void = { @execution(caller) x in } // Ok - let _: (Int, isolated any Actor) async -> Void = { @execution(caller) (x: Int) in } // Ok - let _: (isolated any Actor, Int, String) async -> Void = { @execution(caller) (x: Int, _: String) in } // Ok } // Non-conversion situations @@ -73,19 +68,19 @@ do { func test(_: S, _: T.Type) {} test(S<() async -> Void>(), type(of: callerTest)) - // expected-error@-1 {{cannot convert value of type '(@execution(caller) () async -> ()).Type' to expected argument type '(() async -> Void).Type'}} + // expected-error@-1 {{cannot convert value of type '(nonisolated(nonsending) () async -> ()).Type' to expected argument type '(() async -> Void).Type'}} - test(S<@execution(caller) () async -> Void>(), type(of: concurrentTest)) - // expected-error@-1 {{cannot convert value of type '(() async -> ()).Type' to expected argument type '(@execution(caller) () async -> Void).Type'}} + test(S Void>(), type(of: concurrentTest)) + // expected-error@-1 {{cannot convert value of type '(() async -> ()).Type' to expected argument type '(nonisolated(nonsending) () async -> Void).Type'}} test(S<@MainActor () async -> Void>(), type(of: callerTest)) - // expected-error@-1 {{cannot convert value of type '(@execution(caller) () async -> ()).Type' to expected argument type '(@MainActor () async -> Void).Type'}} + // expected-error@-1 {{cannot convert value of type '(nonisolated(nonsending) () async -> ()).Type' to expected argument type '(@MainActor () async -> Void).Type'}} test(S<@MainActor () async -> Void>(), type(of: concurrentTest)) // expected-error@-1 {{cannot convert value of type '(() async -> ()).Type' to expected argument type '(@MainActor () async -> Void).Type'}} test(S<(isolated (any Actor)?) async -> Void>(), type(of: callerTest)) - // expected-error@-1 {{cannot convert value of type '(@execution(caller) () async -> ()).Type' to expected argument type '((isolated (any Actor)?) async -> Void).Type'}} + // expected-error@-1 {{cannot convert value of type '(nonisolated(nonsending) () async -> ()).Type' to expected argument type '((isolated (any Actor)?) async -> Void).Type'}} test(S<(isolated (any Actor)?) async -> Void>(), type(of: concurrentTest)) // expected-error@-1 {{cannot convert value of type '(() async -> ()).Type' to expected argument type '((isolated (any Actor)?) async -> Void).Type'}} @@ -93,22 +88,16 @@ do { test(S<@isolated(any) () async -> Void>(), type(of: concurrentTest)) // expected-error@-1 {{cannot convert value of type '(() async -> ()).Type' to expected argument type '(@isolated(any) () async -> Void).Type'}} test(S<@isolated(any) () async -> Void>(), type(of: callerTest)) - // expected-error@-1 {{cannot convert value of type '(@execution(caller) () async -> ()).Type' to expected argument type '(@isolated(any) () async -> Void).Type'}} + // expected-error@-1 {{cannot convert value of type '(nonisolated(nonsending) () async -> ()).Type' to expected argument type '(@isolated(any) () async -> Void).Type'}} } do { - let _: () -> Void = { @execution(concurrent) in + let _: () -> Void = { @concurrent in // expected-error@-1 {{invalid conversion from 'async' function of type '() async -> Void' to synchronous function type '() -> Void'}} } - - func test(_: () -> Void) {} - - test { @execution(caller) in - // expected-error@-1 {{cannot pass function of type '@execution(caller) () async -> ()' to parameter expecting synchronous function type}} - } } -// Converting to `@execution(caller)` function +// Converting to `nonisolated(nonsending)` function class NonSendable {} func testNonSendableDiagnostics( @@ -117,40 +106,40 @@ func testNonSendableDiagnostics( erased1: @escaping @Sendable @isolated(any) (NonSendable) async -> Void, erased2: @escaping @Sendable @isolated(any) () async -> NonSendable, nonIsolated1: @escaping @Sendable (NonSendable) -> Void, - nonIsolated2: @escaping @Sendable @execution(concurrent) (NonSendable) async -> Void, + nonIsolated2: @escaping @Sendable @concurrent (NonSendable) async -> Void, nonIsolated3: @escaping @Sendable () -> NonSendable, - nonIsolated4: @escaping @Sendable @execution(concurrent) () async -> NonSendable, - caller1: @escaping @Sendable @execution(caller) (NonSendable) async -> Void, - caller2: @escaping @Sendable @execution(caller) () async -> NonSendable + nonIsolated4: @escaping @Sendable @concurrent () async -> NonSendable, + caller1: nonisolated(nonsending) @escaping @Sendable (NonSendable) async -> Void, + caller2: nonisolated(nonsending) @escaping @Sendable () async -> NonSendable ) { - let _: @execution(caller) (NonSendable) async -> Void = globalActor1 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} - // expected-error@-1 {{cannot convert '@MainActor @Sendable (NonSendable) async -> Void' to '@execution(caller) (NonSendable) async -> Void' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} - let _: @execution(caller) () async -> NonSendable = globalActor2 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} - // expected-error@-1 {{cannot convert '@MainActor @Sendable () async -> NonSendable' to '@execution(caller) () async -> NonSendable' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} + let _: nonisolated(nonsending) (NonSendable) async -> Void = globalActor1 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} + // expected-error@-1 {{cannot convert '@MainActor @Sendable (NonSendable) async -> Void' to 'nonisolated(nonsending) (NonSendable) async -> Void' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} + let _: nonisolated(nonsending) () async -> NonSendable = globalActor2 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} + // expected-error@-1 {{cannot convert '@MainActor @Sendable () async -> NonSendable' to 'nonisolated(nonsending) () async -> NonSendable' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} - let _: @execution(caller) (NonSendable) async -> Void = erased1 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} - // expected-error@-1 {{cannot convert '@isolated(any) @Sendable (NonSendable) async -> Void' to '@execution(caller) (NonSendable) async -> Void' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} - let _: @execution(caller) () async -> NonSendable = erased2 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} - // expected-error@-1 {{cannot convert '@isolated(any) @Sendable () async -> NonSendable' to '@execution(caller) () async -> NonSendable' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} + let _: nonisolated(nonsending) (NonSendable) async -> Void = erased1 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} + // expected-error@-1 {{cannot convert '@isolated(any) @Sendable (NonSendable) async -> Void' to 'nonisolated(nonsending) (NonSendable) async -> Void' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} + let _: nonisolated(nonsending) () async -> NonSendable = erased2 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} + // expected-error@-1 {{cannot convert '@isolated(any) @Sendable () async -> NonSendable' to 'nonisolated(nonsending) () async -> NonSendable' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} - let _: @execution(caller) (NonSendable) async -> Void = nonIsolated1 // Ok - let _: @execution(caller) (NonSendable) async -> Void = nonIsolated2 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} - // expected-error@-1 {{cannot convert '@Sendable (NonSendable) async -> Void' to '@execution(caller) (NonSendable) async -> Void' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} + let _: nonisolated(nonsending) (NonSendable) async -> Void = nonIsolated1 // Ok + let _: nonisolated(nonsending) (NonSendable) async -> Void = nonIsolated2 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} + // expected-error@-1 {{cannot convert '@Sendable (NonSendable) async -> Void' to 'nonisolated(nonsending) (NonSendable) async -> Void' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} - let _: @execution(caller) () async -> NonSendable = nonIsolated3 // Ok - let _: @execution(caller) () async -> NonSendable = nonIsolated4 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} - // expected-error@-1 {{cannot convert '@Sendable () async -> NonSendable' to '@execution(caller) () async -> NonSendable' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} + let _: nonisolated(nonsending) () async -> NonSendable = nonIsolated3 // Ok + let _: nonisolated(nonsending) () async -> NonSendable = nonIsolated4 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} + // expected-error@-1 {{cannot convert '@Sendable () async -> NonSendable' to 'nonisolated(nonsending) () async -> NonSendable' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} - let _: @execution(concurrent) (NonSendable) async -> Void = erased1 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} + let _: @concurrent (NonSendable) async -> Void = erased1 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} // expected-warning@-1 {{cannot convert '@isolated(any) @Sendable (NonSendable) async -> Void' to '(NonSendable) async -> Void' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} - let _: @execution(concurrent) () async -> NonSendable = erased2 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} + let _: @concurrent () async -> NonSendable = erased2 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} // expected-warning@-1 {{cannot convert '@isolated(any) @Sendable () async -> NonSendable' to '() async -> NonSendable' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} - let _: @execution(concurrent) (NonSendable) async -> Void = caller1 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} - // expected-warning@-1 {{cannot convert '@execution(caller) @Sendable (NonSendable) async -> Void' to '(NonSendable) async -> Void' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} - let _: @execution(concurrent) () async -> NonSendable = caller2 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} - // expected-warning@-1 {{cannot convert '@execution(caller) @Sendable () async -> NonSendable' to '() async -> NonSendable' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} + let _: @concurrent (NonSendable) async -> Void = caller1 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} + // expected-warning@-1 {{cannot convert 'nonisolated(nonsending) @Sendable (NonSendable) async -> Void' to '(NonSendable) async -> Void' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} + let _: @concurrent () async -> NonSendable = caller2 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} + // expected-warning@-1 {{cannot convert 'nonisolated(nonsending) @Sendable () async -> NonSendable' to '() async -> NonSendable' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol}} let _: @MainActor (NonSendable) async -> Void = nonIsolated1 // Ok let _: @MainActor (NonSendable) async -> Void = nonIsolated2 // expected-note {{type 'NonSendable' does not conform to 'Sendable' protocol}} diff --git a/test/Concurrency/attr_execution/conversions_silgen.swift b/test/Concurrency/attr_execution/conversions_silgen.swift index 4ed0ec15f1379..64cc5b920d16d 100644 --- a/test/Concurrency/attr_execution/conversions_silgen.swift +++ b/test/Concurrency/attr_execution/conversions_silgen.swift @@ -1,21 +1,20 @@ -// RUN: %target-swift-emit-silgen %s -module-name attr_execution_silgen -target %target-swift-5.1-abi-triple -enable-experimental-feature ExecutionAttribute -DSWIFT_FIVE | %FileCheck -check-prefix CHECK -check-prefix FIVE %s -// RUN: %target-swift-emit-silgen %s -swift-version 6 -module-name attr_execution_silgen -target %target-swift-5.1-abi-triple -enable-experimental-feature ExecutionAttribute | %FileCheck -check-prefix CHECK -check-prefix SIX %s +// RUN: %target-swift-emit-silgen %s -module-name attr_execution_silgen -target %target-swift-5.1-abi-triple -DSWIFT_FIVE | %FileCheck -check-prefix CHECK -check-prefix FIVE %s +// RUN: %target-swift-emit-silgen %s -swift-version 6 -module-name attr_execution_silgen -target %target-swift-5.1-abi-triple | %FileCheck -check-prefix CHECK -check-prefix SIX %s // We codegen slightly differently for swift 5 vs swift 6, so we need to check // both. // REQUIRES: asserts // REQUIRES: concurrency -// REQUIRES: swift_feature_ExecutionAttribute //////////////////////// // MARK: Declarations // //////////////////////// -@execution(caller) +nonisolated(nonsending) func globalCallerFunc() async -> () {} -@execution(concurrent) +@concurrent func globalConcurrentFunc() async -> () {} class NonSendableKlass { @@ -25,16 +24,16 @@ class SendableKlass : @unchecked Sendable { init() {} } -@execution(caller) +nonisolated(nonsending) func globalCallerFuncSendableKlass(_ x: SendableKlass) async -> () {} -@execution(concurrent) +@concurrent func globalConcurrentFuncSendableKlass(_ x: SendableKlass) async -> () {} -@execution(caller) +nonisolated(nonsending) func globalCallerFuncSendableKlass(_ x: SendableKlass) async -> SendableKlass { fatalError() } -@execution(concurrent) +@concurrent func globalConcurrentFuncSendableKlass(_ x: SendableKlass) async -> SendableKlass { fatalError() } @@ -48,8 +47,8 @@ func globalConcurrentFuncSendableKlass(_ x: SendableKlass) async -> SendableKlas // CHECK: [[THUNK:%.*]] = function_ref @$sScA_pSgIegHg_IegH_TR : $@convention(thin) @async (@guaranteed @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> ()) -> () // CHECK: partial_apply [callee_guaranteed] [[THUNK]]([[FUNC_COPY]]) // CHECK: } // end sil function '$s21attr_execution_silgen33testCallerToConcurrentNonIsolatedyyyyYaYCcYaF' -public func testCallerToConcurrentNonIsolated(_ x: @escaping @execution(caller) () async -> ()) async { - let y: @execution(concurrent) () async -> () = x +public func testCallerToConcurrentNonIsolated(_ x: nonisolated(nonsending) @escaping () async -> ()) async { + let y: @concurrent () async -> () = x await y() } @@ -69,8 +68,8 @@ public func testCallerToConcurrentNonIsolated(_ x: @escaping @execution(caller) // CHECK: partial_apply [callee_guaranteed] [[THUNK]]([[FUNC_COPY]]) // CHECK: } // end sil function '$s21attr_execution_silgen31testCallerToConcurrentMainActoryyyyYaYCcYaF' @MainActor -public func testCallerToConcurrentMainActor(_ x: @escaping @execution(caller) () async -> ()) async { - let y: @execution(concurrent) () async -> () = x +public func testCallerToConcurrentMainActor(_ x: nonisolated(nonsending) @escaping () async -> ()) async { + let y: @concurrent () async -> () = x await y() } @@ -80,8 +79,8 @@ public func testCallerToConcurrentMainActor(_ x: @escaping @execution(caller) () // CHECK: [[THUNK:%.*]] = function_ref @$sIegH_ScA_pSgIegHg_TR : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, @guaranteed @async @callee_guaranteed () -> ()) -> () // CHECK: partial_apply [callee_guaranteed] [[THUNK]]([[FUNC_COPY]]) // CHECK: } // end sil function '$s21attr_execution_silgen33testConcurrentToCallerNonIsolatedyyyyYacYaF' -public func testConcurrentToCallerNonIsolated(_ x: @escaping @execution(concurrent) () async -> ()) async { - let y: @execution(caller) () async -> () = x +public func testConcurrentToCallerNonIsolated(_ x: @escaping @concurrent () async -> ()) async { + let y: nonisolated(nonsending) () async -> () = x await y() } @@ -100,8 +99,8 @@ public func testConcurrentToCallerNonIsolated(_ x: @escaping @execution(concurre // CHECK: partial_apply [callee_guaranteed] [[THUNK]]([[FUNC_COPY]]) // CHECK: } // end sil function '$s21attr_execution_silgen42testConcurrentToCallerNonIsolatedMainActoryyyyYacYaF' @MainActor -public func testConcurrentToCallerNonIsolatedMainActor(_ x: @escaping @execution(concurrent) () async -> ()) async { - let y: @execution(caller) () async -> () = x +public func testConcurrentToCallerNonIsolatedMainActor(_ x: @escaping @concurrent () async -> ()) async { + let y: nonisolated(nonsending) () async -> () = x await y() } @@ -124,10 +123,10 @@ public func testConcurrentToCallerNonIsolatedMainActor(_ x: @escaping @execution // CHECK: [[BORROW_COPY_Z:%.*]] = begin_borrow [[COPY_Z]] // CHECK: apply [[BORROW_COPY_Z]]() // CHECK: } // end sil function '$s21attr_execution_silgen016testConcurrentToE0yyyyYacYaF' -public func testConcurrentToConcurrent(_ x: @escaping @execution(concurrent) () async -> ()) async { - let y: @execution(concurrent) () async -> () = x +public func testConcurrentToConcurrent(_ x: @escaping @concurrent () async -> ()) async { + let y: @concurrent () async -> () = x await y() - let z: @execution(concurrent) () async -> () = globalConcurrentFunc + let z: @concurrent () async -> () = globalConcurrentFunc await z() } @@ -142,10 +141,10 @@ public func testConcurrentToConcurrent(_ x: @escaping @execution(concurrent) () // CHECK: } // end sil function '$s21attr_execution_silgen012testCallerToE0yyyyYaYCcYaF' // // z has a round trip issue. -public func testCallerToCaller(_ x: @escaping @execution(caller) () async -> ()) async { - let y: @execution(caller) () async -> () = x +public func testCallerToCaller(_ x: nonisolated(nonsending) @escaping () async -> ()) async { + let y: nonisolated(nonsending) () async -> () = x await y() - let z: @execution(caller) () async -> () = globalCallerFunc + let z: nonisolated(nonsending) () async -> () = globalCallerFunc await z() } @@ -162,9 +161,9 @@ public func testCallerToCaller(_ x: @escaping @execution(caller) () async -> ()) // CHECK: [[Y2_B_C_B:%.*]] = begin_borrow [[Y2_B_C]] // CHECK: apply [[Y2_B_C_B]]([[ACTOR]]) // CHECK: } // end sil function '$s21attr_execution_silgen24testCallerLocalVariablesyyyyYaYCcYaF' -public func testCallerLocalVariables(_ x: @escaping @execution(caller) () async -> ()) async { - let y: @execution(caller) () async -> () = x - let y2: @execution(caller) () async -> () = y +public func testCallerLocalVariables(_ x: nonisolated(nonsending) @escaping () async -> ()) async { + let y: nonisolated(nonsending) () async -> () = x + let y2: nonisolated(nonsending) () async -> () = y await y2() } @@ -179,9 +178,9 @@ public func testCallerLocalVariables(_ x: @escaping @execution(caller) () async // CHECK: [[Y2_B_C_B:%.*]] = begin_borrow [[Y2_B_C]] // CHECK: apply [[Y2_B_C_B]]() // CHECK: } // end sil function '$s21attr_execution_silgen28testConcurrentLocalVariablesyyyyYacYaF' -public func testConcurrentLocalVariables(_ x: @escaping @execution(concurrent) () async -> ()) async { - let y: @execution(concurrent) () async -> () = x - let y2: @execution(concurrent) () async -> () = y +public func testConcurrentLocalVariables(_ x: @escaping @concurrent () async -> ()) async { + let y: @concurrent () async -> () = x + let y2: @concurrent () async -> () = y await y2() } @@ -196,9 +195,9 @@ public func testConcurrentLocalVariables(_ x: @escaping @execution(concurrent) ( // CHECK: [[THUNK_2:%.*]] = function_ref @$sIegH_ScA_pSgIegHg_TR : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, @guaranteed @async @callee_guaranteed () -> ()) -> () // CHECK: [[PA_2:%.*]] = partial_apply [callee_guaranteed] [[THUNK_2]]([[Y_B_C]]) // CHECK: } // end sil function '$s21attr_execution_silgen34testCallerConcurrentLocalVariablesyyyyYaYCcYaF' -public func testCallerConcurrentLocalVariables(_ x: @escaping @execution(caller) () async -> ()) async { - let y: @execution(concurrent) () async -> () = x - let y2: @execution(caller) () async -> () = y +public func testCallerConcurrentLocalVariables(_ x: nonisolated(nonsending) @escaping () async -> ()) async { + let y: @concurrent () async -> () = x + let y2: nonisolated(nonsending) () async -> () = y await y2() } @@ -213,9 +212,9 @@ public func testCallerConcurrentLocalVariables(_ x: @escaping @execution(caller) // CHECK: [[THUNK_2:%.*]] = function_ref @$sScA_pSgIegHg_IegH_TR : $@convention(thin) @async (@guaranteed @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> ()) -> () // CHECK: [[PA_2:%.*]] = partial_apply [callee_guaranteed] [[THUNK_2]]([[Y_B_C]]) // CHECK: } // end sil function '$s21attr_execution_silgen34testConcurrentCallerLocalVariablesyyyyYacYaF' -public func testConcurrentCallerLocalVariables(_ x: @escaping @execution(concurrent) () async -> ()) async { - let y: @execution(caller) () async -> () = x - let y2: @execution(concurrent) () async -> () = y +public func testConcurrentCallerLocalVariables(_ x: @escaping @concurrent () async -> ()) async { + let y: nonisolated(nonsending) () async -> () = x + let y2: @concurrent () async -> () = y await y2() } @@ -261,8 +260,8 @@ public func testConcurrentCallerLocalVariables(_ x: @escaping @execution(concurr // FIVE: apply [[V4_B_C_B]]() // CHECK: } // end sil function '$s21attr_execution_silgen22globalActorConversionsyyyyYac_yyYaYCctYaF' -func globalActorConversions(_ x: @escaping @execution(concurrent) () async -> (), - _ y: @escaping @execution(caller) () async -> ()) async { +func globalActorConversions(_ x: @escaping @concurrent () async -> (), + _ y: nonisolated(nonsending) @escaping () async -> ()) async { let v1: @MainActor () async -> Void = globalCallerFunc await v1() let v2: @MainActor () async -> Void = globalConcurrentFunc @@ -320,8 +319,8 @@ func globalActorConversions(_ x: @escaping @execution(concurrent) () async -> () // FIVE: apply [[V4_B_C_B]]({{%.*}}) // CHECK: } // end sil function '$s21attr_execution_silgen23globalActorConversions2yyyAA13SendableKlassCYac_yADYaYCctYaF' -func globalActorConversions2(_ x: @escaping @execution(concurrent) (SendableKlass) async -> (), - _ y: @escaping @execution(caller) (SendableKlass) async -> ()) async { +func globalActorConversions2(_ x: @escaping @concurrent (SendableKlass) async -> (), + _ y: nonisolated(nonsending) @escaping (SendableKlass) async -> ()) async { let v1: @MainActor (SendableKlass) async -> Void = globalCallerFuncSendableKlass await v1(SendableKlass()) let v2: @MainActor (SendableKlass) async -> Void = globalConcurrentFuncSendableKlass @@ -332,7 +331,7 @@ func globalActorConversions2(_ x: @escaping @execution(concurrent) (SendableKlas let v4: @MainActor (SendableKlass) async -> Void = y await v4(SendableKlass()) #endif - let v5: @execution(concurrent) (SendableKlass) async -> Void = y + let v5: @concurrent (SendableKlass) async -> Void = y await v5(SendableKlass()) } @@ -381,8 +380,8 @@ func globalActorConversions2(_ x: @escaping @execution(concurrent) (SendableKlas // CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[Y_C]]) // CHECK: [[V5:%.*]] = move_value [lexical] [var_decl] [[PA]] // CHECK: } // end sil function '$s21attr_execution_silgen23globalActorConversions3yyAA13SendableKlassCADYac_A2DYaYCctYaF' -func globalActorConversions3(_ x: @escaping @execution(concurrent) (SendableKlass) async -> SendableKlass, - _ y: @escaping @execution(caller) (SendableKlass) async -> SendableKlass) async { +func globalActorConversions3(_ x: @escaping @concurrent (SendableKlass) async -> SendableKlass, + _ y: nonisolated(nonsending) @escaping (SendableKlass) async -> SendableKlass) async { let v1: @MainActor (SendableKlass) async -> SendableKlass = globalCallerFuncSendableKlass _ = await v1(SendableKlass()) let v2: @MainActor (SendableKlass) async -> SendableKlass = globalConcurrentFuncSendableKlass @@ -393,7 +392,7 @@ func globalActorConversions3(_ x: @escaping @execution(concurrent) (SendableKlas let v4: @MainActor (SendableKlass) async -> SendableKlass = y _ = await v4(SendableKlass()) #endif - let v5: @execution(concurrent) (SendableKlass) async -> SendableKlass = y + let v5: @concurrent (SendableKlass) async -> SendableKlass = y _ = await v5(SendableKlass()) } @@ -421,8 +420,8 @@ func globalActorConversions3(_ x: @escaping @execution(concurrent) (SendableKlas func conversionsFromSyncToAsync(_ x: @escaping @Sendable (NonSendableKlass) -> Void, _ y: @escaping @MainActor @Sendable (SendableKlass) -> Void, _ z: @escaping @MainActor @Sendable (NonSendableKlass) -> Void) async { - let _: @execution(caller) (NonSendableKlass) async -> Void = x - let _: @execution(caller) (SendableKlass) async -> Void = y - let _: @execution(concurrent) (SendableKlass) async -> Void = y - let _: @execution(concurrent) (NonSendableKlass) async -> Void = z + let _: nonisolated(nonsending) (NonSendableKlass) async -> Void = x + let _: nonisolated(nonsending) (SendableKlass) async -> Void = y + let _: @concurrent (SendableKlass) async -> Void = y + let _: @concurrent (NonSendableKlass) async -> Void = z } diff --git a/test/Concurrency/attr_execution/protocols_silgen.swift b/test/Concurrency/attr_execution/protocols_silgen.swift index 78e81d36d14ef..37bdaa54649bb 100644 --- a/test/Concurrency/attr_execution/protocols_silgen.swift +++ b/test/Concurrency/attr_execution/protocols_silgen.swift @@ -1,16 +1,15 @@ -// RUN: %target-swift-emit-silgen %s -module-name attr_execution_silgen -target %target-swift-5.1-abi-triple -enable-experimental-feature ExecutionAttribute -DSWIFT_FIVE | %FileCheck -check-prefix CHECK -check-prefix FIVE %s -// RUN: %target-swift-emit-silgen %s -swift-version 6 -module-name attr_execution_silgen -target %target-swift-5.1-abi-triple -enable-experimental-feature ExecutionAttribute | %FileCheck -check-prefix CHECK -check-prefix SIX %s +// RUN: %target-swift-emit-silgen %s -module-name attr_execution_silgen -target %target-swift-5.1-abi-triple -DSWIFT_FIVE | %FileCheck -check-prefix CHECK -check-prefix FIVE %s +// RUN: %target-swift-emit-silgen %s -swift-version 6 -module-name attr_execution_silgen -target %target-swift-5.1-abi-triple | %FileCheck -check-prefix CHECK -check-prefix SIX %s // We codegen slightly differently for swift 5 vs swift 6, so we need to check // both. // REQUIRES: asserts // REQUIRES: concurrency -// REQUIRES: swift_feature_ExecutionAttribute protocol P { - @execution(caller) func callerTest() async - @execution(concurrent) func concurrentTest() async + nonisolated(nonsending) func callerTest() async + @concurrent func concurrentTest() async @MainActor func mainActorTest() async } @@ -47,7 +46,7 @@ struct AllCaller : P { // CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen9AllCallerV10callerTestyyYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, AllCaller) -> () // CHECK: apply [[FUNC]]([[ACTOR]], [[LOAD]]) // CHECK: } // end sil function '$s21attr_execution_silgen9AllCallerVAA1PA2aDP10callerTestyyYaFTW' - @execution(caller) func callerTest() async {} + nonisolated(nonsending) func callerTest() async {} // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s21attr_execution_silgen9AllCallerVAA1PA2aDP14concurrentTestyyYaFTW : $@convention(witness_method: P) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, @in_guaranteed AllCaller) -> () { // CHECK: bb0([[ACTOR:%.*]] : @guaranteed $Optional, [[SELF:%.*]] : $*AllCaller): @@ -56,7 +55,7 @@ struct AllCaller : P { // CHECK: [[NIL:%.*]] = enum $Optional, #Optional.none!enumelt // CHECK: apply [[FUNC]]([[NIL]], [[LOAD]]) // CHECK: } // end sil function '$s21attr_execution_silgen9AllCallerVAA1PA2aDP14concurrentTestyyYaFTW' - @execution(caller) func concurrentTest() async {} + nonisolated(nonsending) func concurrentTest() async {} // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s21attr_execution_silgen9AllCallerVAA1PA2aDP13mainActorTestyyYaFTW : $@convention(witness_method: P) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, @in_guaranteed AllCaller) -> () { // CHECK: bb0({{%.*}} : @guaranteed $Optional, [[SELF:%.*]] : $*AllCaller): @@ -67,7 +66,7 @@ struct AllCaller : P { // CHECK: [[OPT_MAIN_ACTOR:%.*]] = enum $Optional, #Optional.some!enumelt, [[EXIS_MAIN_ACTOR]] // CHECK: apply [[FUNC]]([[OPT_MAIN_ACTOR]], [[LOAD]]) // CHECK: } // end sil function '$s21attr_execution_silgen9AllCallerVAA1PA2aDP13mainActorTestyyYaFTW' - @execution(caller) func mainActorTest() async {} + nonisolated(nonsending) func mainActorTest() async {} } struct AllConcurrent : P { @@ -80,7 +79,7 @@ struct AllConcurrent : P { // CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen13AllConcurrentV10callerTestyyYaF : $@convention(method) @async (AllConcurrent) -> () // CHECK: apply [[FUNC]]([[LOAD]]) // CHECK: } // end sil function '$s21attr_execution_silgen13AllConcurrentVAA1PA2aDP10callerTestyyYaFTW' - @execution(concurrent) func callerTest() async {} + @concurrent func callerTest() async {} // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s21attr_execution_silgen13AllConcurrentVAA1PA2aDP14concurrentTestyyYaFTW : $@convention(witness_method: P) @async (@in_guaranteed AllConcurrent) -> () { // CHECK: bb0([[SELF:%.*]] : @@ -88,7 +87,7 @@ struct AllConcurrent : P { // CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen13AllConcurrentV14concurrentTestyyYaF : $@convention(method) @async (AllConcurrent) -> () // CHECK: apply [[FUNC]]([[LOAD]]) // CHECK: } // end sil function '$s21attr_execution_silgen13AllConcurrentVAA1PA2aDP14concurrentTestyyYaFTW' - @execution(concurrent) func concurrentTest() async {} + @concurrent func concurrentTest() async {} // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s21attr_execution_silgen13AllConcurrentVAA1PA2aDP13mainActorTestyyYaFTW : $@convention(witness_method: P) @async (@in_guaranteed AllConcurrent) -> () { // CHECK: bb0([[SELF:%.*]] : @@ -96,7 +95,7 @@ struct AllConcurrent : P { // CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen13AllConcurrentV13mainActorTestyyYaF : $@convention(method) @async (AllConcurrent) -> () // CHECK: apply [[FUNC]]([[LOAD]]) // CHECK: } // end sil function '$s21attr_execution_silgen13AllConcurrentVAA1PA2aDP13mainActorTestyyYaFTW' - @execution(concurrent) func mainActorTest() async {} + @concurrent func mainActorTest() async {} } struct AllMainActor : P { diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt index 3bb986765a1f7..540bf28a22e00 100644 --- a/test/Demangle/Inputs/manglings.txt +++ b/test/Demangle/Inputs/manglings.txt @@ -488,7 +488,7 @@ $s3red7MyActorC3runyxxyYaKACYcYTXEYaKlFZ ---> static red.MyActor.run(@red.MyA $s3red7MyActorC3runyxxyYaKYAYTXEYaKlFZ ---> static red.MyActor.run(@isolated(any) () async throws -> sending A) async throws -> A $s7ToolKit10TypedValueOACs5Error_pIgHTnTrzo_A2CsAD_pIegHiTrzr_TR ---> {T:} reabstraction thunk helper from @callee_guaranteed @async (@in_guaranteed sending ToolKit.TypedValue) -> sending (@out ToolKit.TypedValue, @error @owned Swift.Error) to @escaping @callee_guaranteed @async (@in sending ToolKit.TypedValue) -> (@out ToolKit.TypedValue, @error @out Swift.Error) $s16sending_mangling16NonSendableKlassCACIegTiTr_A2CIegTxTo_TR ---> {T:} reabstraction thunk helper from @escaping @callee_guaranteed (@in sending sending_mangling.NonSendableKlass) -> sending (@out sending_mangling.NonSendableKlass) to @escaping @callee_guaranteed (@owned sending sending_mangling.NonSendableKlass) -> sending (@owned sending_mangling.NonSendableKlass) -$s3red7MyActorC3runyxxyYaKYCXEYaKlFZ ---> static red.MyActor.run(@execution(caller) () async throws -> A) async throws -> A +$s3red7MyActorC3runyxxyYaKYCXEYaKlFZ ---> static red.MyActor.run(nonisolated(nonsending) () async throws -> A) async throws -> A $s5thing1PP1sAA1SVvxTwc ---> coro function pointer to thing.P.s.modify2 : thing.S _$s15raw_identifiers0020foospace_liaADEDGcjayyF ---> raw_identifiers.`foo space`() -> () _$s15raw_identifiers0018_3times_pgaIGJCFbhayyF ---> raw_identifiers.`3 times`() -> () diff --git a/test/IDE/complete_decl_attribute.swift b/test/IDE/complete_decl_attribute.swift index fb24931965970..c75551c8e2379 100644 --- a/test/IDE/complete_decl_attribute.swift +++ b/test/IDE/complete_decl_attribute.swift @@ -183,6 +183,7 @@ actor MyGenericGlobalActor { // ON_GLOBALVAR-DAG: Keyword/None: exclusivity[#Var Attribute#]; name=exclusivity // ON_GLOBALVAR-DAG: Keyword/None: preconcurrency[#Var Attribute#]; name=preconcurrency // ON_GLOBALVAR-DAG: Keyword/None: backDeployed[#Var Attribute#]; name=backDeployed +// ON_GLOBALVAR-DAG: Keyword/None: concurrent[#Var Attribute#]; name=concurrent // ON_GLOBALVAR-NOT: Keyword // ON_GLOBALVAR-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct // ON_GLOBALVAR-DAG: Decl[Struct]/CurrModule/TypeRelation[Convertible]: MyPropertyWrapper[#Property Wrapper#]; name=MyPropertyWrapper @@ -220,6 +221,7 @@ struct _S { // ON_PROPERTY-DAG: Keyword/None: exclusivity[#Var Attribute#]; name=exclusivity // ON_PROPERTY-DAG: Keyword/None: preconcurrency[#Var Attribute#]; name=preconcurrency // ON_PROPERTY-DAG: Keyword/None: backDeployed[#Var Attribute#]; name=backDeployed +// ON_PROPERTY-DAG: Keyword/None: concurrent[#Var Attribute#]; name=concurrent // ON_PROPERTY-NOT: Keyword // ON_PROPERTY-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct // ON_PROPERTY-DAG: Decl[Struct]/CurrModule/TypeRelation[Convertible]: MyPropertyWrapper[#Property Wrapper#]; name=MyPropertyWrapper @@ -251,6 +253,7 @@ struct _S { // ON_METHOD-DAG: Keyword/None: preconcurrency[#Func Attribute#]; name=preconcurrency // ON_METHOD-DAG: Keyword/None: backDeployed[#Func Attribute#]; name=backDeployed // ON_METHOD-DAG: Keyword/None: lifetime[#Func Attribute#]; name=lifetime +// ON_METHOD-DAG: Keyword/None: concurrent[#Func Attribute#]; name=concurrent // ON_METHOD-NOT: Keyword // ON_METHOD-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct // ON_METHOD-DAG: Decl[Struct]/CurrModule: MyPropertyWrapper[#Property Wrapper#]; name=MyPropertyWrapper @@ -326,6 +329,7 @@ struct _S { // ON_MEMBER_LAST-DAG: Keyword/None: storageRestrictions[#Declaration Attribute#]; name=storageRestrictions // ON_MEMBER_LAST-DAG: Keyword/None: lifetime[#Declaration Attribute#]; name=lifetime // ON_MEMBER_LAST-DAG: Keyword/None: extensible[#Declaration Attribute#]; name=extensible +// ON_MEMBER_LAST-DAG: Keyword/None: concurrent[#Declaration Attribute#]; name=concurrent // ON_MEMBER_LAST-NOT: Keyword // ON_MEMBER_LAST-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct // ON_MEMBER_LAST-DAG: Decl[Struct]/CurrModule/TypeRelation[Convertible]: MyPropertyWrapper[#Property Wrapper#]; name=MyPropertyWrapper @@ -399,6 +403,7 @@ func dummy2() {} // KEYWORD_LAST-DAG: Keyword/None: storageRestrictions[#Declaration Attribute#]; name=storageRestrictions // KEYWORD_LAST-DAG: Keyword/None: lifetime[#Declaration Attribute#]; name=lifetime // KEYWORD_LAST-DAG: Keyword/None: extensible[#Declaration Attribute#]; name=extensible +// KEYWORD_LAST-DAG: Keyword/None: concurrent[#Declaration Attribute#]; name=concurrent // KEYWORD_LAST-NOT: Keyword // KEYWORD_LAST-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct // KEYWORD_LAST-DAG: Decl[Struct]/CurrModule/TypeRelation[Convertible]: MyGenericPropertyWrapper[#Property Wrapper#]; name=MyGenericPropertyWrapper diff --git a/test/IDE/complete_decl_attribute_feature_requirement.swift b/test/IDE/complete_decl_attribute_feature_requirement.swift index 8fabadd74d3f1..f3d12029bc26e 100644 --- a/test/IDE/complete_decl_attribute_feature_requirement.swift +++ b/test/IDE/complete_decl_attribute_feature_requirement.swift @@ -7,8 +7,7 @@ // RUN: %batch-code-completion -filecheck-additional-suffix _DISABLED // RUN: %batch-code-completion -filecheck-additional-suffix _ENABLED \ -// RUN: -enable-experimental-feature ABIAttribute \ -// RUN: -enable-experimental-feature ExecutionAttribute +// RUN: -enable-experimental-feature ABIAttribute // NOTE: Please do not include the ", N items" after "Begin completions". The // item count creates needless merge conflicts given that an "End completions" @@ -18,18 +17,14 @@ // KEYWORD2: Begin completions // KEYWORD2_ENABLED-DAG: Keyword/None: abi[#Func Attribute#]; name=abi -// KEYWORD2_ENABLED-DAG: Keyword/None: execution[#Func Attribute#]; name=execution // KEYWORD2_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi -// KEYWORD2_DISABLED-NOT: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // KEYWORD2: End completions @#^KEYWORD3^# class C {} // KEYWORD3: Begin completions // KEYWORD3_ENABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi -// KEYWORD3_ENABLED-NOT: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // KEYWORD3_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi -// KEYWORD3_DISABLED-NOT: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // KEYWORD3: End completions @#^KEYWORD3_2?check=KEYWORD3^#IB class C2 {} @@ -38,68 +33,52 @@ @#^KEYWORD4^# enum E {} // KEYWORD4: Begin completions // KEYWORD4_ENABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi -// KEYWORD4_ENABLED-NOT: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // KEYWORD4_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi -// KEYWORD4_DISABLED-NOT: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // KEYWORD4: End completions @#^KEYWORD5^# struct S{} // KEYWORD5: Begin completions // KEYWORD5_ENABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi -// KEYWORD5_ENABLED-NOT: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // KEYWORD5_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi -// KEYWORD5_DISABLED-NOT: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // KEYWORD5: End completions @#^ON_GLOBALVAR^# var globalVar // ON_GLOBALVAR: Begin completions // ON_GLOBALVAR_ENABLED-DAG: Keyword/None: abi[#Var Attribute#]; name=abi -// ON_GLOBALVAR_ENABLED-DAG: Keyword/None: execution[#Var Attribute#]; name=execution // ON_GLOBALVAR_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi -// ON_GLOBALVAR_DISABLED-NOT: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // ON_GLOBALVAR: End completions struct _S { @#^ON_INIT^# init() // ON_INIT: Begin completions // ON_INIT_ENABLED-DAG: Keyword/None: abi[#Constructor Attribute#]; name=abi -// ON_INIT_ENABLED-DAG: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // ON_INIT_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi -// ON_INIT_DISABLED-NOT: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // ON_INIT: End completions @#^ON_PROPERTY^# var foo // ON_PROPERTY: Begin completions // ON_PROPERTY_ENABLED-DAG: Keyword/None: abi[#Var Attribute#]; name=abi -// ON_PROPERTY_ENABLED-DAG: Keyword/None: execution[#Var Attribute#]; name=execution // ON_PROPERTY_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi -// ON_PROPERTY_DISABLED-NOT: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // ON_PROPERTY: End completions @#^ON_SUBSCR^# subscript // ON_SUBSCR: Begin completions // ON_SUBSCR_ENABLED-DAG: Keyword/None: abi[#Declaration Attribute#]; name=abi -// ON_SUBSCR_ENABLED-DAG: Keyword/None: execution[#Declaration Attribute#]; name=execution // ON_SUBSCR_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi -// ON_SUBSCR_DISABLED-NOT: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // ON_SUBSCR: End completions @#^ON_METHOD^# private func foo() // ON_METHOD: Begin completions // ON_METHOD_ENABLED-DAG: Keyword/None: abi[#Func Attribute#]; name=abi -// ON_METHOD_ENABLED-DAG: Keyword/None: execution[#Func Attribute#]; name=execution // ON_METHOD_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi -// ON_METHOD_DISABLED-NOT: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // ON_METHOD: End completions func bar(@#^ON_PARAM_1?check=ON_PARAM^#) // ON_PARAM: Begin completions // ON_PARAM_ENABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi -// ON_PARAM_ENABLED-NOT: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // ON_PARAM_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi -// ON_PARAM_DISABLED-NOT: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // ON_PARAM: End completions func bar( @@ -122,9 +101,7 @@ struct _S { @#^ON_MEMBER_LAST^# // ON_MEMBER_LAST: Begin completions // ON_MEMBER_LAST_ENABLED-DAG: Keyword/None: abi[#Declaration Attribute#]; name=abi -// ON_MEMBER_LAST_ENABLED-DAG: Keyword/None: execution[#Declaration Attribute#]; name=execution // ON_MEMBER_LAST_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi -// ON_MEMBER_LAST_DISABLED-NOT: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // ON_MEMBER_LAST: End completions } @@ -136,9 +113,7 @@ func takeClosure(_: () -> Void) { // IN_CLOSURE: Begin completions // FIXME: Not valid in this position (but CompletionLookup can't tell that) // IN_CLOSURE_ENABLED-DAG: Keyword/None: abi[#Declaration Attribute#]; name=abi -// IN_CLOSURE_ENABLED-DAG: Keyword/None: execution[#Declaration Attribute#]; name=execution // IN_CLOSURE_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi -// IN_CLOSURE_DISABLED-NOT: Keyword/None: execution[#{{.*}} Attribute#]; name=execution // IN_CLOSURE: End completions @#^KEYWORD_INDEPENDENT_1?check=KEYWORD_LAST^# @@ -154,7 +129,5 @@ func dummy2() {} // KEYWORD_LAST: Begin completions // KEYWORD_LAST_ENABLED-DAG: Keyword/None: abi[#Declaration Attribute#]; name=abi -// KEYWORD_LAST_ENABLED-DAG: Keyword/None: execution[#Declaration Attribute#]; name=execution // KEYWORD_LAST_DISABLED-NOT: Keyword/None: abi[#Declaration Attribute#]; name=abi -// KEYWORD_LAST_DISABLED-NOT: Keyword/None: execution[#Declaration Attribute#]; name=execution // KEYWORD_LAST: End completions diff --git a/test/ModuleInterface/attrs.swift b/test/ModuleInterface/attrs.swift index 022ac15ff4a26..9573e863be49c 100644 --- a/test/ModuleInterface/attrs.swift +++ b/test/ModuleInterface/attrs.swift @@ -1,7 +1,6 @@ // RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -module-name attrs \ // RUN: -emit-private-module-interface-path %t.private.swiftinterface \ -// RUN: -enable-experimental-feature ABIAttribute \ -// RUN: -enable-experimental-feature ExecutionAttribute +// RUN: -enable-experimental-feature ABIAttribute // RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -module-name attrs // RUN: %target-swift-typecheck-module-from-interface(%t.private.swiftinterface) -module-name attrs @@ -10,7 +9,6 @@ // RUN: %FileCheck %s --check-prefixes CHECK,PRIVATE-CHECK --input-file %t.private.swiftinterface // REQUIRES: swift_feature_ABIAttribute -// REQUIRES: swift_feature_ExecutionAttribute // CHECK: @_transparent public func glass() -> Swift.Int { return 0 }{{$}} @_transparent public func glass() -> Int { return 0 } @@ -87,13 +85,13 @@ public struct MutatingTest { @abi(func abiSpiFunc()) @_spi(spiGroup) public func abiSpiFunc() {} -@execution(concurrent) +@concurrent public func testExecutionConcurrent() async {} -// CHECK: @execution(concurrent) public func testExecutionConcurrent() async +// CHECK: @concurrent public func testExecutionConcurrent() async -@execution(caller) +nonisolated(nonsending) public func testExecutionCaller() async {} -// CHECK: @execution(caller) public func testExecutionCaller() async +// CHECK: nonisolated(nonsending) public func testExecutionCaller() async // CHECK-NOT: @extensible // CHECK: public enum TestExtensible diff --git a/test/ModuleInterface/execution_attr.swift b/test/ModuleInterface/execution_attr.swift deleted file mode 100644 index d3b2e4ada0a76..0000000000000 --- a/test/ModuleInterface/execution_attr.swift +++ /dev/null @@ -1,66 +0,0 @@ -// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -module-name execution_attr -enable-experimental-feature ExecutionAttribute -// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -module-name execution_attr - -// RUN: %FileCheck %s --input-file %t.swiftinterface - -// REQUIRES: swift_feature_ExecutionAttribute - -public struct Test { - // CHECK: #if compiler(>=5.3) && $ExecutionAttribute - // CHECK-NEXT: @execution(caller) public init() async - // CHECK-NEXT: #else - // CHECK-NEXT: public init() async - // CHECK-NEXT: #endif - @execution(caller) - public init() async { - } - - // CHECK: #if compiler(>=5.3) && $ExecutionAttribute - // CHECK-NEXT: @execution(concurrent) public func test() async - // CHECK-NEXT: #else - // CHECK-NEXT: public func test() async - // CHECK-NEXT: #endif - @execution(concurrent) - public func test() async { - } - - // CHECK: #if compiler(>=5.3) && $ExecutionAttribute - // CHECK-NEXT: public func other(_: @execution(caller) () async -> Swift.Void) - // CHECK-NEXT: #else - // CHECK-NEXT: public func other(_: () async -> Swift.Void) - // CHECK-NEXT: #endif - public func other(_: @execution(caller) () async -> Void) {} - - // CHECK: #if compiler(>=5.3) && $ExecutionAttribute - // CHECK-NEXT: @execution(caller) public var testOnVar: Swift.Int { - // CHECK-NEXT: get async - // CHECK-NEXT: } - // CHECK-NEXT: #else - // CHECK-NEXT: public var testOnVar: Swift.Int { - // CHECK-NEXT: get async - // CHECK-NEXT: } - // CHECK-NEXT: #endif - @execution(caller) - public var testOnVar: Int { - get async { - 42 - } - } - - // CHECK: #if compiler(>=5.3) && $ExecutionAttribute - // CHECK-NEXT: @execution(caller) public subscript(onSubscript _: Swift.Int) -> Swift.Bool { - // CHECK-NEXT: get async - // CHECK-NEXT: } - // CHECK-NEXT: #else - // CHECK-NEXT: public subscript(onSubscript _: Swift.Int) -> Swift.Bool { - // CHECK-NEXT: get async - // CHECK-NEXT: } - // CHECK-NEXT: #endif - @execution(caller) - public subscript(onSubscript _: Int) -> Bool { - get async { - false - } - } -} - diff --git a/test/ModuleInterface/execution_behavior_attrs.swift b/test/ModuleInterface/execution_behavior_attrs.swift new file mode 100644 index 0000000000000..b9a73348f87d2 --- /dev/null +++ b/test/ModuleInterface/execution_behavior_attrs.swift @@ -0,0 +1,104 @@ +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -module-name execution_attr +// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -module-name execution_attr + +// RUN: %FileCheck %s --input-file %t.swiftinterface + +// REQUIRES: concurrency + +public struct Test { + // CHECK: #if compiler(>=5.3) && $AsyncExecutionBehaviorAttributes + // CHECK-NEXT: nonisolated(nonsending) public init() async + // CHECK-NEXT: #endif + nonisolated(nonsending) + public init() async { + } + + // CHECK: #if compiler(>=5.3) && $AsyncExecutionBehaviorAttributes + // CHECK-NEXT: @concurrent public init(something: Swift.Int) async + // CHECK-NEXT: #endif + @concurrent + public init(something: Int) async { + } + + // CHECK-NOT: #if compiler(>=5.3) && $AsyncExecutionBehaviorAttributes + // CHECK: public init(noExplicit: Swift.String) async + // CHECK-NOT: #endif + public init(noExplicit: String) async { + } + + // CHECK: #if compiler(>=5.3) && $AsyncExecutionBehaviorAttributes + // CHECK-NEXT: @concurrent public func test() async + // CHECK-NEXT: #endif + @concurrent + public func test() async { + } + + // CHECK: #if compiler(>=5.3) && $AsyncExecutionBehaviorAttributes + // CHECK-NEXT: public func other(_: nonisolated(nonsending) () async -> Swift.Void) + // CHECK-NEXT: #endif + public func other(_: nonisolated(nonsending) () async -> Void) {} + + // CHECK-NOT: #if compiler(>=5.3) && $AsyncExecutionBehaviorAttributes + // CHECK: public func concurrentResult(_: () async -> Swift.Void) -> (Swift.Int) async -> Swift.Void + // CHECK-NOT: #endif + public func concurrentResult(_: () async -> Void) -> @concurrent (Int) async -> Void {} + + // CHECK: #if compiler(>=5.3) && $AsyncExecutionBehaviorAttributes + // CHECK-NEXT: public func nestedPositions1(_: Swift.Array<[Swift.String : nonisolated(nonsending) (Swift.Int) async -> Swift.Void]>) + // CHECK-NEXT: #endif + public func nestedPositions1(_: Array<[String: nonisolated(nonsending) (Int) async -> Void]>) {} + + // CHECK-NOT: #if compiler(>=5.3) && $AsyncExecutionBehaviorAttributes + // CHECK: public func nestedPositions2(_: Swift.Array<[Swift.String : (Swift.Int) async -> Swift.Void]>) + // CHECK-NOT: #endif + public func nestedPositions2(_: Array<[String: @concurrent (Int) async -> Void]>) {} + + // CHECK: #if compiler(>=5.3) && $AsyncExecutionBehaviorAttributes + // CHECK-NEXT: nonisolated(nonsending) public var testOnVar: Swift.Int { + // CHECK-NEXT: get async + // CHECK-NEXT: } + // CHECK-NEXT: #endif + nonisolated(nonsending) + public var testOnVar: Int { + get async { + 42 + } + } + + // CHECK: #if compiler(>=5.3) && $AsyncExecutionBehaviorAttributes + // CHECK-NEXT: @concurrent public var testOnVarConcurrent: Swift.Int { + // CHECK-NEXT: get async + // CHECK-NEXT: } + // CHECK-NEXT: #endif + @concurrent + public var testOnVarConcurrent: Int { + get async { + 42 + } + } + + // CHECK: #if compiler(>=5.3) && $AsyncExecutionBehaviorAttributes + // CHECK-NEXT: nonisolated(nonsending) public subscript(onSubscript _: Swift.Int) -> Swift.Bool { + // CHECK-NEXT: get async + // CHECK-NEXT: } + // CHECK-NEXT: #endif + nonisolated(nonsending) + public subscript(onSubscript _: Int) -> Bool { + get async { + false + } + } + + // CHECK: #if compiler(>=5.3) && $AsyncExecutionBehaviorAttributes + // CHECK-NEXT: @concurrent public subscript(concurrentOnSubscript _: Swift.Int) -> Swift.Bool { + // CHECK-NEXT: get async + // CHECK-NEXT: } + // CHECK-NEXT: #endif + @concurrent + public subscript(concurrentOnSubscript _: Int) -> Bool { + get async { + false + } + } +} + diff --git a/test/Parse/execution.swift b/test/Parse/execution.swift deleted file mode 100644 index 18d5a9e51ea00..0000000000000 --- a/test/Parse/execution.swift +++ /dev/null @@ -1,56 +0,0 @@ -// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature ExecutionAttribute - -// REQUIRES: concurrency -// REQUIRES: swift_feature_ExecutionAttribute - -typealias F = @execution(concurrent) () async -> Void - -typealias E = @execution(concurrent) () -> Void -// expected-error@-1 {{cannot use '@execution' on non-async function type}} - -func test1(_: @execution(caller) (Int...) async -> Void) {} -func test2(_: @execution(concurrent) (Int...) async -> Void) {} - -func test_err1_concurrent(_: @execution(concurrent) @MainActor () async -> Void) {} -// expected-error@-1 {{cannot use '@execution' because function type is isolated to a global actor 'MainActor'}} - -func test_err1_caller(_: @execution(caller) @MainActor () async -> Void) {} -// expected-error@-1 {{cannot use '@execution' because function type is isolated to a global actor 'MainActor'}} - -func test_err2_concurrent(_: @execution(concurrent) @isolated(any) () async -> Void) {} -// expected-error@-1 {{cannot use '@execution' together with @isolated(any)}} - -func test_err2_caller(_: @execution(caller) @isolated(any) () async -> Void) {} -// expected-error@-1 {{cannot use '@execution' together with @isolated(any)}} - -func test_err3_concurrent(_: @execution(concurrent) (isolated (any Actor)?) async -> Void) {} -// expected-error@-1 {{cannot use '@execution' together with an isolated parameter}} - -func test_err3_caller(_: @execution(caller) (isolated (any Actor)?) async -> Void) {} -// expected-error@-1 {{cannot use '@execution' together with an isolated parameter}} - -func test_err4(_: @execution (Int) -> Void) {} -// expected-error@-1 {{expected 'concurrent' or 'caller' as the execution behavior}} -// expected-error@-2 {{expected parameter type following ':'}} - -func test_err5(_: @execution( () async -> Void) {} -// expected-error@-1 {{expected 'concurrent' or 'caller' as the execution behavior}} -// expected-note@-2 {{to match this opening '('}} -// expected-error@-3 {{expected ')' after execution behavior}} - -func test_err6(_: @execution(hello) () async -> Void) {} -// expected-error@-1 {{expected 'concurrent' or 'caller' as the execution behavior}} - -func test_err7(_: @execution(hello () async -> Void) {} -// expected-error@-1 {{expected 'concurrent' or 'caller' as the execution behavior}} -// expected-note@-2 {{to match this opening '('}} -// expected-error@-3 {{expected ')' after execution behavior}} - -func test_err8(_: @execution(concurrent) Int) {} // expected-error {{attribute does not apply to type}} - -do { - let _ = [@execution(caller) () async -> Void]() - let _ = [@execution(caller) () -> Void]() - // expected-error@-1 {{cannot use '@execution' on non-async function type}} -} - diff --git a/test/Parse/execution_behavior_attrs.swift b/test/Parse/execution_behavior_attrs.swift new file mode 100644 index 0000000000000..6397a35b8e70e --- /dev/null +++ b/test/Parse/execution_behavior_attrs.swift @@ -0,0 +1,86 @@ +// RUN: %target-typecheck-verify-swift -disable-availability-checking + +// REQUIRES: concurrency + +typealias F = @concurrent () async -> Void + +typealias E = @concurrent () -> Void +// expected-error@-1 {{cannot use '@concurrent' on non-async function type}} + +func test1(_: nonisolated(nonsending) (Int...) async -> Void) {} +func test2(_: @concurrent (Int...) async -> Void) {} + +func test_err1_concurrent(_: @concurrent @MainActor () async -> Void) {} +// expected-error@-1 {{cannot use '@concurrent' because function type is isolated to a global actor 'MainActor'}} + +func test_err1_caller(_: nonisolated(nonsending) @MainActor () async -> Void) {} +// expected-error@-1 {{cannot use 'nonisolated(nonsending)' because function type is isolated to a global actor 'MainActor'}} + +func test_err2_concurrent(_: @concurrent @isolated(any) () async -> Void) {} +// expected-error@-1 {{cannot use '@concurrent' together with @isolated(any)}} + +func test_err2_caller(_: nonisolated(nonsending) @isolated(any) () async -> Void) {} +// expected-error@-1 {{cannot use 'nonisolated(nonsending)' together with @isolated(any)}} + +func test_err3_concurrent(_: @concurrent (isolated (any Actor)?) async -> Void) {} +// expected-error@-1 {{cannot use '@concurrent' together with an isolated parameter}} + +func test_err3_caller(_: nonisolated(nonsending) (isolated (any Actor)?) async -> Void) {} +// expected-error@-1 {{cannot use 'nonisolated(nonsending)' together with an isolated parameter}} + +func test_err4(_: nonisolated (Int) -> Void) {} +// expected-error@-1 {{expected 'nonsending' in modifier}} +// expected-error@-2 {{expected '{' in body of function declaration}} +// expected-warning@-3 {{extraneous whitespace between attribute name and '('; this is an error in the Swift 6 language mode}} +// expected-error@-4 {{consecutive statements on a line must be separated by ';'}} +// expected-error@-5 {{expected expression}} + +func test_err5(_: nonisolated( () async -> Void) {} +// expected-error@-1 {{expected 'nonsending' in modifier}} + +func test_err6(_: nonisolated(hello) () async -> Void) {} +// expected-error@-1 {{expected 'nonsending' in modifier}} +// expected-error@-2 {{cannot have more than one parameter list}} +// expected-error@-3 {{cannot find type 'hello' in scope}} +// expected-error@-4 {{onsecutive statements on a line must be separated by ';'}} +// expected-error@-5 {{expected expression}} + +func test_err7(_: nonisolated(hello () async -> Void) {} +// expected-error@-1 {{expected 'nonsending' in modifier}} +// expected-error@-2 {{cannot find type 'hello' in scope}} + +func test_err8(_: @concurrent Int) {} // expected-error {{attribute does not apply to type}} + +do { + let _ = [nonisolated(nonsending) () async -> Void]() + let _ = [nonisolated(nonsending) () -> Void]() + // expected-error@-1 {{cannot use 'nonisolated(nonsending)' on non-async function type}} +} + +protocol P {} + +struct S : nonisolated + P { // Ok +} + +do { + func nonisolated() {} + + // `nonisolated` is parsed as a function call + nonisolated // expected-error {{function is unused}} + (42) // expected-warning {{integer literal is unused}} + + let _: nonisolated // expected-error {{cannot find type 'nonisolated' in scope}} + (Int) async -> Void // expected-error {{expected member name or initializer call after type name}} + // expected-note@-1 {{use '.self' to reference the type object}} + // expected-warning@-2 {{expression of type '((Int) async -> Void).Type' is unused}} + + _ = [nonisolated()] +} + +do { + func nonisolated(_: Int) -> Int { 42 } + + nonisolated(0) // expected-warning {{result of call to 'nonisolated' is unused}} + print("hello") +} diff --git a/test/SILGen/execution_attr.swift b/test/SILGen/execution_attr.swift index a5682dede74ae..06336c713cf24 100644 --- a/test/SILGen/execution_attr.swift +++ b/test/SILGen/execution_attr.swift @@ -1,8 +1,7 @@ -// RUN: %target-swift-emit-silgen %s -enable-experimental-feature ExecutionAttribute | %FileCheck -check-prefix CHECK -check-prefix DISABLED %s -// RUN: %target-swift-emit-silgen %s -enable-experimental-feature ExecutionAttribute -enable-experimental-feature AsyncCallerExecution | %FileCheck -check-prefix CHECK -check-prefix ENABLED %s +// RUN: %target-swift-emit-silgen %s | %FileCheck -check-prefix CHECK -check-prefix DISABLED %s +// RUN: %target-swift-emit-silgen %s -enable-experimental-feature AsyncCallerExecution | %FileCheck -check-prefix CHECK -check-prefix ENABLED %s // REQUIRES: concurrency -// REQUIRES: swift_feature_ExecutionAttribute // REQUIRES: swift_feature_AsyncCallerExecution // Validate that both with and without the experimental flag we properly codegen @@ -11,30 +10,30 @@ // CHECK-LABEL: // executionCaller() // CHECK-NEXT: // Isolation: caller_isolation_inheriting // CHECK-NEXT: sil hidden [ossa] @$s14execution_attr0A6CalleryyYaF : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () { -@execution(caller) +nonisolated(nonsending) func executionCaller() async {} // CHECK-LABEL: // executionConcurrent() // CHECK: // Isolation: nonisolated // CHECK: sil hidden [ossa] @$s14execution_attr0A10ConcurrentyyYaF : $@convention(thin) @async () -> () { -@execution(concurrent) +@concurrent func executionConcurrent() async {} // DISABLED: sil hidden [ossa] @$s14execution_attr0A15CallerParameteryyyyYaYCXEYaF : $@convention(thin) @async (@guaranteed @noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> ()) -> () { // ENABLED: sil hidden [ossa] @$s14execution_attr0A15CallerParameteryyyyYaYCXEYaF : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, @guaranteed @noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> ()) -> () { // CHECK: } // end sil function '$s14execution_attr0A15CallerParameteryyyyYaYCXEYaF' -func executionCallerParameter(_ x: @execution(caller) () async -> ()) async { +func executionCallerParameter(_ x: nonisolated(nonsending) () async -> ()) async { await x() } // DISABLED-LABEL: sil hidden [ossa] @$s14execution_attr0A19ConcurrentParameteryyyyYaXEYaF : $@convention(thin) @async (@guaranteed @noescape @async @callee_guaranteed () -> ()) -> () { // ENABLED-LABEL: sil hidden [ossa] @$s14execution_attr0A19ConcurrentParameteryyyyYaXEYaF : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, @guaranteed @noescape @async @callee_guaranteed () -> ()) -> () { -func executionConcurrentParameter(_ x: @execution(concurrent) () async -> ()) async { +func executionConcurrentParameter(_ x: @concurrent () async -> ()) async { await x() } struct S { - let field: @execution(caller) () async -> () + let field: nonisolated(nonsending) () async -> () } // DISABLED: sil hidden [ossa] @$s14execution_attr0A11CallerFieldyyAA1SVYaF : $@convention(thin) @async (@guaranteed S) -> () { @@ -61,5 +60,5 @@ extension S { // CHECK-LABEL: // S.executionCallerFieldMethod(_:) // CHECK: // Isolation: unspecified // CHECK: sil hidden [ossa] @$s14execution_attr1SV0A17CallerFieldMethodyyyyYaYCXEF : $@convention(method) (@guaranteed @noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> (), @guaranteed S) -> () { - func executionCallerFieldMethod(_ x: @execution(caller) () async -> ()) {} + func executionCallerFieldMethod(_ x: nonisolated(nonsending) () async -> ()) {} } diff --git a/test/Serialization/Inputs/caller_inheriting_isolation.swift b/test/Serialization/Inputs/caller_inheriting_isolation.swift index cd2bd31fc9235..b249da80dbc88 100644 --- a/test/Serialization/Inputs/caller_inheriting_isolation.swift +++ b/test/Serialization/Inputs/caller_inheriting_isolation.swift @@ -2,22 +2,22 @@ public func unspecifiedAsync(_ t: T) async { } -@execution(caller) +nonisolated(nonsending) public func unspecifiedAsyncCaller(_ t: T) async { } -@execution(concurrent) +@concurrent public func unspecifiedAsyncConcurrent(_ t: T) async { } nonisolated public func nonisolatedAsync(_ t: T) async { } -@execution(caller) -nonisolated public func nonisolatedAsyncCaller(_ t: T) async { +nonisolated(nonsending) +public func nonisolatedAsyncCaller(_ t: T) async { } -@execution(concurrent) +@concurrent nonisolated public func nonisolatedAsyncConcurrent(_ t: T) async { } @@ -26,22 +26,22 @@ public struct S { public func unspecifiedAsync(_ t: T) async { } - @execution(caller) + nonisolated(nonsending) public func unspecifiedAsyncCaller(_ t: T) async { } - @execution(concurrent) + @concurrent public func unspecifiedAsyncConcurrent(_ t: T) async { } nonisolated public func nonisolatedAsync(_ t: T) async { } - @execution(caller) - nonisolated public func nonisolatedAsyncCaller(_ t: T) async { + nonisolated(nonsending) + public func nonisolatedAsyncCaller(_ t: T) async { } - @execution(concurrent) + @concurrent nonisolated public func nonisolatedAsyncConcurrent(_ t: T) async { } } diff --git a/test/Serialization/caller_isolation_inherit.swift b/test/Serialization/caller_isolation_inherit.swift index d58f749dd0b62..58612b169012e 100644 --- a/test/Serialization/caller_isolation_inherit.swift +++ b/test/Serialization/caller_isolation_inherit.swift @@ -1,13 +1,12 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -enable-experimental-feature ExecutionAttribute -enable-experimental-feature AsyncCallerExecution -emit-module-path %t/WithFeature.swiftmodule -module-name WithFeature %S/Inputs/caller_inheriting_isolation.swift -swift-version 6 -// RUN: %target-swift-frontend -enable-experimental-feature ExecutionAttribute -emit-module-path %t/WithoutFeature.swiftmodule -module-name WithoutFeature %S/Inputs/caller_inheriting_isolation.swift -swift-version 6 +// RUN: %target-swift-frontend -enable-experimental-feature AsyncCallerExecution -emit-module-path %t/WithFeature.swiftmodule -module-name WithFeature %S/Inputs/caller_inheriting_isolation.swift -swift-version 6 +// RUN: %target-swift-frontend -emit-module-path %t/WithoutFeature.swiftmodule -module-name WithoutFeature %S/Inputs/caller_inheriting_isolation.swift -swift-version 6 // RUN: %target-swift-frontend -module-name main -I %t %s -emit-sil -o - | %FileCheck %s -// RUN: %target-swift-frontend -enable-experimental-feature ExecutionAttribute -enable-experimental-feature AsyncCallerExecution -module-name main -I %t %s -emit-sil -verify -swift-version 6 +// RUN: %target-swift-frontend -enable-experimental-feature AsyncCallerExecution -module-name main -I %t %s -emit-sil -verify -swift-version 6 // REQUIRES: asserts -// REQUIRES: swift_feature_ExecutionAttribute // REQUIRES: swift_feature_AsyncCallerExecution import WithFeature diff --git a/test/attr/attr_abi.swift b/test/attr/attr_abi.swift index 1409d75bf0fdf..96be8a8d29105 100644 --- a/test/attr/attr_abi.swift +++ b/test/attr/attr_abi.swift @@ -1,9 +1,8 @@ -// RUN: %target-typecheck-verify-swift -enable-experimental-feature Extern -enable-experimental-feature ABIAttribute -enable-experimental-feature AddressableParameters -enable-experimental-feature NoImplicitCopy -enable-experimental-feature SymbolLinkageMarkers -enable-experimental-feature StrictMemorySafety -enable-experimental-feature LifetimeDependence -enable-experimental-feature CImplementation -enable-experimental-feature ExecutionAttribute -import-bridging-header %S/Inputs/attr_abi.h -parse-as-library -Rabi-inference -debugger-support +// RUN: %target-typecheck-verify-swift -enable-experimental-feature Extern -enable-experimental-feature ABIAttribute -enable-experimental-feature AddressableParameters -enable-experimental-feature NoImplicitCopy -enable-experimental-feature SymbolLinkageMarkers -enable-experimental-feature StrictMemorySafety -enable-experimental-feature LifetimeDependence -enable-experimental-feature CImplementation -import-bridging-header %S/Inputs/attr_abi.h -parse-as-library -Rabi-inference -debugger-support // REQUIRES: swift_feature_ABIAttribute // REQUIRES: swift_feature_AddressableParameters // REQUIRES: swift_feature_CImplementation -// REQUIRES: swift_feature_ExecutionAttribute // REQUIRES: swift_feature_Extern // REQUIRES: swift_feature_LifetimeDependence // REQUIRES: swift_feature_NoImplicitCopy @@ -948,7 +947,7 @@ func addressableTest( _ e: @MainActor () -> AnyObject, _ f: (isolated MainActor) -> AnyObject, _ g: @isolated(any) () -> AnyObject, // expected-error {{parameter 'g' type '@isolated(any) () -> AnyObject' in '@abi' should match '() -> AnyObject'}} - _ h: @execution(caller) () async -> AnyObject, + _ h: nonisolated(nonsending) () async -> AnyObject, _ i: () -> AnyObject, // expected-error {{parameter 'i' type '() -> AnyObject' in '@abi' should match '@isolated(any) () -> AnyObject'}} _ j: () async -> Void, _ k: () -> Void, // expected-error {{parameter 'k' type '() -> Void' in '@abi' should match '() async -> Void'}} @@ -1232,41 +1231,41 @@ nonisolated func isolation5() {} @abi(func isolation7(_: some Actor)) func isolation7(_: isolated some Actor) {} -@abi(@execution(concurrent) func isolation8() async) -@execution(concurrent) func isolation8() async {} +@abi(@concurrent func isolation8() async) +@concurrent func isolation8() async {} @abi(func isolation9() async) -@execution(concurrent) func isolation9() async {} +@concurrent func isolation9() async {} -@abi(@execution(concurrent) func isolation10() async) +@abi(@concurrent func isolation10() async) func isolation10() async {} @abi(nonisolated func isolation11() async) -@execution(concurrent) func isolation11() async {} +@concurrent func isolation11() async {} -@abi(@execution(concurrent) func isolation12() async) +@abi(@concurrent func isolation12() async) nonisolated func isolation12() async {} -@abi(@execution(caller) func isolation13() async) -@execution(caller) func isolation13() async {} +@abi(nonisolated(nonsending) func isolation13() async) +nonisolated(nonsending) func isolation13() async {} @abi(func isolation14() async) -@execution(caller) func isolation14() async {} +nonisolated(nonsending) func isolation14() async {} -@abi(@execution(caller) func isolation15() async) +@abi(nonisolated(nonsending) func isolation15() async) func isolation15() async {} @abi(nonisolated func isolation16() async) -@execution(caller) func isolation16() async {} +nonisolated(nonsending) func isolation16() async {} -@abi(@execution(caller) func isolation17() async) +@abi(nonisolated(nonsending) func isolation17() async) nonisolated func isolation17() async {} -@abi(@execution(caller) func isolation18() async) -@execution(concurrent) func isolation18() async {} +@abi(nonisolated(nonsending) func isolation18() async) +@concurrent func isolation18() async {} -@abi(@execution(concurrent) func isolation19() async) -@execution(caller) func isolation19() async {} +@abi(@concurrent func isolation19() async) +nonisolated(nonsending) func isolation19() async {} // NSCopying - see attr/attr_abi_objc.swift diff --git a/test/attr/attr_execution.swift b/test/attr/attr_execution.swift deleted file mode 100644 index 9ee107a382121..0000000000000 --- a/test/attr/attr_execution.swift +++ /dev/null @@ -1,141 +0,0 @@ -// RUN: %target-typecheck-verify-swift -target %target-swift-5.1-abi-triple -enable-experimental-feature ExecutionAttribute - -// REQUIRES: concurrency -// REQUIRES: swift_feature_ExecutionAttribute - -@execution(something) func invalidAttr() async {} // expected-error {{unknown option 'something' for attribute 'execution'}} - -@execution(concurrent) @execution(caller) func mutipleAttrs() async {} -// expected-error@-1 {{duplicate attribute}} expected-note@-1 {{attribute already specified here}} - -do { - @execution(caller) struct S {} - // expected-error@-1 {{'@execution(caller)' attribute cannot be applied to this declaration}} - - func f(@execution(caller) param: Int) {} - // expected-error@-1 {{'@execution(caller)' attribute cannot be applied to this declaration}} -} - -@execution(concurrent) func nonAsync1() {} -// expected-error@-1 {{cannot use '@execution' on non-async global function 'nonAsync1()'}} - -@execution(caller) func nonAsync2() {} -// expected-error@-1 {{cannot use '@execution' on non-async global function 'nonAsync2()'}} - -@execution(concurrent) func testGlobal() async {} // Ok - -struct Test { - @execution(concurrent) init() {} - // expected-error@-1 {{cannot use '@execution' on non-async initializer 'init()'}} - - @execution(concurrent) init(async: Void) async {} - - @execution(concurrent) func member() {} - // expected-error@-1 {{cannot use '@execution' on non-async instance method 'member()'}} - - @execution(concurrent) func member() async {} // Ok - - @execution(concurrent) var syncP: Int { - // expected-error@-1 {{cannot use '@execution' on non-async property 'syncP'}} - get {} - } - @execution(concurrent) var asyncP: Int { - get async {} - } - - // expected-error@+1 {{cannot use '@execution' on non-async subscript 'subscript(sync:)'}} - @execution(caller) subscript(sync _: Int) -> Bool { - @execution(concurrent) get { false } - // expected-error@-1 {{@execution(concurrent)' attribute cannot be applied to this declaration}} - @execution(concurrent) set { } - // expected-error@-1 {{@execution(concurrent)' attribute cannot be applied to this declaration}} - } - @execution(caller) subscript(async _: Int) -> Bool { - get async {} - } - - @execution(caller) var storedVar: Int - // expected-error@-1 {{'@execution(caller)' must not be used on stored properties}} - @execution(caller) let storedLet: Int - // expected-error@-1 {{'@execution(caller)' must not be used on stored properties}} -} - -do { - class C { - @execution(caller) deinit {} - // expected-error@-1 {{'@execution(caller)' attribute cannot be applied to this declaration}} - } -} - -do { - @execution(caller) func local() async {} // Ok - - protocol P { - @execution(caller) var syncP: Int { get } - // expected-error@-1 {{cannot use '@execution' on non-async property 'syncP'}} - - @execution(caller) var asyncP: Int { get async } - } -} - -struct TestAttributeCollisions { - @execution(concurrent) nonisolated func testNonIsolated() async {} - - @execution(concurrent) func test(arg: isolated MainActor) async {} - // expected-error@-1 {{cannot use '@execution' on instance method 'test(arg:)' because it has an isolated parameter: 'arg'}} - @execution(concurrent) subscript(test arg: isolated MainActor) -> Int { - // expected-error@-1 {{cannot use '@execution' on subscript 'subscript(test:)' because it has an isolated parameter: 'arg'}} - get async {} - } - - @execution(concurrent) func testIsolationAny(arg: @isolated(any) () -> Void) async {} - // expected-error@-1 {{cannot use '@execution' on instance method 'testIsolationAny(arg:)' because it has a dynamically isolated parameter: 'arg'}} - @execution(concurrent) subscript(testIsolationAny arg: @isolated(any) () -> Void) -> Int { - // expected-error@-1 {{cannot use '@execution' on subscript 'subscript(testIsolationAny:)' because it has a dynamically isolated parameter: 'arg'}} - get async {} - } - - @MainActor @execution(concurrent) func testGlobalActor() async {} - // expected-warning @-1 {{instance method 'testGlobalActor()' has multiple actor-isolation attributes (@MainActor and @execution(concurrent))}} - - @execution(caller) nonisolated func testNonIsolatedCaller() async {} // Ok - @MainActor @execution(caller) func testGlobalActorCaller() async {} - // expected-warning@-1 {{instance method 'testGlobalActorCaller()' has multiple actor-isolation attributes (@MainActor and @execution(caller))}} - @execution(caller) func testCaller(arg: isolated MainActor) async {} - // expected-error@-1 {{cannot use '@execution' on instance method 'testCaller(arg:)' because it has an isolated parameter: 'arg'}} - - @execution(concurrent) @Sendable func test(_: @Sendable () -> Void, _: sending Int) async {} // Ok - @execution(caller) @Sendable func testWithSendableCaller(_: @Sendable () -> Void, _: sending Int) async {} // Ok -} - -@MainActor -protocol P { - func test() async -} - -struct InfersMainActor : P { - @execution(concurrent) func test() async {} -} - -@MainActor -struct IsolatedType { - @execution(concurrent) func test() async {} -} - -_ = { @execution(caller) in // Ok -} - -_ = { @execution(concurrent) in // Ok -} - -_ = { @MainActor @execution(concurrent) in - // expected-error@-1 {{cannot use '@execution' because function type is isolated to a global actor 'MainActor'}} -} - -_ = { @execution(concurrent) () -> Int in - // expected-error@-1 {{'@execution' on non-async closure}} -} - -_ = { @execution(caller) (x: isolated (any Actor)?) in - // expected-error@-1 {{cannot use '@execution' together with an isolated parameter}} -} diff --git a/test/attr/execution_behavior_attrs.swift b/test/attr/execution_behavior_attrs.swift new file mode 100644 index 0000000000000..90a9a818c0c30 --- /dev/null +++ b/test/attr/execution_behavior_attrs.swift @@ -0,0 +1,139 @@ +// RUN: %target-typecheck-verify-swift -target %target-swift-5.1-abi-triple + +// REQUIRES: concurrency + +// FIXME: Bad parser diagnostic on C++ side +nonisolated(something) func invalidAttr() async {} // expected-error {{cannot find 'nonisolated' in scope}} +// expected-error@-1 {{cannot find 'something' in scope}} +// expected-error@-2 {{consecutive statements on a line must be separated by ';'}} + +@concurrent nonisolated(nonsending) func mutipleAttrs() async {} +// expected-error@-1 {{global function 'mutipleAttrs()' has multiple actor-isolation attributes (@concurrent and 'nonisolated(nonsending)')}} + +do { + nonisolated(nonsending) struct S {} + // expected-error@-1 {{'nonisolated(nonsending)' is only applicable to asynchronous functions, initializers, subscripts and computed properties}} + + + func f(nonisolated(nonsending) param: Int) {} + // expected-error@-1 {{expected parameter name followed by ':'}} + // expected-error@-2 {{parameter may have at most one of the 'inout', 'borrowing', or 'consuming' specifiers}} +} + +@concurrent func nonAsync1() {} +// expected-error@-1 {{cannot use @concurrent on non-async global function 'nonAsync1()'}} + +nonisolated(nonsending) func nonAsync2() {} +// expected-error@-1 {{cannot use 'nonisolated(nonsending)' on non-async global function 'nonAsync2()'}} + +@concurrent func testGlobal() async {} // Ok + +struct Test { + @concurrent init() {} + // expected-error@-1 {{cannot use @concurrent on non-async initializer 'init()'}} + + @concurrent init(async: Void) async {} + + @concurrent func member() {} + // expected-error@-1 {{cannot use @concurrent on non-async instance method 'member()'}} + + @concurrent func member() async {} // Ok + + @concurrent var syncP: Int { + // expected-error@-1 {{cannot use @concurrent on non-async property 'syncP'}} + get {} + } + @concurrent var asyncP: Int { + get async {} + } + + // expected-error@+1 {{cannot use 'nonisolated(nonsending)' on non-async subscript 'subscript(sync:)'}} + nonisolated(nonsending) subscript(sync _: Int) -> Bool { + @concurrent get { false } + // expected-error@-1 {{@concurrent' attribute cannot be applied to this declaration}} + @concurrent set { } + // expected-error@-1 {{@concurrent' attribute cannot be applied to this declaration}} + } + nonisolated(nonsending) subscript(async _: Int) -> Bool { + get async {} + } + + // FIXME: Incorrect quotes due to inconsistent DeclAttribute printing between modifiers and attributes + nonisolated(nonsending) var storedVar: Int + // expected-error@-1 {{''nonisolated(nonsending)'' must not be used on stored properties}} + nonisolated(nonsending) let storedLet: Int + // expected-error@-1 {{''nonisolated(nonsending)'' must not be used on stored properties}} +} + +do { + class C { + nonisolated(nonsending) deinit {} + // expected-error@-1 {{'nonisolated(nonsending)' is only applicable to asynchronous functions, initializers, subscripts and computed properties}} + } +} + +do { + nonisolated(nonsending) func local() async {} // Ok + + protocol P { + nonisolated(nonsending) var syncP: Int { get } + // expected-error@-1 {{cannot use 'nonisolated(nonsending)' on non-async property 'syncP'}} + + nonisolated(nonsending) var asyncP: Int { get async } + } +} + +struct TestAttributeCollisions { + @concurrent nonisolated func testNonIsolated() async {} + + @concurrent func test(arg: isolated MainActor) async {} + // expected-error@-1 {{cannot use @concurrent on instance method 'test(arg:)' because it has an isolated parameter: 'arg'}} + @concurrent subscript(test arg: isolated MainActor) -> Int { + // expected-error@-1 {{cannot use @concurrent on subscript 'subscript(test:)' because it has an isolated parameter: 'arg'}} + get async {} + } + + @concurrent func testIsolationAny(arg: @isolated(any) () -> Void) async {} + // expected-error@-1 {{cannot use @concurrent on instance method 'testIsolationAny(arg:)' because it has a dynamically isolated parameter: 'arg'}} + @concurrent subscript(testIsolationAny arg: @isolated(any) () -> Void) -> Int { + // expected-error@-1 {{cannot use @concurrent on subscript 'subscript(testIsolationAny:)' because it has a dynamically isolated parameter: 'arg'}} + get async {} + } + + @MainActor @concurrent func testGlobalActor() async {} + // expected-warning @-1 {{instance method 'testGlobalActor()' has multiple actor-isolation attributes (@MainActor and @concurrent)}} + + nonisolated(nonsending) nonisolated func testNonIsolatedCaller() async {} // expected-error {{duplicate modifier}} expected-note {{modifier already specified here}} + @MainActor nonisolated(nonsending) func testGlobalActorCaller() async {} + // expected-warning@-1 {{instance method 'testGlobalActorCaller()' has multiple actor-isolation attributes (@MainActor and 'nonisolated(nonsending)')}} + nonisolated(nonsending) func testCaller(arg: isolated MainActor) async {} + // expected-error@-1 {{cannot use 'nonisolated(nonsending)' on instance method 'testCaller(arg:)' because it has an isolated parameter: 'arg'}} + + @concurrent @Sendable func test(_: @Sendable () -> Void, _: sending Int) async {} // Ok + @Sendable nonisolated(nonsending) func testWithSendableCaller(_: @Sendable () -> Void, _: sending Int) async {} // Ok +} + +@MainActor +protocol P { + func test() async +} + +struct InfersMainActor : P { + @concurrent func test() async {} +} + +@MainActor +struct IsolatedType { + @concurrent func test() async {} +} + +_ = { @concurrent in // Ok +} + +_ = { @MainActor @concurrent in + // expected-error@-1 {{cannot use @concurrent because function type is isolated to a global actor 'MainActor'}} +} + +_ = { @concurrent () -> Int in + // expected-error@-1 {{@concurrent on non-async closure}} +} diff --git a/userdocs/diagnostics/async-caller-execution.md b/userdocs/diagnostics/async-caller-execution.md index a763e13482c7a..374ee54263069 100644 --- a/userdocs/diagnostics/async-caller-execution.md +++ b/userdocs/diagnostics/async-caller-execution.md @@ -7,9 +7,9 @@ these functions. This feature was proposed in [SE-0461](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0461-async-function-isolation.md) -* The `@execution(concurrent)` attribute specifies that a function must always +* The `@concurrent` attribute specifies that a function must always switch off of an actor to run. This is the default behavior without `AsyncCallerExecution`. -* The `@execution(caller)` attribute specifies that a function must always +* The `nonisolated(nonsending)` modifier specifies that a function must always run on the caller's actor. This is the default behavior with `AsyncCallerExecution`.