From 1a3af5c91de8b3c4bb9a2cb32ef60021f2898704 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 1 Apr 2025 15:21:03 -0700 Subject: [PATCH 01/14] [Diagnostics] Adjust `@execution(...)` diagnostic to take `DeclAttribute` or `StringRef` It has been decided to split the attribute into `@concurrent` and `nonisolated(nonsending`. Adjusting diagnostics to accept the attribute makes the transition easier. --- include/swift/AST/DiagnosticsSema.def | 61 +++++++++++++++------------ lib/Sema/TypeCheckAttr.cpp | 21 +++++---- lib/Sema/TypeCheckType.cpp | 13 +++--- test/attr/attr_execution.swift | 30 ++++++------- 4 files changed, 69 insertions(+), 56 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 217a95377b350..187de7a9e16e9 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8553,40 +8553,47 @@ GROUPED_ERROR(isolated_conformance_wrong_domain,IsolatedConformances,none, // MARK: @execution Attribute //===----------------------------------------------------------------------===// -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(execution_behavior_only_on_async_closure,none, + "cannot use '%0' on non-async closure", + (DeclAttribute)) -ERROR(attr_execution_type_attr_only_on_async,none, - "cannot use '@execution' on non-async function type", - ()) +ERROR(execution_behavior_type_attr_only_on_async,none, + "cannot use '@%0' on non-async function type", + (StringRef)) -ERROR(attr_execution_incompatible_isolated_parameter,none, - "cannot use '@execution' on %kind0 because it has " - "an isolated parameter: %1", - (ValueDecl *, ValueDecl *)) +ERROR(execution_behavior_incompatible_isolated_parameter,none, + "cannot use '%0' on %kind1 because it has " + "an isolated parameter: %2", + (DeclAttribute, ValueDecl *, ValueDecl *)) -ERROR(attr_execution_incompatible_dynamically_isolated_parameter,none, - "cannot use '@execution' on %kind0 because it has " - "a dynamically isolated parameter: %1", - (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(attr_execution_type_attr_incompatible_with_global_isolation,none, - "cannot use '@execution' because function type is " - "isolated to a global actor %0", - (Type)) +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(attr_execution_type_attr_incompatible_with_isolated_param,none, - "cannot use '@execution' together with an isolated parameter", - ()) +ERROR(execution_behavior_attr_incompatible_with_isolated_param,none, + "cannot use '%0' together with an isolated parameter", + (DeclAttribute)) -ERROR(attr_execution_type_attr_incompatible_with_isolated_any,none, - "cannot use '@execution' together with @isolated(any)", - ()) +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(execution_behavior_type_attr_incompatible_with_isolated_param,none, + "cannot use '@%0' together with an isolated parameter", + (StringRef)) + +ERROR(execution_behavior_type_attr_incompatible_with_isolated_any,none, + "cannot use '@%0' together with @isolated(any)", + (StringRef)) ERROR(invalid_function_conversion_with_non_sendable,none, "cannot convert %0 to %1 because crossing of an isolation boundary " diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 4b4b337fb08eb..a3323b1134649 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -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; } } @@ -8154,7 +8156,7 @@ class ClosureAttributeChecker 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 +8165,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,7 +8176,8 @@ 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(); } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index d1432534b11db..6f8a6b9312fb1 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -4198,7 +4198,8 @@ NeverNullType TypeResolver::resolveASTFunctionType( if (auto executionAttr = claim(attrs)) { if (!repr->isAsync()) { diagnoseInvalid(repr, executionAttr->getAtLoc(), - diag::attr_execution_type_attr_only_on_async); + diag::execution_behavior_type_attr_only_on_async, + executionAttr->getAttrName()); } switch (isolation.getKind()) { @@ -4208,20 +4209,22 @@ NeverNullType TypeResolver::resolveASTFunctionType( case FunctionTypeIsolation::Kind::GlobalActor: diagnoseInvalid( repr, executionAttr->getAtLoc(), - diag::attr_execution_type_attr_incompatible_with_global_isolation, - isolation.getGlobalActorType()); + diag::execution_behavior_type_attr_incompatible_with_global_isolation, + executionAttr->getAttrName(), isolation.getGlobalActorType()); break; case FunctionTypeIsolation::Kind::Parameter: diagnoseInvalid( repr, executionAttr->getAtLoc(), - diag::attr_execution_type_attr_incompatible_with_isolated_param); + diag::execution_behavior_type_attr_incompatible_with_isolated_param, + executionAttr->getAttrName()); break; case FunctionTypeIsolation::Kind::Erased: diagnoseInvalid( repr, executionAttr->getAtLoc(), - diag::attr_execution_type_attr_incompatible_with_isolated_any); + diag::execution_behavior_type_attr_incompatible_with_isolated_any, + executionAttr->getAttrName()); break; case FunctionTypeIsolation::Kind::NonIsolatedCaller: diff --git a/test/attr/attr_execution.swift b/test/attr/attr_execution.swift index 9ee107a382121..678d27da20687 100644 --- a/test/attr/attr_execution.swift +++ b/test/attr/attr_execution.swift @@ -17,33 +17,33 @@ do { } @execution(concurrent) func nonAsync1() {} -// expected-error@-1 {{cannot use '@execution' on non-async global function 'nonAsync1()'}} +// expected-error@-1 {{cannot use '@execution(concurrent)' on non-async global function 'nonAsync1()'}} @execution(caller) func nonAsync2() {} -// expected-error@-1 {{cannot use '@execution' on non-async global function 'nonAsync2()'}} +// expected-error@-1 {{cannot use '@execution(caller)' 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()'}} + // expected-error@-1 {{cannot use '@execution(concurrent)' 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()'}} + // expected-error@-1 {{cannot use '@execution(concurrent)' 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'}} + // expected-error@-1 {{cannot use '@execution(concurrent)' 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:)'}} + // expected-error@+1 {{cannot use '@execution(caller)' 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}} @@ -72,7 +72,7 @@ do { protocol P { @execution(caller) var syncP: Int { get } - // expected-error@-1 {{cannot use '@execution' on non-async property 'syncP'}} + // expected-error@-1 {{cannot use '@execution(caller)' on non-async property 'syncP'}} @execution(caller) var asyncP: Int { get async } } @@ -82,16 +82,16 @@ 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'}} + // expected-error@-1 {{cannot use '@execution(concurrent)' 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'}} + // expected-error@-1 {{cannot use '@execution(concurrent)' 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'}} + // expected-error@-1 {{cannot use '@execution(concurrent)' 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'}} + // expected-error@-1 {{cannot use '@execution(concurrent)' on subscript 'subscript(testIsolationAny:)' because it has a dynamically isolated parameter: 'arg'}} get async {} } @@ -102,7 +102,7 @@ struct TestAttributeCollisions { @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'}} + // expected-error@-1 {{cannot use '@execution(caller)' 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 @@ -129,13 +129,13 @@ _ = { @execution(concurrent) in // Ok } _ = { @MainActor @execution(concurrent) in - // expected-error@-1 {{cannot use '@execution' because function type is isolated to a global actor 'MainActor'}} + // expected-error@-1 {{cannot use '@execution(concurrent)' because function type is isolated to a global actor 'MainActor'}} } _ = { @execution(concurrent) () -> Int in - // expected-error@-1 {{'@execution' on non-async closure}} + // expected-error@-1 {{'@execution(concurrent)' on non-async closure}} } _ = { @execution(caller) (x: isolated (any Actor)?) in - // expected-error@-1 {{cannot use '@execution' together with an isolated parameter}} + // expected-error@-1 {{cannot use '@execution(caller)' together with an isolated parameter}} } From 2704ab73370fb8b09270d7d685d97be422bd0616 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 1 Apr 2025 16:51:57 -0700 Subject: [PATCH 02/14] [AST/ASTGen] Introduce `@concurrent` attribute to replace `@execution(concurrent)` spelling --- include/swift/AST/DeclAttr.def | 8 +++++- lib/AST/ASTDumper.cpp | 1 + lib/AST/Decl.cpp | 3 ++ lib/AST/FeatureSet.cpp | 3 ++ lib/ASTGen/Sources/ASTGen/DeclAttrs.swift | 2 ++ lib/Sema/ConstraintSystem.cpp | 6 ++-- lib/Sema/TypeCheckAttr.cpp | 35 ++++++++++++++++++++--- lib/Sema/TypeCheckConcurrency.cpp | 9 +++++- lib/Sema/TypeCheckDeclOverride.cpp | 1 + lib/Serialization/ModuleFormat.h | 2 +- 10 files changed, 61 insertions(+), 9 deletions(-) diff --git a/include/swift/AST/DeclAttr.def b/include/swift/AST/DeclAttr.def index 7e40507ef6072..05bf77f70e535 100644 --- a/include/swift/AST/DeclAttr.def +++ b/include/swift/AST/DeclAttr.def @@ -884,7 +884,13 @@ 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) +DECL_ATTR_FEATURE_REQUIREMENT(Concurrent, ExecutionAttribute) + +LAST_DECL_ATTR(Concurrent) #undef DECL_ATTR_ALIAS #undef CONTEXTUAL_DECL_ATTR_ALIAS diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 17ec755b21990..411b61a22c05d 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -4926,6 +4926,7 @@ 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 diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index ac9b1d0af9040..2160eae621f63 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -8758,6 +8758,9 @@ void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const { std::optional AbstractFunctionDecl::getExecutionBehavior() const { + if (getAttrs().hasAttribute()) + return ExecutionKind::Concurrent; + auto *attr = getAttrs().getAttribute(); if (!attr) return {}; diff --git a/lib/AST/FeatureSet.cpp b/lib/AST/FeatureSet.cpp index 2912d9eb5c292..894451e8028b9 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -510,6 +510,9 @@ static bool usesFeatureExecutionAttribute(Decl *decl) { if (decl->getAttrs().hasAttribute()) return true; + if (decl->getAttrs().hasAttribute()) + return true; + auto hasExecutionAttr = [](TypeRepr *R) { if (!R) return false; diff --git a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift index b409845e7ede3..06b15b1184a58 100644 --- a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift @@ -197,6 +197,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) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 1a6bb0ee54208..0978434dc7472 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -1414,8 +1414,10 @@ 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()) { + // `@execution(...)` and `@concurrent` attributes are only + // valid on asynchronous function types. + if (expr->getAttrs().hasAttribute() || + expr->getAttrs().hasAttribute()) { async = true; } diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index a3323b1134649..d1bbb1f1307ef 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); @@ -258,6 +258,22 @@ class AttributeChecker : public AttributeVisitor { } } + void visitExecutionAttr(ExecutionAttr *attr) { + checkExecutionBehaviorAttribute(attr); + + if (auto *concurrentAttr = D->getAttrs().getAttribute()) + diagnoseAndRemoveAttr(attr, diag::actor_isolation_multiple_attr_2, D, + attr, concurrentAttr); + } + + void visitConcurrentAttr(ConcurrentAttr *attr) { + checkExecutionBehaviorAttribute(attr); + + if (auto *executionAttr = D->getAttrs().getAttribute()) + diagnoseAndRemoveAttr(attr, diag::actor_isolation_multiple_attr_2, D, + attr, executionAttr); + } + void visitAlignmentAttr(AlignmentAttr *attr) { // Alignment must be a power of two. auto value = attr->getValue(); @@ -4316,6 +4332,7 @@ static void checkGlobalActorAttr( auto isolatedAttr = decl->getAttrs().getAttribute(); auto nonisolatedAttr = decl->getAttrs().getAttribute(); auto executionAttr = decl->getAttrs().getAttribute(); + auto concurrentAttr = decl->getAttrs().getAttribute(); llvm::SmallVector attributes; @@ -4330,7 +4347,9 @@ static void checkGlobalActorAttr( if (executionAttr) { attributes.push_back(executionAttr); } - + if (concurrentAttr) { + attributes.push_back(concurrentAttr); + } if (attributes.size() == 1) return; @@ -8145,13 +8164,13 @@ class ClosureAttributeChecker // Nothing else to check. } - void visitExecutionAttr(ExecutionAttr *attr) { + void checkExecutionBehaviorAttribute(DeclAttribute *attr) { if (!ctx.LangOpts.hasFeature(Feature::ExecutionAttribute)) { visitDeclAttribute(attr); return; } - // `@execution(...)` implies `async`. + // execution behavior attribute implies `async`. if (closure->hasExplicitResultType() && closure->getAsyncLoc().isInvalid()) { ctx.Diags @@ -8184,6 +8203,14 @@ class ClosureAttributeChecker } } + void visitExecutionAttr(ExecutionAttr *attr) { + checkExecutionBehaviorAttribute(attr); + } + + 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..9f47dc1377d97 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4890,6 +4890,7 @@ getIsolationFromAttributes(const Decl *decl, bool shouldDiagnose = true, 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) { @@ -4901,11 +4902,14 @@ getIsolationFromAttributes(const Decl *decl, bool shouldDiagnose = true, 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) + (concurrentExecutionAttr ? 1 : 0) + + (concurrentAttr ? 1 : 0); if (numIsolationAttrs == 0) { if (isa(decl) && !decl->isImplicit()) { return ActorIsolation::forNonisolated(false); @@ -4930,6 +4934,9 @@ getIsolationFromAttributes(const Decl *decl, bool shouldDiagnose = true, } } + if (concurrentAttr) + return ActorIsolation::forNonisolated(/*is unsafe*/ false); + // If the declaration is explicitly marked 'nonisolated', report it as // independent. if (nonisolatedAttr) { diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index 7218b3c0aee9f..c61e59e6f8478 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1588,6 +1588,7 @@ namespace { UNINTERESTING_ATTR(Borrowed) UNINTERESTING_ATTR(Borrowing) UNINTERESTING_ATTR(CDecl) + UNINTERESTING_ATTR(Concurrent) UNINTERESTING_ATTR(Consuming) UNINTERESTING_ATTR(Documentation) UNINTERESTING_ATTR(Dynamic) diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index eac43d54380bd..d180768509df4 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 = 939; // @concurrent attribute /// A standard hash seed used for all string hashes in a serialized module. /// From e3cbdaa8631bd6c426488387e214d82746be2c3d Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 1 Apr 2025 16:53:51 -0700 Subject: [PATCH 03/14] [Parse] Remove warning about `@concurrent` being alternative to `@Sendable` --- lib/Parse/ParseDecl.cpp | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index f778dea293b23..fef78ce1aeb84 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -4246,10 +4246,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 +4599,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) { From 318c4150f3500969d83e2bce101b7c229d54aa0b Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 1 Apr 2025 17:57:13 -0700 Subject: [PATCH 04/14] [AST/Sema] Support for `@concurrent` attribute in type context --- include/swift/AST/TypeAttr.def | 1 + lib/ASTGen/Sources/ASTGen/TypeAttrs.swift | 1 + lib/Sema/TypeCheckType.cpp | 26 +++++++++++++++-------- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/include/swift/AST/TypeAttr.def b/include/swift/AST/TypeAttr.def index 811e85a08d865..e1b0320f1b1ee 100644 --- a/include/swift/AST/TypeAttr.def +++ b/include/swift/AST/TypeAttr.def @@ -68,6 +68,7 @@ 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/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift b/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift index 0aea4fe145ca4..708e8765f0fbf 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, diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 6f8a6b9312fb1..9f330a5d323ba 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -4195,11 +4195,11 @@ NeverNullType TypeResolver::resolveASTFunctionType( } } - if (auto executionAttr = claim(attrs)) { + auto checkExecutionBehaviorAttribute = [&](TypeAttribute *attr) { if (!repr->isAsync()) { - diagnoseInvalid(repr, executionAttr->getAtLoc(), + diagnoseInvalid(repr, attr->getAttrLoc(), diag::execution_behavior_type_attr_only_on_async, - executionAttr->getAttrName()); + attr->getAttrName()); } switch (isolation.getKind()) { @@ -4208,29 +4208,33 @@ NeverNullType TypeResolver::resolveASTFunctionType( case FunctionTypeIsolation::Kind::GlobalActor: diagnoseInvalid( - repr, executionAttr->getAtLoc(), + repr, attr->getAttrLoc(), diag::execution_behavior_type_attr_incompatible_with_global_isolation, - executionAttr->getAttrName(), isolation.getGlobalActorType()); + attr->getAttrName(), isolation.getGlobalActorType()); break; case FunctionTypeIsolation::Kind::Parameter: diagnoseInvalid( - repr, executionAttr->getAtLoc(), + repr, attr->getAttrLoc(), diag::execution_behavior_type_attr_incompatible_with_isolated_param, - executionAttr->getAttrName()); + attr->getAttrName()); break; case FunctionTypeIsolation::Kind::Erased: diagnoseInvalid( - repr, executionAttr->getAtLoc(), + repr, attr->getAttrLoc(), diag::execution_behavior_type_attr_incompatible_with_isolated_any, - executionAttr->getAttrName()); + attr->getAttrName()); break; case FunctionTypeIsolation::Kind::NonIsolatedCaller: llvm_unreachable("cannot happen because multiple @execution attributes " "aren't allowed."); } + }; + + if (auto executionAttr = claim(attrs)) { + checkExecutionBehaviorAttribute(executionAttr); if (!repr->isInvalid()) { switch (executionAttr->getBehavior()) { @@ -4242,6 +4246,10 @@ NeverNullType TypeResolver::resolveASTFunctionType( break; } } + } else if (auto concurrentAttr = claim(attrs)) { + checkExecutionBehaviorAttribute(concurrentAttr); + if (!repr->isInvalid()) + isolation = FunctionTypeIsolation::forNonIsolated(); } else { if (ctx.LangOpts.getFeatureState(Feature::AsyncCallerExecution) .isEnabledForAdoption()) { From 4b8c8e7d72bb4a0ff8c65f8260fc1c06ffcc8fa4 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 2 Apr 2025 15:31:03 -0700 Subject: [PATCH 05/14] [AST/Sema] Replace `@execution(concurrent)` with `@concurrent` --- include/swift/AST/ASTBridging.h | 2 - include/swift/AST/AttrKind.h | 3 +- lib/AST/ASTDumper.cpp | 2 - lib/AST/Attr.cpp | 8 -- lib/AST/Bridging/DeclAttributeBridging.cpp | 2 - lib/AST/Bridging/TypeAttributeBridging.cpp | 2 - lib/AST/Decl.cpp | 3 - lib/ASTGen/Sources/ASTGen/DeclAttrs.swift | 1 - lib/ASTGen/Sources/ASTGen/TypeAttrs.swift | 1 - lib/Parse/ParseDecl.cpp | 8 +- lib/SIL/IR/SILFunctionType.cpp | 18 +-- lib/Sema/AsyncCallerExecutionMigration.cpp | 11 +- lib/Sema/CSGen.cpp | 6 +- lib/Sema/TypeCheckConcurrency.cpp | 2 - lib/Sema/TypeCheckType.cpp | 3 - test/ASTGen/attrs.swift | 6 +- .../nonisolated_inherits_isolation.swift | 2 +- .../attr_execution/adoption_mode.swift | 116 +++++++++--------- .../attr_execution/attr_execution.swift | 2 +- .../attr_execution/conversions.swift | 24 ++-- .../attr_execution/conversions_silgen.swift | 46 +++---- test/ModuleInterface/attrs.swift | 4 +- test/ModuleInterface/execution_attr.swift | 4 +- test/Parse/execution.swift | 22 ++-- test/SILGen/execution_attr.swift | 4 +- .../Inputs/caller_inheriting_isolation.swift | 8 +- test/attr/attr_abi.swift | 16 +-- test/attr/attr_execution.swift | 74 +++++------ 28 files changed, 187 insertions(+), 213 deletions(-) diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index f3b7220761f56..789653479382a 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -911,7 +911,6 @@ SWIFT_NAME("BridgedAvailableAttr.setIsGroupTerminator(self:)") void BridgedAvailableAttr_setIsGroupTerminator(BridgedAvailableAttr cAttr); enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedExecutionKind { - BridgedExecutionKindConcurrent, BridgedExecutionKindCaller, }; @@ -2591,7 +2590,6 @@ BridgedConventionTypeAttr BridgedConventionTypeAttr_createParsed( BridgedStringRef cClangType, BridgedSourceLoc cClangTypeLoc); enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedExecutionTypeAttrExecutionKind { - BridgedExecutionTypeAttrExecutionKind_Concurrent, BridgedExecutionTypeAttrExecutionKind_Caller }; diff --git a/include/swift/AST/AttrKind.h b/include/swift/AST/AttrKind.h index d56edbc4b6e31..7f7e372f643b3 100644 --- a/include/swift/AST/AttrKind.h +++ b/include/swift/AST/AttrKind.h @@ -131,8 +131,7 @@ enum : unsigned { NumExternKindBits = countBitsUsed(static_cast(ExternKind::Last_ExternKind)) }; enum class ExecutionKind : uint8_t { - Concurrent = 0, - Caller, + Caller = 0, Last_ExecutionKind = Caller }; diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 411b61a22c05d..1aa64459a7767 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -620,8 +620,6 @@ static StringRef getDumpString(FunctionRefInfo::ApplyLevel applyLevel) { } static StringRef getDumpString(ExecutionKind kind) { switch (kind) { - case ExecutionKind::Concurrent: - return "concurrent"; case ExecutionKind::Caller: return "caller"; } diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 61b992437d66c..7274a728a622e 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -313,9 +313,6 @@ void ExecutionTypeAttr::printImpl(ASTPrinter &printer, printer.printAttrName("@execution"); printer << "("; switch (getBehavior()) { - case ExecutionKind::Concurrent: - printer << "concurrent"; - break; case ExecutionKind::Caller: printer << "caller"; break; @@ -1725,9 +1722,6 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, case DeclAttrKind::Execution: { auto *attr = cast(this); switch (attr->getBehavior()) { - case ExecutionKind::Concurrent: - Printer << "@execution(concurrent)"; - break; case ExecutionKind::Caller: Printer << "@execution(caller)"; break; @@ -1958,8 +1952,6 @@ StringRef DeclAttribute::getAttrName() const { return "lifetime"; case DeclAttrKind::Execution: { switch (cast(this)->getBehavior()) { - case ExecutionKind::Concurrent: - return "execution(concurrent)"; case ExecutionKind::Caller: return "execution(caller)"; } diff --git a/lib/AST/Bridging/DeclAttributeBridging.cpp b/lib/AST/Bridging/DeclAttributeBridging.cpp index 1cb1165bf470b..cad38eeaecb69 100644 --- a/lib/AST/Bridging/DeclAttributeBridging.cpp +++ b/lib/AST/Bridging/DeclAttributeBridging.cpp @@ -889,8 +889,6 @@ BridgedUnavailableFromAsyncAttr BridgedUnavailableFromAsyncAttr_createParsed( static ExecutionKind unbridged(BridgedExecutionKind kind) { switch (kind) { - case BridgedExecutionKindConcurrent: - return ExecutionKind::Concurrent; case BridgedExecutionKindCaller: return ExecutionKind::Caller; } diff --git a/lib/AST/Bridging/TypeAttributeBridging.cpp b/lib/AST/Bridging/TypeAttributeBridging.cpp index 8f8e92537ea30..70d093b96dddb 100644 --- a/lib/AST/Bridging/TypeAttributeBridging.cpp +++ b/lib/AST/Bridging/TypeAttributeBridging.cpp @@ -94,8 +94,6 @@ BridgedExecutionTypeAttr BridgedExecutionTypeAttr_createParsed( BridgedSourceLoc cBehaviorLoc) { auto behaviorKind = [=] { switch (behavior) { - case BridgedExecutionTypeAttrExecutionKind_Concurrent: - return ExecutionKind::Concurrent; case BridgedExecutionTypeAttrExecutionKind_Caller: return ExecutionKind::Caller; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 2160eae621f63..ac9b1d0af9040 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -8758,9 +8758,6 @@ void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const { std::optional AbstractFunctionDecl::getExecutionBehavior() const { - if (getAttrs().hasAttribute()) - return ExecutionKind::Concurrent; - auto *attr = getAttrs().getAttribute(); if (!attr) return {}; diff --git a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift index 06b15b1184a58..059283f9e91e5 100644 --- a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift @@ -371,7 +371,6 @@ extension ASTGenVisitor { attribute: node, { switch $0.rawText { - case "concurrent": return .concurrent case "caller": return .caller default: return nil } diff --git a/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift b/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift index 708e8765f0fbf..e54b9e14178a3 100644 --- a/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift @@ -247,7 +247,6 @@ extension ASTGenVisitor { attribute: node, { switch $0.rawText { - case "concurrent": return .concurrent case "caller": return .caller default: // TODO: Diagnose. diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index fef78ce1aeb84..4a1ed0c93ecb2 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3950,8 +3950,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, case DeclAttrKind::Execution: { auto behavior = parseSingleAttrOption( *this, Loc, AttrRange, AttrName, DK, - {{Context.Id_concurrent, ExecutionKind::Concurrent}, - {Context.Id_caller, ExecutionKind::Caller}}); + {{Context.Id_caller, ExecutionKind::Caller}}); if (!behavior) return makeParserSuccess(); @@ -4766,10 +4765,7 @@ ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result, bool invalid = false; std::optional behavior; - if (isIdentifier(Tok, "concurrent")) { - behaviorLoc = consumeToken(tok::identifier); - behavior = ExecutionKind::Concurrent; - } else if (isIdentifier(Tok, "caller")) { + if (isIdentifier(Tok, "caller")) { behaviorLoc = consumeToken(tok::identifier); behavior = ExecutionKind::Caller; } else { diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 7721209473c18..81a36ba26ea41 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -2624,15 +2624,17 @@ static CanSILFunctionType getSILFunctionType( if (constant) { 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 behavior = decl->getExecutionBehavior()) { + switch (behavior.value()) { + case ExecutionKind::Caller: + actorIsolation = ActorIsolation::forCallerIsolationInheriting(); + break; + } + } + + if (decl->getAttrs().hasAttribute()) { actorIsolation = ActorIsolation::forNonisolated(false /*unsafe*/); - break; - case ExecutionKind::Caller: - actorIsolation = ActorIsolation::forCallerIsolationInheriting(); - break; } } else { actorIsolation = diff --git a/lib/Sema/AsyncCallerExecutionMigration.cpp b/lib/Sema/AsyncCallerExecutionMigration.cpp index 5385d386cfd93..f2f69aaa5e98b 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,7 +121,8 @@ void AsyncCallerExecutionMigrationTarget::diagnose() const { attrs = &closure->getAttrs(); } - if (attrs && attrs->hasAttribute()) { + if (attrs && (attrs->hasAttribute() || + attrs->hasAttribute())) { return; } } @@ -142,7 +143,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/CSGen.cpp b/lib/Sema/CSGen.cpp index d72f5621a505e..439a7cba3f140 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2589,11 +2589,13 @@ namespace { 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(); }(); extInfo = extInfo.withIsolation(isolation); diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 9f47dc1377d97..1e285616a685b 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4927,8 +4927,6 @@ getIsolationFromAttributes(const Decl *decl, bool shouldDiagnose = true, // 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(); } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 9f330a5d323ba..972d36cd7e2fc 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -4238,9 +4238,6 @@ NeverNullType TypeResolver::resolveASTFunctionType( if (!repr->isInvalid()) { switch (executionAttr->getBehavior()) { - case ExecutionKind::Concurrent: - isolation = FunctionTypeIsolation::forNonIsolated(); - break; case ExecutionKind::Caller: isolation = FunctionTypeIsolation::forNonIsolatedCaller(); break; diff --git a/test/ASTGen/attrs.swift b/test/ASTGen/attrs.swift index 307dd7770c3b1..9a8eda233be64 100644 --- a/test/ASTGen/attrs.swift +++ b/test/ASTGen/attrs.swift @@ -195,19 +195,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 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..c4c40b3ce099a 100644 --- a/test/Concurrency/Runtime/nonisolated_inherits_isolation.swift +++ b/test/Concurrency/Runtime/nonisolated_inherits_isolation.swift @@ -40,7 +40,7 @@ func executionCallerIsolation() async { } // 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..82e34468a416e 100644 --- a/test/Concurrency/attr_execution/adoption_mode.swift +++ b/test/Concurrency/attr_execution/adoption_mode.swift @@ -8,62 +8,62 @@ struct G { init(_: T) {} } -@execution(concurrent) func globalAsyncF() async {} +@concurrent func globalAsyncF() async {} // MARK: Functions do { func syncF() {} - @execution(concurrent) func executionConcurrentAsyncF() async {} + @concurrent func executionConcurrentAsyncF() async {} @execution(caller) 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 +76,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 +96,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 +113,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 +135,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 +147,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 +160,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 +184,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 +196,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 +209,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 +223,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..e09c9b9fcae47 100644 --- a/test/Concurrency/attr_execution/attr_execution.swift +++ b/test/Concurrency/attr_execution/attr_execution.swift @@ -7,7 +7,7 @@ // CHECK-LABEL: // concurrentTest() // CHECK: // Isolation: nonisolated // CHECK: sil hidden [ossa] @$s14attr_execution14concurrentTestyyYaF : $@convention(thin) @async () -> () { -@execution(concurrent) +@concurrent func concurrentTest() async {} // CHECK-LABEL: // callerTest() diff --git a/test/Concurrency/attr_execution/conversions.swift b/test/Concurrency/attr_execution/conversions.swift index 3113724468061..7e7b7eaeb247c 100644 --- a/test/Concurrency/attr_execution/conversions.swift +++ b/test/Concurrency/attr_execution/conversions.swift @@ -8,7 +8,7 @@ actor MyActor { static let shared = MyActor() } -@execution(concurrent) +@concurrent func concurrentTest() async { } @@ -20,7 +20,7 @@ func callerTest() async { func actorIsolated() async {} let _: @execution(caller) () async -> Void = concurrentTest // Ok -let _: @execution(concurrent) () async -> Void = callerTest // Ok +let _: @concurrent () async -> Void = callerTest // Ok let _: @MainActor () async -> Void = concurrentTest // Ok let _: @MainActor () async -> Void = callerTest // Ok @@ -30,10 +30,10 @@ let _: @isolated(any) () async -> Void = callerTest // expected-error@-1 {{cannot convert value of type '@execution(caller) () async -> ()' to specified type '@isolated(any) () async -> Void'}} let _: @execution(caller) () async -> Void = actorIsolated // Ok -let _: @execution(concurrent) () 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 _: @concurrent () async -> Void = fn // Ok let _: @execution(caller) () async -> Void = fn // Ok } @@ -47,7 +47,7 @@ func testUpcast(arr: [@execution(caller) () async -> Void]) { 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 + 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 @@ -97,7 +97,7 @@ do { } 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'}} } @@ -117,9 +117,9 @@ 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, + nonIsolated4: @escaping @Sendable @concurrent () async -> NonSendable, caller1: @escaping @Sendable @execution(caller) (NonSendable) async -> Void, caller2: @escaping @Sendable @execution(caller) () async -> NonSendable ) { @@ -141,15 +141,15 @@ func testNonSendableDiagnostics( 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 _: @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}} + let _: @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}} + let _: @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 _: @MainActor (NonSendable) async -> Void = nonIsolated1 // Ok diff --git a/test/Concurrency/attr_execution/conversions_silgen.swift b/test/Concurrency/attr_execution/conversions_silgen.swift index 4ed0ec15f1379..579fc46be08d4 100644 --- a/test/Concurrency/attr_execution/conversions_silgen.swift +++ b/test/Concurrency/attr_execution/conversions_silgen.swift @@ -15,7 +15,7 @@ @execution(caller) func globalCallerFunc() async -> () {} -@execution(concurrent) +@concurrent func globalConcurrentFunc() async -> () {} class NonSendableKlass { @@ -28,13 +28,13 @@ class SendableKlass : @unchecked Sendable { @execution(caller) func globalCallerFuncSendableKlass(_ x: SendableKlass) async -> () {} -@execution(concurrent) +@concurrent func globalConcurrentFuncSendableKlass(_ x: SendableKlass) async -> () {} @execution(caller) func globalCallerFuncSendableKlass(_ x: SendableKlass) async -> SendableKlass { fatalError() } -@execution(concurrent) +@concurrent func globalConcurrentFuncSendableKlass(_ x: SendableKlass) async -> SendableKlass { fatalError() } @@ -49,7 +49,7 @@ func globalConcurrentFuncSendableKlass(_ x: SendableKlass) async -> SendableKlas // 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 + let y: @concurrent () async -> () = x await y() } @@ -70,7 +70,7 @@ public func testCallerToConcurrentNonIsolated(_ x: @escaping @execution(caller) // CHECK: } // end sil function '$s21attr_execution_silgen31testCallerToConcurrentMainActoryyyyYaYCcYaF' @MainActor public func testCallerToConcurrentMainActor(_ x: @escaping @execution(caller) () async -> ()) async { - let y: @execution(concurrent) () async -> () = x + let y: @concurrent () async -> () = x await y() } @@ -80,7 +80,7 @@ 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 { +public func testConcurrentToCallerNonIsolated(_ x: @escaping @concurrent () async -> ()) async { let y: @execution(caller) () async -> () = x await y() } @@ -100,7 +100,7 @@ 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 { +public func testConcurrentToCallerNonIsolatedMainActor(_ x: @escaping @concurrent () async -> ()) async { let y: @execution(caller) () async -> () = x await y() } @@ -124,10 +124,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() } @@ -179,9 +179,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() } @@ -197,7 +197,7 @@ public func testConcurrentLocalVariables(_ x: @escaping @execution(concurrent) ( // 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 y: @concurrent () async -> () = x let y2: @execution(caller) () async -> () = y await y2() } @@ -213,9 +213,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 { +public func testConcurrentCallerLocalVariables(_ x: @escaping @concurrent () async -> ()) async { let y: @execution(caller) () async -> () = x - let y2: @execution(concurrent) () async -> () = y + let y2: @concurrent () async -> () = y await y2() } @@ -261,7 +261,7 @@ 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 -> (), +func globalActorConversions(_ x: @escaping @concurrent () async -> (), _ y: @escaping @execution(caller) () async -> ()) async { let v1: @MainActor () async -> Void = globalCallerFunc await v1() @@ -320,7 +320,7 @@ 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 -> (), +func globalActorConversions2(_ x: @escaping @concurrent (SendableKlass) async -> (), _ y: @escaping @execution(caller) (SendableKlass) async -> ()) async { let v1: @MainActor (SendableKlass) async -> Void = globalCallerFuncSendableKlass await v1(SendableKlass()) @@ -332,7 +332,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,7 +381,7 @@ 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, +func globalActorConversions3(_ x: @escaping @concurrent (SendableKlass) async -> SendableKlass, _ y: @escaping @execution(caller) (SendableKlass) async -> SendableKlass) async { let v1: @MainActor (SendableKlass) async -> SendableKlass = globalCallerFuncSendableKlass _ = await v1(SendableKlass()) @@ -393,7 +393,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()) } @@ -423,6 +423,6 @@ func conversionsFromSyncToAsync(_ x: @escaping @Sendable (NonSendableKlass) -> V _ 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 _: @concurrent (SendableKlass) async -> Void = y + let _: @concurrent (NonSendableKlass) async -> Void = z } diff --git a/test/ModuleInterface/attrs.swift b/test/ModuleInterface/attrs.swift index 022ac15ff4a26..251b28751baab 100644 --- a/test/ModuleInterface/attrs.swift +++ b/test/ModuleInterface/attrs.swift @@ -87,9 +87,9 @@ 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) public func testExecutionCaller() async {} diff --git a/test/ModuleInterface/execution_attr.swift b/test/ModuleInterface/execution_attr.swift index d3b2e4ada0a76..cbfb735588a9e 100644 --- a/test/ModuleInterface/execution_attr.swift +++ b/test/ModuleInterface/execution_attr.swift @@ -16,11 +16,11 @@ public struct Test { } // CHECK: #if compiler(>=5.3) && $ExecutionAttribute - // CHECK-NEXT: @execution(concurrent) public func test() async + // CHECK-NEXT: @concurrent public func test() async // CHECK-NEXT: #else // CHECK-NEXT: public func test() async // CHECK-NEXT: #endif - @execution(concurrent) + @concurrent public func test() async { } diff --git a/test/Parse/execution.swift b/test/Parse/execution.swift index 18d5a9e51ea00..2b0980da15332 100644 --- a/test/Parse/execution.swift +++ b/test/Parse/execution.swift @@ -3,28 +3,28 @@ // REQUIRES: concurrency // REQUIRES: swift_feature_ExecutionAttribute -typealias F = @execution(concurrent) () async -> Void +typealias F = @concurrent () async -> Void -typealias E = @execution(concurrent) () -> Void -// expected-error@-1 {{cannot use '@execution' on non-async function type}} +typealias E = @concurrent () -> Void +// expected-error@-1 {{cannot use '@concurrent' on non-async function type}} func test1(_: @execution(caller) (Int...) async -> Void) {} -func test2(_: @execution(concurrent) (Int...) async -> Void) {} +func test2(_: @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_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(_: @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_concurrent(_: @concurrent @isolated(any) () async -> Void) {} +// expected-error@-1 {{cannot use '@concurrent' 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_concurrent(_: @concurrent (isolated (any Actor)?) async -> Void) {} +// expected-error@-1 {{cannot use '@concurrent' 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}} @@ -46,7 +46,7 @@ func test_err7(_: @execution(hello () async -> Void) {} // 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}} +func test_err8(_: @concurrent Int) {} // expected-error {{attribute does not apply to type}} do { let _ = [@execution(caller) () async -> Void]() diff --git a/test/SILGen/execution_attr.swift b/test/SILGen/execution_attr.swift index a5682dede74ae..a5681cd97bac1 100644 --- a/test/SILGen/execution_attr.swift +++ b/test/SILGen/execution_attr.swift @@ -17,7 +17,7 @@ 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) -> ()) -> () { @@ -29,7 +29,7 @@ func executionCallerParameter(_ x: @execution(caller) () async -> ()) async { // 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() } diff --git a/test/Serialization/Inputs/caller_inheriting_isolation.swift b/test/Serialization/Inputs/caller_inheriting_isolation.swift index cd2bd31fc9235..980afa340f8ae 100644 --- a/test/Serialization/Inputs/caller_inheriting_isolation.swift +++ b/test/Serialization/Inputs/caller_inheriting_isolation.swift @@ -6,7 +6,7 @@ public func unspecifiedAsync(_ t: T) async { public func unspecifiedAsyncCaller(_ t: T) async { } -@execution(concurrent) +@concurrent public func unspecifiedAsyncConcurrent(_ t: T) async { } @@ -17,7 +17,7 @@ nonisolated public func nonisolatedAsync(_ t: T) async { nonisolated public func nonisolatedAsyncCaller(_ t: T) async { } -@execution(concurrent) +@concurrent nonisolated public func nonisolatedAsyncConcurrent(_ t: T) async { } @@ -30,7 +30,7 @@ public struct S { public func unspecifiedAsyncCaller(_ t: T) async { } - @execution(concurrent) + @concurrent public func unspecifiedAsyncConcurrent(_ t: T) async { } @@ -41,7 +41,7 @@ public struct S { nonisolated public func nonisolatedAsyncCaller(_ t: T) async { } - @execution(concurrent) + @concurrent nonisolated public func nonisolatedAsyncConcurrent(_ t: T) async { } } diff --git a/test/attr/attr_abi.swift b/test/attr/attr_abi.swift index 1409d75bf0fdf..04ecbbacff0a2 100644 --- a/test/attr/attr_abi.swift +++ b/test/attr/attr_abi.swift @@ -1232,19 +1232,19 @@ 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) @@ -1263,9 +1263,9 @@ func isolation15() async {} nonisolated func isolation17() async {} @abi(@execution(caller) func isolation18() async) -@execution(concurrent) func isolation18() async {} +@concurrent func isolation18() async {} -@abi(@execution(concurrent) func isolation19() async) +@abi(@concurrent func isolation19() async) @execution(caller) func isolation19() async {} // NSCopying - see attr/attr_abi_objc.swift diff --git a/test/attr/attr_execution.swift b/test/attr/attr_execution.swift index 678d27da20687..e9dc8aa4625cd 100644 --- a/test/attr/attr_execution.swift +++ b/test/attr/attr_execution.swift @@ -5,8 +5,8 @@ @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}} +@concurrent @execution(caller) func mutipleAttrs() async {} +// expected-error@-1 {{global function 'mutipleAttrs()' has multiple actor-isolation attributes (@execution(caller) and @concurrent)}} do { @execution(caller) struct S {} @@ -16,39 +16,39 @@ do { // expected-error@-1 {{'@execution(caller)' attribute cannot be applied to this declaration}} } -@execution(concurrent) func nonAsync1() {} -// expected-error@-1 {{cannot use '@execution(concurrent)' on non-async global function 'nonAsync1()'}} +@concurrent func nonAsync1() {} +// expected-error@-1 {{cannot use '@concurrent' on non-async global function 'nonAsync1()'}} @execution(caller) func nonAsync2() {} // expected-error@-1 {{cannot use '@execution(caller)' on non-async global function 'nonAsync2()'}} -@execution(concurrent) func testGlobal() async {} // Ok +@concurrent func testGlobal() async {} // Ok struct Test { - @execution(concurrent) init() {} - // expected-error@-1 {{cannot use '@execution(concurrent)' on non-async initializer 'init()'}} + @concurrent init() {} + // expected-error@-1 {{cannot use '@concurrent' on non-async initializer 'init()'}} - @execution(concurrent) init(async: Void) async {} + @concurrent init(async: Void) async {} - @execution(concurrent) func member() {} - // expected-error@-1 {{cannot use '@execution(concurrent)' on non-async instance method 'member()'}} + @concurrent func member() {} + // expected-error@-1 {{cannot use '@concurrent' on non-async instance method 'member()'}} - @execution(concurrent) func member() async {} // Ok + @concurrent func member() async {} // Ok - @execution(concurrent) var syncP: Int { - // expected-error@-1 {{cannot use '@execution(concurrent)' on non-async property 'syncP'}} + @concurrent var syncP: Int { + // expected-error@-1 {{cannot use '@concurrent' on non-async property 'syncP'}} get {} } - @execution(concurrent) var asyncP: Int { + @concurrent var asyncP: Int { get async {} } // expected-error@+1 {{cannot use '@execution(caller)' 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}} + @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}} } @execution(caller) subscript(async _: Int) -> Bool { get async {} @@ -79,24 +79,24 @@ do { } struct TestAttributeCollisions { - @execution(concurrent) nonisolated func testNonIsolated() async {} + @concurrent nonisolated func testNonIsolated() async {} - @execution(concurrent) func test(arg: isolated MainActor) async {} - // expected-error@-1 {{cannot use '@execution(concurrent)' 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(concurrent)' on subscript 'subscript(test:)' because it has an isolated parameter: 'arg'}} + @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 {} } - @execution(concurrent) func testIsolationAny(arg: @isolated(any) () -> Void) async {} - // expected-error@-1 {{cannot use '@execution(concurrent)' 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(concurrent)' on subscript 'subscript(testIsolationAny:)' because it has a dynamically isolated parameter: 'arg'}} + @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 @execution(concurrent) func testGlobalActor() async {} - // expected-warning @-1 {{instance method 'testGlobalActor()' has multiple actor-isolation attributes (@MainActor and @execution(concurrent))}} + @MainActor @concurrent func testGlobalActor() async {} + // expected-warning @-1 {{instance method 'testGlobalActor()' has multiple actor-isolation attributes (@MainActor and @concurrent)}} @execution(caller) nonisolated func testNonIsolatedCaller() async {} // Ok @MainActor @execution(caller) func testGlobalActorCaller() async {} @@ -104,7 +104,7 @@ struct TestAttributeCollisions { @execution(caller) func testCaller(arg: isolated MainActor) async {} // expected-error@-1 {{cannot use '@execution(caller)' on instance method 'testCaller(arg:)' because it has an isolated parameter: 'arg'}} - @execution(concurrent) @Sendable func test(_: @Sendable () -> Void, _: sending Int) async {} // Ok + @concurrent @Sendable func test(_: @Sendable () -> Void, _: sending Int) async {} // Ok @execution(caller) @Sendable func testWithSendableCaller(_: @Sendable () -> Void, _: sending Int) async {} // Ok } @@ -114,26 +114,26 @@ protocol P { } struct InfersMainActor : P { - @execution(concurrent) func test() async {} + @concurrent func test() async {} } @MainActor struct IsolatedType { - @execution(concurrent) func test() async {} + @concurrent func test() async {} } _ = { @execution(caller) in // Ok } -_ = { @execution(concurrent) in // Ok +_ = { @concurrent in // Ok } -_ = { @MainActor @execution(concurrent) in - // expected-error@-1 {{cannot use '@execution(concurrent)' because function type is isolated to a global actor 'MainActor'}} +_ = { @MainActor @concurrent in + // expected-error@-1 {{cannot use '@concurrent' because function type is isolated to a global actor 'MainActor'}} } -_ = { @execution(concurrent) () -> Int in - // expected-error@-1 {{'@execution(concurrent)' on non-async closure}} +_ = { @concurrent () -> Int in + // expected-error@-1 {{'@concurrent' on non-async closure}} } _ = { @execution(caller) (x: isolated (any Actor)?) in From b1ffa063b684036532ecdc2ad38560314e0e9e49 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 4 Apr 2025 09:20:08 -0700 Subject: [PATCH 06/14] [AST/Sema] Intoduce `nonisolated(nonsending)` as a replacement for `@execution(caller)` --- include/swift/AST/ASTBridging.h | 11 +- include/swift/AST/Attr.h | 29 +++-- include/swift/AST/AttrKind.h | 12 ++ include/swift/AST/DiagnosticsSema.def | 17 ++- include/swift/AST/KnownIdentifiers.def | 1 + lib/AST/ASTDumper.cpp | 3 + lib/AST/Attr.cpp | 20 ++- lib/AST/Bridging/DeclAttributeBridging.cpp | 18 ++- lib/AST/Decl.cpp | 5 + lib/ASTGen/Sources/ASTGen/DeclAttrs.swift | 26 ++-- lib/Parse/ParseDecl.cpp | 20 +-- lib/SIL/IR/SILFunctionType.cpp | 14 +- lib/Sema/AsyncCallerExecutionMigration.cpp | 12 +- lib/Sema/TypeCheckAttr.cpp | 19 +++ lib/Sema/TypeCheckConcurrency.cpp | 8 +- lib/Serialization/Deserialization.cpp | 7 +- lib/Serialization/ModuleFormat.h | 4 +- lib/Serialization/Serialization.cpp | 6 +- test/attr/attr_execution.swift | 141 --------------------- test/attr/execution_behavior_attrs.swift | 140 ++++++++++++++++++++ 20 files changed, 310 insertions(+), 203 deletions(-) delete mode 100644 test/attr/attr_execution.swift create mode 100644 test/attr/execution_behavior_attrs.swift diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 789653479382a..f962df542cffb 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -1234,11 +1234,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 diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index fb8afc911a3b6..7c97070c6b8bd 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, @@ -2978,17 +2978,26 @@ 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); } NonisolatedAttr(bool unsafe, bool implicit) - : NonisolatedAttr({}, {}, unsafe, implicit) {} + : NonisolatedAttr({}, {}, + unsafe ? NonIsolatedModifier::Unsafe + : NonIsolatedModifier::None, + implicit) {} - bool isUnsafe() const { return Bits.NonisolatedAttr.isUnsafe; } + NonIsolatedModifier getModifier() const { + return static_cast(Bits.NonisolatedAttr.Modifier); + } + + bool isUnsafe() const { return getModifier() == NonIsolatedModifier::Unsafe; } + bool isNonSending() const { + return getModifier() == NonIsolatedModifier::NonSending; + } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DeclAttrKind::Nonisolated; @@ -2996,11 +3005,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(); } }; diff --git a/include/swift/AST/AttrKind.h b/include/swift/AST/AttrKind.h index 7f7e372f643b3..320c8ea03ff67 100644 --- a/include/swift/AST/AttrKind.h +++ b/include/swift/AST/AttrKind.h @@ -138,6 +138,18 @@ enum class ExecutionKind : uint8_t { enum : unsigned { NumExecutionKindBits = countBitsUsed(static_cast(ExecutionKind::Last_ExecutionKind)) }; +enum class NonIsolatedModifier : uint8_t { + None = 0, + Unsafe, + NonSending, + Last_NonIsolatedModifier = NonSending +}; + +enum : unsigned { + NumNonIsolatedModifierBits = countBitsUsed( + static_cast(NonIsolatedModifier::Last_NonIsolatedModifier)) +}; + enum class DeclAttrKind : unsigned { #define DECL_ATTR(_, CLASS, ...) CLASS, #define LAST_DECL_ATTR(CLASS) Last_DeclAttr = CLASS, diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 187de7a9e16e9..0927b9a7c37d5 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8554,11 +8554,16 @@ GROUPED_ERROR(isolated_conformance_wrong_domain,IsolatedConformances,none, //===----------------------------------------------------------------------===// ERROR(execution_behavior_only_on_async,none, - "cannot use '%0' on non-async %kind1", + "cannot use %0 on non-async %kind1", (DeclAttribute, ValueDecl *)) +ERROR(cannot_specify_execution_behavior_for_decl,none, + "%0 is only applicable to asynchronous functions, " + "initializers, subscripts and computed properties", + (DeclAttribute)) + ERROR(execution_behavior_only_on_async_closure,none, - "cannot use '%0' on non-async closure", + "cannot use %0 on non-async closure", (DeclAttribute)) ERROR(execution_behavior_type_attr_only_on_async,none, @@ -8566,21 +8571,21 @@ ERROR(execution_behavior_type_attr_only_on_async,none, (StringRef)) ERROR(execution_behavior_incompatible_isolated_parameter,none, - "cannot use '%0' on %kind1 because it has " + "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 " + "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", + "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", + "cannot use %0 together with an isolated parameter", (DeclAttribute)) ERROR(execution_behavior_type_attr_incompatible_with_global_isolation,none, 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/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 1aa64459a7767..902e3776815c0 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -2389,6 +2389,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); } @@ -5183,6 +5185,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) { diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 7274a728a622e..e6d1487c1ec31 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -1535,8 +1535,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; } @@ -1925,10 +1932,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()) { diff --git a/lib/AST/Bridging/DeclAttributeBridging.cpp b/lib/AST/Bridging/DeclAttributeBridging.cpp index cad38eeaecb69..2d4ab9d0d7444 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 diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index ac9b1d0af9040..5bf90ed2bf35e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -8758,6 +8758,11 @@ void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const { std::optional AbstractFunctionDecl::getExecutionBehavior() const { + if (auto *nonisolatedAttr = getAttrs().getAttribute()) { + if (nonisolatedAttr->isNonSending()) + return ExecutionKind::Caller; + } + auto *attr = getAttrs().getAttribute(); if (!attr) return {}; diff --git a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift index 059283f9e91e5..858dc8229d1d0 100644 --- a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift @@ -1416,27 +1416,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 ) } @@ -2410,12 +2408,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 @@ -2426,7 +2426,7 @@ extension ASTGenVisitor { self.ctx, atLoc: nil, range: self.generateSourceRange(node), - isUnsafe: isUnsafe + modifier: modifier ) } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 4a1ed0c93ecb2..381a4792060c1 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; @@ -5660,9 +5661,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/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 81a36ba26ea41..3fcd07b78786a 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -2622,6 +2622,10 @@ 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()) { @@ -2633,10 +2637,16 @@ static CanSILFunctionType getSILFunctionType( } } - if (decl->getAttrs().hasAttribute()) { + if (auto *nonisolatedAttr = + decl->getAttrs().getAttribute()) { + if (nonisolatedAttr->isNonSending()) + actorIsolation = ActorIsolation::forCallerIsolationInheriting(); + } else if (decl->getAttrs().hasAttribute()) { actorIsolation = ActorIsolation::forNonisolated(false /*unsafe*/); } - } else { + } + + if (!actorIsolation) { actorIsolation = getActorIsolationOfContext(constant->getInnermostDeclContext()); } diff --git a/lib/Sema/AsyncCallerExecutionMigration.cpp b/lib/Sema/AsyncCallerExecutionMigration.cpp index f2f69aaa5e98b..98d3c9c461a2e 100644 --- a/lib/Sema/AsyncCallerExecutionMigration.cpp +++ b/lib/Sema/AsyncCallerExecutionMigration.cpp @@ -121,9 +121,15 @@ void AsyncCallerExecutionMigrationTarget::diagnose() const { attrs = &closure->getAttrs(); } - if (attrs && (attrs->hasAttribute() || - attrs->hasAttribute())) { - return; + if (attrs) { + if (attrs->hasAttribute() || + attrs->hasAttribute()) + return; + + if (auto *nonisolated = attrs->getAttribute()) { + if (nonisolated->isNonSending()) + return; + } } } diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index d1bbb1f1307ef..000a8c6ce53df 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -272,6 +272,12 @@ class AttributeChecker : public AttributeVisitor { if (auto *executionAttr = D->getAttrs().getAttribute()) diagnoseAndRemoveAttr(attr, diag::actor_isolation_multiple_attr_2, D, attr, executionAttr); + + if (auto *nonisolated = D->getAttrs().getAttribute()) { + if (nonisolated->isNonSending()) + diagnoseAndRemoveAttr(attr, diag::actor_isolation_multiple_attr_2, D, + attr, nonisolated); + } } void visitAlignmentAttr(AlignmentAttr *attr) { @@ -7550,6 +7556,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(); diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 1e285616a685b..2172a6195edbe 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4938,8 +4938,12 @@ getIsolationFromAttributes(const Decl *decl, bool shouldDiagnose = true, // 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); diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index eac0003ef183e..f588a4287f143 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -6513,11 +6513,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 d180768509df4..dbb2856eb633b 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 = 939; // @concurrent attribute +const uint16_t SWIFTMODULE_VERSION_MINOR = 940; // nonisolated(nonsending) /// A standard hash seed used for all string hashes in a serialized module. /// @@ -2551,7 +2551,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..1c76a25ae1f1a 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3471,9 +3471,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/attr/attr_execution.swift b/test/attr/attr_execution.swift deleted file mode 100644 index e9dc8aa4625cd..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'}} - -@concurrent @execution(caller) func mutipleAttrs() async {} -// expected-error@-1 {{global function 'mutipleAttrs()' has multiple actor-isolation attributes (@execution(caller) and @concurrent)}} - -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}} -} - -@concurrent func nonAsync1() {} -// expected-error@-1 {{cannot use '@concurrent' on non-async global function 'nonAsync1()'}} - -@execution(caller) func nonAsync2() {} -// expected-error@-1 {{cannot use '@execution(caller)' 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 '@execution(caller)' on non-async subscript 'subscript(sync:)'}} - @execution(caller) 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}} - } - @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(caller)' on non-async property 'syncP'}} - - @execution(caller) 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)}} - - @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(caller)' on instance method 'testCaller(arg:)' because it has an isolated parameter: 'arg'}} - - @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 { - @concurrent func test() async {} -} - -@MainActor -struct IsolatedType { - @concurrent func test() async {} -} - -_ = { @execution(caller) in // Ok -} - -_ = { @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}} -} - -_ = { @execution(caller) (x: isolated (any Actor)?) in - // expected-error@-1 {{cannot use '@execution(caller)' 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..61ffad7d7c4e4 --- /dev/null +++ b/test/attr/execution_behavior_attrs.swift @@ -0,0 +1,140 @@ +// RUN: %target-typecheck-verify-swift -target %target-swift-5.1-abi-triple -enable-experimental-feature ExecutionAttribute + +// REQUIRES: concurrency +// REQUIRES: swift_feature_ExecutionAttribute + +// 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}} +} From 54b62ae9833fe5da7bc2131b2d9176ba7db7aa5e Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 7 Apr 2025 16:18:40 -0700 Subject: [PATCH 07/14] [AST/Parse] Implement `nonisolated(nonsending)` type modifier --- include/swift/AST/ASTBridging.h | 6 +++ include/swift/AST/DiagnosticsParse.def | 13 +++++ include/swift/AST/DiagnosticsSema.def | 26 +++++++++- include/swift/AST/TypeRepr.h | 30 +++++++++++ include/swift/AST/TypeReprNodes.def | 1 + include/swift/Parse/Parser.h | 13 +++++ lib/AST/ASTDumper.cpp | 6 +++ lib/AST/ASTWalker.cpp | 4 ++ lib/AST/Bridging/TypeReprBridging.cpp | 8 +++ lib/AST/NameLookup.cpp | 6 +++ lib/AST/TypeRepr.cpp | 5 ++ lib/ASTGen/Sources/ASTGen/Types.swift | 11 ++++ lib/Migrator/APIDiffMigratorPass.cpp | 4 ++ lib/Parse/ParseDecl.cpp | 38 ++++++++++++++ lib/Parse/ParseExpr.cpp | 5 +- lib/Parse/ParseType.cpp | 42 +++++++++++++++ lib/Sema/TypeCheckDecl.cpp | 6 ++- lib/Sema/TypeCheckType.cpp | 72 +++++++++++++++++++++++++- 18 files changed, 291 insertions(+), 5 deletions(-) diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index f962df542cffb..9dd80a51ed67e 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -2782,6 +2782,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/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index e7d6ba6adcc97..58decf8ee8d5a 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -2172,5 +2172,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 0927b9a7c37d5..3401889dfe79e 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8550,7 +8550,7 @@ GROUPED_ERROR(isolated_conformance_wrong_domain,IsolatedConformances,none, (ActorIsolation, Type, DeclName, ActorIsolation)) //===----------------------------------------------------------------------===// -// MARK: @execution Attribute +// MARK: @execution, @concurrent and nonisolated(nonsending) attributes //===----------------------------------------------------------------------===// ERROR(execution_behavior_only_on_async,none, @@ -8570,6 +8570,18 @@ ERROR(execution_behavior_type_attr_only_on_async,none, "cannot use '@%0' on non-async function type", (StringRef)) +ERROR(nonisolated_nonsending_only_on_function_types, none, + "%0 may only be used on function types", + (TypeRepr *)) + +ERROR(nonisolated_nonsending_only_on_async,none, + "cannot use %0 on non-async function type", + (TypeRepr *)) + +ERROR(cannot_use_nonisolated_nonsending_together_with_concurrent,none, + "cannot use %0 together with '@concurrent'", + (TypeRepr *)) + ERROR(execution_behavior_incompatible_isolated_parameter,none, "cannot use %0 on %kind1 because it has " "an isolated parameter: %2", @@ -8592,14 +8604,26 @@ 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 " "requires parameter and result types to conform to 'Sendable' protocol", 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/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 902e3776815c0..f3ee5bc28b9ca 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -4646,6 +4646,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")); 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/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/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/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/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 381a4792060c1..f6a30693e2905 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -5297,6 +5297,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 @@ -5323,6 +5324,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")) { 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..5e16612a2e580 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,34 @@ 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 `(<>)` + if (!Tok.is(tok::l_paren)) + return false; + + // Consume argument list + skipSingle(); + + // if consumed '(...)' ended up being followed + // by `[async, throws, ...] -> ...` this means + // the `nonisolated` is invalid as a modifier. + return !isAtFunctionTypeArrow(); +} + bool Parser::canParseTypeScalar() { // Accept 'inout' at for better recovery. consumeIf(tok::kw_inout); @@ -1737,6 +1769,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/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/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 972d36cd7e2fc..4cb36059a93a9 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); @@ -5275,6 +5281,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) { @@ -6395,6 +6464,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker { case TypeReprKind::PackElement: case TypeReprKind::LifetimeDependent: case TypeReprKind::Integer: + case TypeReprKind::CallerIsolated: return false; } } From 07ff063ae39e3fe1274957e6d06eb33082f8df40 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 8 Apr 2025 18:20:23 -0700 Subject: [PATCH 08/14] [AST/ASTGen/Sema/Serialization] Remove `@execution` attribute Complete the transition from `@execution` to `@concurrent` and `nonisolated(nonsending)` --- include/swift/AST/ASTBridging.h | 21 ----- include/swift/AST/Attr.h | 58 ------------- include/swift/AST/AttrKind.h | 8 -- include/swift/AST/Decl.h | 2 - include/swift/AST/DeclAttr.def | 6 +- include/swift/AST/DiagnosticsParse.def | 8 -- include/swift/AST/DiagnosticsSema.def | 2 +- include/swift/AST/TypeAttr.def | 1 - lib/AST/ASTDumper.cpp | 13 +-- lib/AST/ASTPrinter.cpp | 5 +- lib/AST/Attr.cpp | 34 -------- lib/AST/Bridging/DeclAttributeBridging.cpp | 18 +--- lib/AST/Bridging/TypeAttributeBridging.cpp | 17 ---- lib/AST/Decl.cpp | 13 --- lib/AST/FeatureSet.cpp | 14 ++-- lib/ASTGen/Sources/ASTGen/DeclAttrs.swift | 28 ------- lib/ASTGen/Sources/ASTGen/TypeAttrs.swift | 30 ------- lib/Demangling/NodePrinter.cpp | 2 +- lib/Parse/ParseDecl.cpp | 61 -------------- lib/SIL/IR/SILFunctionType.cpp | 8 -- lib/Sema/AsyncCallerExecutionMigration.cpp | 3 +- lib/Sema/CSGen.cpp | 8 -- lib/Sema/ConstraintSystem.cpp | 6 +- lib/Sema/TypeCheckAttr.cpp | 25 ------ lib/Sema/TypeCheckConcurrency.cpp | 36 +++----- lib/Sema/TypeCheckDeclOverride.cpp | 1 - lib/Sema/TypeCheckType.cpp | 12 +-- lib/Serialization/Deserialization.cpp | 8 -- lib/Serialization/ModuleFormat.h | 7 +- lib/Serialization/Serialization.cpp | 9 -- test/ASTGen/attrs.swift | 2 +- .../nonisolated_inherits_isolation.swift | 2 +- .../attr_execution/adoption_mode.swift | 2 +- .../attr_execution/attr_execution.swift | 2 +- .../attr_execution/conversions.swift | 84 ++++++++----------- .../attr_execution/conversions_silgen.swift | 42 +++++----- .../attr_execution/protocols_silgen.swift | 16 ++-- test/Demangle/Inputs/manglings.txt | 2 +- ...e_decl_attribute_feature_requirement.swift | 26 ------ test/ModuleInterface/attrs.swift | 4 +- test/ModuleInterface/execution_attr.swift | 66 --------------- .../execution_behavior_attrs.swift | 42 ++++++++++ test/Parse/execution.swift | 56 ------------- test/Parse/execution_behavior_attrs.swift | 80 ++++++++++++++++++ test/SILGen/execution_attr.swift | 8 +- .../Inputs/caller_inheriting_isolation.swift | 12 +-- test/attr/attr_abi.swift | 18 ++-- 47 files changed, 242 insertions(+), 686 deletions(-) delete mode 100644 test/ModuleInterface/execution_attr.swift create mode 100644 test/ModuleInterface/execution_behavior_attrs.swift delete mode 100644 test/Parse/execution.swift create mode 100644 test/Parse/execution_behavior_attrs.swift diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 9dd80a51ed67e..4273dcae8e416 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -910,15 +910,6 @@ void BridgedAvailableAttr_setIsGroupedWithWildcard(BridgedAvailableAttr cAttr); SWIFT_NAME("BridgedAvailableAttr.setIsGroupTerminator(self:)") void BridgedAvailableAttr_setIsGroupTerminator(BridgedAvailableAttr cAttr); -enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedExecutionKind { - 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, @@ -2596,10 +2587,6 @@ BridgedConventionTypeAttr BridgedConventionTypeAttr_createParsed( BridgedSourceLoc cNameLoc, BridgedDeclNameRef cWitnessMethodProtocol, BridgedStringRef cClangType, BridgedSourceLoc cClangTypeLoc); -enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedExecutionTypeAttrExecutionKind { - BridgedExecutionTypeAttrExecutionKind_Caller -}; - SWIFT_NAME("BridgedDifferentiableTypeAttr.createParsed(_:atLoc:nameLoc:" "parensRange:kind:kindLoc:)") BridgedDifferentiableTypeAttr BridgedDifferentiableTypeAttr_createParsed( @@ -2607,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( diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 7c97070c6b8bd..d9bc17ab67d75 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -236,10 +236,6 @@ class DeclAttribute : public AttributeBase { NumFeatures : 31 ); - - SWIFT_INLINE_BITFIELD(ExecutionAttr, DeclAttribute, NumExecutionKindBits, - Behavior : NumExecutionKindBits - ); } Bits; // clang-format on @@ -3284,34 +3280,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. @@ -3771,10 +3739,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 @@ -4046,28 +4010,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 320c8ea03ff67..7ac94fb07c0e2 100644 --- a/include/swift/AST/AttrKind.h +++ b/include/swift/AST/AttrKind.h @@ -130,14 +130,6 @@ enum class ExternKind: uint8_t { enum : unsigned { NumExternKindBits = countBitsUsed(static_cast(ExternKind::Last_ExternKind)) }; -enum class ExecutionKind : uint8_t { - Caller = 0, - Last_ExecutionKind = Caller -}; - -enum : unsigned { NumExecutionKindBits = - countBitsUsed(static_cast(ExecutionKind::Last_ExecutionKind)) }; - enum class NonIsolatedModifier : uint8_t { None = 0, Unsafe, 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 05bf77f70e535..c179bda8bab08 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, diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 58decf8ee8d5a..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, diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 3401889dfe79e..7661d18157842 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8550,7 +8550,7 @@ GROUPED_ERROR(isolated_conformance_wrong_domain,IsolatedConformances,none, (ActorIsolation, Type, DeclName, ActorIsolation)) //===----------------------------------------------------------------------===// -// MARK: @execution, @concurrent and nonisolated(nonsending) attributes +// MARK: @concurrent and nonisolated(nonsending) attributes //===----------------------------------------------------------------------===// ERROR(execution_behavior_only_on_async,none, diff --git a/include/swift/AST/TypeAttr.def b/include/swift/AST/TypeAttr.def index e1b0320f1b1ee..4defd43cf1cdf 100644 --- a/include/swift/AST/TypeAttr.def +++ b/include/swift/AST/TypeAttr.def @@ -67,7 +67,6 @@ 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 diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index f3ee5bc28b9ca..060a8364a635a 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -618,12 +618,6 @@ static StringRef getDumpString(FunctionRefInfo::ApplyLevel applyLevel) { return "double_apply"; } } -static StringRef getDumpString(ExecutionKind kind) { - switch (kind) { - case ExecutionKind::Caller: - return "caller"; - } -} static StringRef getDumpString(ExplicitSafety safety) { switch (safety) { case ExplicitSafety::Unspecified: @@ -4936,11 +4930,6 @@ class PrintAttribute : public AttributeVisitor, #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")); @@ -6349,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..649fcc4399627 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3306,7 +3306,7 @@ static void suppressingFeatureExecutionAttribute(PrintOptions &options, llvm::function_ref action) { llvm::SaveAndRestore scope1(options.SuppressExecutionAttribute, true); - ExcludeAttrRAII scope2(options.ExcludeAttrList, DeclAttrKind::Execution); + ExcludeAttrRAII scope2(options.ExcludeAttrList, DeclAttrKind::Concurrent); action(); } @@ -6509,8 +6509,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/Attr.cpp b/lib/AST/Attr.cpp index e6d1487c1ec31..12631530028cb 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -304,23 +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::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 @@ -1726,16 +1709,6 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, break; } - case DeclAttrKind::Execution: { - auto *attr = cast(this); - switch (attr->getBehavior()) { - 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"); @@ -1960,13 +1933,6 @@ StringRef DeclAttribute::getAttrName() const { } case DeclAttrKind::Lifetime: return "lifetime"; - case DeclAttrKind::Execution: { - switch (cast(this)->getBehavior()) { - 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 2d4ab9d0d7444..a9a6654dc2342 100644 --- a/lib/AST/Bridging/DeclAttributeBridging.cpp +++ b/lib/AST/Bridging/DeclAttributeBridging.cpp @@ -899,20 +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 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 70d093b96dddb..1cc5050d13f90 100644 --- a/lib/AST/Bridging/TypeAttributeBridging.cpp +++ b/lib/AST/Bridging/TypeAttributeBridging.cpp @@ -87,23 +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_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/Decl.cpp b/lib/AST/Decl.cpp index 5bf90ed2bf35e..91c7b3378b7a5 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -8756,19 +8756,6 @@ void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const { } } -std::optional -AbstractFunctionDecl::getExecutionBehavior() const { - if (auto *nonisolatedAttr = getAttrs().getAttribute()) { - if (nonisolatedAttr->isNonSending()) - return ExecutionKind::Caller; - } - - 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 894451e8028b9..1c73e8cf06ea5 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -503,17 +503,15 @@ static bool usesFeatureBuiltinEmplaceTypedThrows(Decl *decl) { } static bool usesFeatureExecutionAttribute(Decl *decl) { - if (!DeclAttribute::canAttributeAppearOnDecl(DeclAttrKind::Execution, decl)) { + if (!DeclAttribute::canAttributeAppearOnDecl(DeclAttrKind::Concurrent, + decl)) { return false; } - if (decl->getAttrs().hasAttribute()) - return true; - if (decl->getAttrs().hasAttribute()) return true; - auto hasExecutionAttr = [](TypeRepr *R) { + auto hasConcurrentAttr = [](TypeRepr *R) { if (!R) return false; @@ -521,7 +519,7 @@ static bool usesFeatureExecutionAttribute(Decl *decl) { if (auto *AT = dyn_cast(repr)) { return llvm::any_of(AT->getAttrs(), [](TypeOrCustomAttr attr) { if (auto *TA = attr.dyn_cast()) { - return isa(TA); + return isa(TA); } return false; }); @@ -535,12 +533,12 @@ static bool usesFeatureExecutionAttribute(Decl *decl) { // Check if any parameters that have `@execution` attribute. if (auto *PL = VD->getParameterList()) { for (auto *P : *PL) { - if (hasExecutionAttr(P->getTypeRepr())) + if (hasConcurrentAttr(P->getTypeRepr())) return true; } } - if (hasExecutionAttr(VD->getResultTypeRepr())) + if (hasConcurrentAttr(VD->getResultTypeRepr())) return true; return false; diff --git a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift index 858dc8229d1d0..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: @@ -361,32 +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 "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()) diff --git a/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift b/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift index e54b9e14178a3..ede0bb3fb31e4 100644 --- a/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/TypeAttrs.swift @@ -76,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(_:)) @@ -240,33 +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 "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/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/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index f6a30693e2905..c2903b5cd681a 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3947,20 +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_caller, ExecutionKind::Caller}}); - if (!behavior) - return makeParserSuccess(); - - if (!DiscardAttribute) - Attributes.add(new (Context) ExecutionAttr(AtLoc, AttrRange, *behavior, - /*Implicit*/ false)); - - break; - } } if (DuplicateAttribute) { @@ -4748,53 +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, "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; diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 3fcd07b78786a..a52a1608532bd 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -2629,14 +2629,6 @@ static CanSILFunctionType getSILFunctionType( if (constant->kind == SILDeclRef::Kind::Deallocator) { actorIsolation = ActorIsolation::forNonisolated(false); } else if (auto *decl = constant->getAbstractFunctionDecl()) { - if (auto behavior = decl->getExecutionBehavior()) { - switch (behavior.value()) { - case ExecutionKind::Caller: - actorIsolation = ActorIsolation::forCallerIsolationInheriting(); - break; - } - } - if (auto *nonisolatedAttr = decl->getAttrs().getAttribute()) { if (nonisolatedAttr->isNonSending()) diff --git a/lib/Sema/AsyncCallerExecutionMigration.cpp b/lib/Sema/AsyncCallerExecutionMigration.cpp index 98d3c9c461a2e..323b2b901e316 100644 --- a/lib/Sema/AsyncCallerExecutionMigration.cpp +++ b/lib/Sema/AsyncCallerExecutionMigration.cpp @@ -122,8 +122,7 @@ void AsyncCallerExecutionMigrationTarget::diagnose() const { } if (attrs) { - if (attrs->hasAttribute() || - attrs->hasAttribute()) + if (attrs->hasAttribute()) return; if (auto *nonisolated = attrs->getAttribute()) { diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 439a7cba3f140..dd62be4ded543 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2584,14 +2584,6 @@ namespace { return FunctionTypeIsolation::forGlobalActor(actorType); } - if (auto *execution = - closure->getAttrs().getAttribute()) { - switch (execution->getBehavior()) { - case ExecutionKind::Caller: - return FunctionTypeIsolation::forNonIsolatedCaller(); - } - } - if (closure->getAttrs().hasAttribute()) { return FunctionTypeIsolation::forNonIsolated(); } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 0978434dc7472..a4d1b99dd4603 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -1414,10 +1414,8 @@ FunctionType::ExtInfo ClosureEffectsRequest::evaluate( bool async = expr->getAsyncLoc().isValid(); bool sendable = expr->getAttrs().hasAttribute(); - // `@execution(...)` and `@concurrent` attributes are only - // valid on asynchronous function types. - if (expr->getAttrs().hasAttribute() || - expr->getAttrs().hasAttribute()) { + // `@concurrent` attribute is only valid on asynchronous function types. + if (expr->getAttrs().hasAttribute()) { async = true; } diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 000a8c6ce53df..656db55f364ef 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -258,21 +258,9 @@ class AttributeChecker : public AttributeVisitor { } } - void visitExecutionAttr(ExecutionAttr *attr) { - checkExecutionBehaviorAttribute(attr); - - if (auto *concurrentAttr = D->getAttrs().getAttribute()) - diagnoseAndRemoveAttr(attr, diag::actor_isolation_multiple_attr_2, D, - attr, concurrentAttr); - } - void visitConcurrentAttr(ConcurrentAttr *attr) { checkExecutionBehaviorAttribute(attr); - if (auto *executionAttr = D->getAttrs().getAttribute()) - diagnoseAndRemoveAttr(attr, diag::actor_isolation_multiple_attr_2, D, - attr, executionAttr); - if (auto *nonisolated = D->getAttrs().getAttribute()) { if (nonisolated->isNonSending()) diagnoseAndRemoveAttr(attr, diag::actor_isolation_multiple_attr_2, D, @@ -4337,7 +4325,6 @@ 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; @@ -4350,9 +4337,6 @@ static void checkGlobalActorAttr( if (nonisolatedAttr) { attributes.push_back(nonisolatedAttr); } - if (executionAttr) { - attributes.push_back(executionAttr); - } if (concurrentAttr) { attributes.push_back(concurrentAttr); } @@ -8184,11 +8168,6 @@ class ClosureAttributeChecker } void checkExecutionBehaviorAttribute(DeclAttribute *attr) { - if (!ctx.LangOpts.hasFeature(Feature::ExecutionAttribute)) { - visitDeclAttribute(attr); - return; - } - // execution behavior attribute implies `async`. if (closure->hasExplicitResultType() && closure->getAsyncLoc().isInvalid()) { @@ -8222,10 +8201,6 @@ class ClosureAttributeChecker } } - void visitExecutionAttr(ExecutionAttr *attr) { - checkExecutionBehaviorAttribute(attr); - } - void visitConcurrentAttr(ConcurrentAttr *attr) { checkExecutionBehaviorAttribute(attr); } diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 2172a6195edbe..f244435e492e6 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4889,7 +4889,6 @@ 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. @@ -4900,16 +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) + - (concurrentAttr ? 1 : 0); + (globalActorAttr ? 1 : 0) + (concurrentAttr ? 1 : 0); if (numIsolationAttrs == 0) { if (isa(decl) && !decl->isImplicit()) { return ActorIsolation::forNonisolated(false); @@ -4917,21 +4913,6 @@ 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::Caller: - return ActorIsolation::forCallerIsolationInheriting(); - } - } - if (concurrentAttr) return ActorIsolation::forNonisolated(/*is unsafe*/ false); @@ -5704,8 +5685,9 @@ 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: { @@ -5898,10 +5880,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/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index c61e59e6f8478..62a7ea1797b99 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1595,7 +1595,6 @@ namespace { 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 4cb36059a93a9..e0b165aae0e5e 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -4239,17 +4239,7 @@ NeverNullType TypeResolver::resolveASTFunctionType( } }; - if (auto executionAttr = claim(attrs)) { - checkExecutionBehaviorAttribute(executionAttr); - - if (!repr->isInvalid()) { - switch (executionAttr->getBehavior()) { - case ExecutionKind::Caller: - isolation = FunctionTypeIsolation::forNonIsolatedCaller(); - break; - } - } - } else if (auto concurrentAttr = claim(attrs)) { + if (auto concurrentAttr = claim(attrs)) { checkExecutionBehaviorAttribute(concurrentAttr); if (!repr->isInvalid()) isolation = FunctionTypeIsolation::forNonIsolated(); diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index f588a4287f143..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; diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index dbb2856eb633b..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 = 940; // nonisolated(nonsending) +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 diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 1c76a25ae1f1a..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]; diff --git a/test/ASTGen/attrs.swift b/test/ASTGen/attrs.swift index 9a8eda233be64..114e75edd1a24 100644 --- a/test/ASTGen/attrs.swift +++ b/test/ASTGen/attrs.swift @@ -199,7 +199,7 @@ struct StorageRestrctionTest { } do { - @execution(caller) func testLocal() async {} // Ok + nonisolated(nonsending) func testLocal() async {} // Ok struct Test { @concurrent func testMember() async {} // Ok diff --git a/test/Concurrency/Runtime/nonisolated_inherits_isolation.swift b/test/Concurrency/Runtime/nonisolated_inherits_isolation.swift index c4c40b3ce099a..e6bad2c008b64 100644 --- a/test/Concurrency/Runtime/nonisolated_inherits_isolation.swift +++ b/test/Concurrency/Runtime/nonisolated_inherits_isolation.swift @@ -34,7 +34,7 @@ struct CustomActor { } } -@execution(caller) +nonisolated(nonsending) func executionCallerIsolation() async { checkIfOnMainQueue() } diff --git a/test/Concurrency/attr_execution/adoption_mode.swift b/test/Concurrency/attr_execution/adoption_mode.swift index 82e34468a416e..02ec00ca136b5 100644 --- a/test/Concurrency/attr_execution/adoption_mode.swift +++ b/test/Concurrency/attr_execution/adoption_mode.swift @@ -14,7 +14,7 @@ struct G { do { func syncF() {} @concurrent func executionConcurrentAsyncF() async {} - @execution(caller) func executionCallerAsyncF() async {} + nonisolated(nonsending) func executionCallerAsyncF() async {} @MainActor func mainActorAsyncF() async {} func isolatedParamAsyncF( isolation: isolated (any Actor)? = #isolation diff --git a/test/Concurrency/attr_execution/attr_execution.swift b/test/Concurrency/attr_execution/attr_execution.swift index e09c9b9fcae47..8ed41f1cce28b 100644 --- a/test/Concurrency/attr_execution/attr_execution.swift +++ b/test/Concurrency/attr_execution/attr_execution.swift @@ -13,5 +13,5 @@ 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 7e7b7eaeb247c..94a4c32596571 100644 --- a/test/Concurrency/attr_execution/conversions.swift +++ b/test/Concurrency/attr_execution/conversions.swift @@ -12,14 +12,14 @@ actor MyActor { func concurrentTest() async { } -@execution(caller) +nonisolated(nonsending) func callerTest() async { } @MainActor func actorIsolated() async {} -let _: @execution(caller) () async -> Void = concurrentTest // Ok +let _: nonisolated(nonsending) () async -> Void = concurrentTest // Ok let _: @concurrent () async -> Void = callerTest // Ok let _: @MainActor () async -> Void = concurrentTest // Ok @@ -27,43 +27,39 @@ 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 _: nonisolated(nonsending) () async -> Void = actorIsolated // Ok let _: @concurrent () async -> Void = actorIsolated // Ok func testIsolationErasure(fn: @escaping @isolated(any) () async -> Void) { let _: @concurrent () async -> Void = fn // Ok - let _: @execution(caller) () 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'}} +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 +69,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 +89,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 = { @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( @@ -120,26 +110,26 @@ func testNonSendableDiagnostics( nonIsolated2: @escaping @Sendable @concurrent (NonSendable) async -> Void, nonIsolated3: @escaping @Sendable () -> NonSendable, nonIsolated4: @escaping @Sendable @concurrent () async -> NonSendable, - caller1: @escaping @Sendable @execution(caller) (NonSendable) async -> Void, - caller2: @escaping @Sendable @execution(caller) () 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 _: @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}} @@ -148,9 +138,9 @@ func testNonSendableDiagnostics( let _: @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}} + // 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 '@execution(caller) @Sendable () async -> NonSendable' to '() async -> NonSendable' because crossing of an isolation boundary requires parameter and result types to 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 579fc46be08d4..60091dd12e445 100644 --- a/test/Concurrency/attr_execution/conversions_silgen.swift +++ b/test/Concurrency/attr_execution/conversions_silgen.swift @@ -12,7 +12,7 @@ // MARK: Declarations // //////////////////////// -@execution(caller) +nonisolated(nonsending) func globalCallerFunc() async -> () {} @concurrent @@ -25,13 +25,13 @@ class SendableKlass : @unchecked Sendable { init() {} } -@execution(caller) +nonisolated(nonsending) func globalCallerFuncSendableKlass(_ x: SendableKlass) async -> () {} @concurrent func globalConcurrentFuncSendableKlass(_ x: SendableKlass) async -> () {} -@execution(caller) +nonisolated(nonsending) func globalCallerFuncSendableKlass(_ x: SendableKlass) async -> SendableKlass { fatalError() } @concurrent @@ -48,7 +48,7 @@ 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 { +public func testCallerToConcurrentNonIsolated(_ x: nonisolated(nonsending) @escaping () async -> ()) async { let y: @concurrent () async -> () = x await y() } @@ -69,7 +69,7 @@ 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 { +public func testCallerToConcurrentMainActor(_ x: nonisolated(nonsending) @escaping () async -> ()) async { let y: @concurrent () async -> () = x await y() } @@ -81,7 +81,7 @@ public func testCallerToConcurrentMainActor(_ x: @escaping @execution(caller) () // CHECK: partial_apply [callee_guaranteed] [[THUNK]]([[FUNC_COPY]]) // CHECK: } // end sil function '$s21attr_execution_silgen33testConcurrentToCallerNonIsolatedyyyyYacYaF' public func testConcurrentToCallerNonIsolated(_ x: @escaping @concurrent () async -> ()) async { - let y: @execution(caller) () async -> () = x + let y: nonisolated(nonsending) () async -> () = x await y() } @@ -101,7 +101,7 @@ public func testConcurrentToCallerNonIsolated(_ x: @escaping @concurrent () asyn // CHECK: } // end sil function '$s21attr_execution_silgen42testConcurrentToCallerNonIsolatedMainActoryyyyYacYaF' @MainActor public func testConcurrentToCallerNonIsolatedMainActor(_ x: @escaping @concurrent () async -> ()) async { - let y: @execution(caller) () async -> () = x + let y: nonisolated(nonsending) () async -> () = x await y() } @@ -142,10 +142,10 @@ public func testConcurrentToConcurrent(_ x: @escaping @concurrent () async -> () // 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 +162,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() } @@ -196,9 +196,9 @@ public func testConcurrentLocalVariables(_ x: @escaping @concurrent () async -> // 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 { +public func testCallerConcurrentLocalVariables(_ x: nonisolated(nonsending) @escaping () async -> ()) async { let y: @concurrent () async -> () = x - let y2: @execution(caller) () async -> () = y + let y2: nonisolated(nonsending) () async -> () = y await y2() } @@ -214,7 +214,7 @@ public func testCallerConcurrentLocalVariables(_ x: @escaping @execution(caller) // CHECK: [[PA_2:%.*]] = partial_apply [callee_guaranteed] [[THUNK_2]]([[Y_B_C]]) // CHECK: } // end sil function '$s21attr_execution_silgen34testConcurrentCallerLocalVariablesyyyyYacYaF' public func testConcurrentCallerLocalVariables(_ x: @escaping @concurrent () async -> ()) async { - let y: @execution(caller) () async -> () = x + let y: nonisolated(nonsending) () async -> () = x let y2: @concurrent () async -> () = y await y2() } @@ -262,7 +262,7 @@ public func testConcurrentCallerLocalVariables(_ x: @escaping @concurrent () asy // CHECK: } // end sil function '$s21attr_execution_silgen22globalActorConversionsyyyyYac_yyYaYCctYaF' func globalActorConversions(_ x: @escaping @concurrent () async -> (), - _ y: @escaping @execution(caller) () async -> ()) async { + _ y: nonisolated(nonsending) @escaping () async -> ()) async { let v1: @MainActor () async -> Void = globalCallerFunc await v1() let v2: @MainActor () async -> Void = globalConcurrentFunc @@ -321,7 +321,7 @@ func globalActorConversions(_ x: @escaping @concurrent () async -> (), // CHECK: } // end sil function '$s21attr_execution_silgen23globalActorConversions2yyyAA13SendableKlassCYac_yADYaYCctYaF' func globalActorConversions2(_ x: @escaping @concurrent (SendableKlass) async -> (), - _ y: @escaping @execution(caller) (SendableKlass) async -> ()) 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 @@ -382,7 +382,7 @@ func globalActorConversions2(_ x: @escaping @concurrent (SendableKlass) async -> // CHECK: [[V5:%.*]] = move_value [lexical] [var_decl] [[PA]] // CHECK: } // end sil function '$s21attr_execution_silgen23globalActorConversions3yyAA13SendableKlassCADYac_A2DYaYCctYaF' func globalActorConversions3(_ x: @escaping @concurrent (SendableKlass) async -> SendableKlass, - _ y: @escaping @execution(caller) (SendableKlass) async -> SendableKlass) async { + _ 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 @@ -421,8 +421,8 @@ func globalActorConversions3(_ x: @escaping @concurrent (SendableKlass) async -> 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 _: 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..935a101d63053 100644 --- a/test/Concurrency/attr_execution/protocols_silgen.swift +++ b/test/Concurrency/attr_execution/protocols_silgen.swift @@ -9,8 +9,8 @@ // 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 +47,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 +56,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 +67,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 +80,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 +88,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 +96,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_feature_requirement.swift b/test/IDE/complete_decl_attribute_feature_requirement.swift index 8fabadd74d3f1..3d260b0faf4c7 100644 --- a/test/IDE/complete_decl_attribute_feature_requirement.swift +++ b/test/IDE/complete_decl_attribute_feature_requirement.swift @@ -18,18 +18,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 +34,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 +102,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 +114,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 +130,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 251b28751baab..ed11b83944ce7 100644 --- a/test/ModuleInterface/attrs.swift +++ b/test/ModuleInterface/attrs.swift @@ -91,9 +91,9 @@ public struct MutatingTest { 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 cbfb735588a9e..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: @concurrent public func test() async - // CHECK-NEXT: #else - // CHECK-NEXT: public func test() async - // CHECK-NEXT: #endif - @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..9a1b0eb92e3a0 --- /dev/null +++ b/test/ModuleInterface/execution_behavior_attrs.swift @@ -0,0 +1,42 @@ +// 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: nonisolated(nonsending) public init() async + nonisolated(nonsending) + public init() async { + } + + // CHECK: @concurrent public func test() async + @concurrent + public func test() async { + } + + // CHECK: public func other(_: nonisolated(nonsending) () async -> Swift.Void) + public func other(_: nonisolated(nonsending) () async -> Void) {} + + // CHECK: nonisolated(nonsending) public var testOnVar: Swift.Int { + // CHECK-NEXT: get async + // CHECK-NEXT: } + nonisolated(nonsending) + public var testOnVar: Int { + get async { + 42 + } + } + + // CHECK: nonisolated(nonsending) public subscript(onSubscript _: Swift.Int) -> Swift.Bool { + // CHECK-NEXT: get async + // CHECK-NEXT: } + nonisolated(nonsending) + public subscript(onSubscript _: Int) -> Bool { + get async { + false + } + } +} + diff --git a/test/Parse/execution.swift b/test/Parse/execution.swift deleted file mode 100644 index 2b0980da15332..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 = @concurrent () async -> Void - -typealias E = @concurrent () -> Void -// expected-error@-1 {{cannot use '@concurrent' on non-async function type}} - -func test1(_: @execution(caller) (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(_: @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(_: @concurrent @isolated(any) () async -> Void) {} -// expected-error@-1 {{cannot use '@concurrent' 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(_: @concurrent (isolated (any Actor)?) async -> Void) {} -// expected-error@-1 {{cannot use '@concurrent' 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(_: @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..a4b51e23336db --- /dev/null +++ b/test/Parse/execution_behavior_attrs.swift @@ -0,0 +1,80 @@ +// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature ExecutionAttribute + +// REQUIRES: concurrency +// REQUIRES: swift_feature_ExecutionAttribute + +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()] +} diff --git a/test/SILGen/execution_attr.swift b/test/SILGen/execution_attr.swift index a5681cd97bac1..acbce63d35c3e 100644 --- a/test/SILGen/execution_attr.swift +++ b/test/SILGen/execution_attr.swift @@ -11,7 +11,7 @@ // 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() @@ -23,7 +23,7 @@ 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() } @@ -34,7 +34,7 @@ func executionConcurrentParameter(_ x: @concurrent () async -> ()) async { } 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 +61,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 980afa340f8ae..b249da80dbc88 100644 --- a/test/Serialization/Inputs/caller_inheriting_isolation.swift +++ b/test/Serialization/Inputs/caller_inheriting_isolation.swift @@ -2,7 +2,7 @@ public func unspecifiedAsync(_ t: T) async { } -@execution(caller) +nonisolated(nonsending) public func unspecifiedAsyncCaller(_ t: T) async { } @@ -13,8 +13,8 @@ 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 { } @concurrent @@ -26,7 +26,7 @@ public struct S { public func unspecifiedAsync(_ t: T) async { } - @execution(caller) + nonisolated(nonsending) public func unspecifiedAsyncCaller(_ t: T) async { } @@ -37,8 +37,8 @@ public struct S { nonisolated public func nonisolatedAsync(_ t: T) async { } - @execution(caller) - nonisolated public func nonisolatedAsyncCaller(_ t: T) async { + nonisolated(nonsending) + public func nonisolatedAsyncCaller(_ t: T) async { } @concurrent diff --git a/test/attr/attr_abi.swift b/test/attr/attr_abi.swift index 04ecbbacff0a2..e7b81d537371e 100644 --- a/test/attr/attr_abi.swift +++ b/test/attr/attr_abi.swift @@ -948,7 +948,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'}} @@ -1247,26 +1247,26 @@ func isolation10() 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) +@abi(nonisolated(nonsending) func isolation18() async) @concurrent func isolation18() async {} @abi(@concurrent func isolation19() async) -@execution(caller) func isolation19() async {} +nonisolated(nonsending) func isolation19() async {} // NSCopying - see attr/attr_abi_objc.swift From 9da457d12963d6df58032d6574aa98795357f9da Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 9 Apr 2025 00:05:16 -0700 Subject: [PATCH 09/14] [Sema/SILGen] NFC: Remove all mentions of `@execution` from comments --- lib/SILGen/SILGenExpr.cpp | 30 ++++++++++++------------ lib/Sema/AsyncCallerExecutionMigration.h | 12 +++++----- lib/Sema/CSSimplify.cpp | 8 +++---- lib/Sema/TypeCheckConcurrency.cpp | 22 ++++++++--------- lib/Sema/TypeCheckType.cpp | 5 ++-- 5 files changed, 39 insertions(+), 38 deletions(-) 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.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/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/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index f244435e492e6..3687caea7364f 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); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index e0b165aae0e5e..bac339da6ef9d 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -4234,8 +4234,9 @@ NeverNullType TypeResolver::resolveASTFunctionType( 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."); } }; From f1b3c7b604217ca0a1dfccc1c7ff50e514164f12 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 9 Apr 2025 00:25:55 -0700 Subject: [PATCH 10/14] [AST] Remove `ExecutionAttribute` experimental feature SE-0461 has been accepted and `@concurrent` and `nonisolated(nonsending)` can be make generally available now. --- include/swift/AST/DeclAttr.def | 1 - include/swift/AST/PrintOptions.h | 3 -- include/swift/Basic/Features.def | 4 -- lib/AST/ASTPrinter.cpp | 8 ---- lib/AST/FeatureSet.cpp | 42 ------------------- test/ASTGen/attrs.swift | 4 -- .../nonisolated_inherits_isolation.swift | 3 +- .../attr_execution/adoption_mode.swift | 5 +-- .../attr_execution/attr_execution.swift | 3 +- .../attr_execution/conversions.swift | 3 +- .../attr_execution/conversions_silgen.swift | 5 +-- .../attr_execution/protocols_silgen.swift | 5 +-- test/IDE/complete_decl_attribute.swift | 5 +++ ...e_decl_attribute_feature_requirement.swift | 3 +- test/ModuleInterface/attrs.swift | 4 +- .../execution_behavior_attrs.swift | 4 +- test/Parse/execution_behavior_attrs.swift | 3 +- test/SILGen/execution_attr.swift | 5 +-- .../caller_isolation_inherit.swift | 7 ++-- test/attr/attr_abi.swift | 3 +- test/attr/execution_behavior_attrs.swift | 3 +- 21 files changed, 26 insertions(+), 97 deletions(-) diff --git a/include/swift/AST/DeclAttr.def b/include/swift/AST/DeclAttr.def index c179bda8bab08..38e758448c8b7 100644 --- a/include/swift/AST/DeclAttr.def +++ b/include/swift/AST/DeclAttr.def @@ -884,7 +884,6 @@ SIMPLE_DECL_ATTR(concurrent, Concurrent, OnFunc | OnConstructor | OnSubscript | OnVar, ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove | UnconstrainedInABIAttr, 170) -DECL_ATTR_FEATURE_REQUIREMENT(Concurrent, ExecutionAttribute) LAST_DECL_ATTR(Concurrent) 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/Basic/Features.def b/include/swift/Basic/Features.def index 672ca8f02dff9..05c6f18406854 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -484,10 +484,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/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 649fcc4399627..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::Concurrent); - action(); -} - /// Suppress the printing of a particular feature. static void suppressingFeature(PrintOptions &options, Feature feature, llvm::function_ref action) { diff --git a/lib/AST/FeatureSet.cpp b/lib/AST/FeatureSet.cpp index 1c73e8cf06ea5..de70a31a620fc 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -502,48 +502,6 @@ static bool usesFeatureBuiltinEmplaceTypedThrows(Decl *decl) { return false; } -static bool usesFeatureExecutionAttribute(Decl *decl) { - if (!DeclAttribute::canAttributeAppearOnDecl(DeclAttrKind::Concurrent, - decl)) { - return false; - } - - if (decl->getAttrs().hasAttribute()) - return true; - - auto hasConcurrentAttr = [](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; - }); - } - return false; - }); - }; - - auto *VD = cast(decl); - - // Check if any parameters that have `@execution` attribute. - if (auto *PL = VD->getParameterList()) { - for (auto *P : *PL) { - if (hasConcurrentAttr(P->getTypeRepr())) - return true; - } - } - - if (hasConcurrentAttr(VD->getResultTypeRepr())) - return true; - - return false; -} - // ---------------------------------------------------------------------------- // MARK: - FeatureSet // ---------------------------------------------------------------------------- diff --git a/test/ASTGen/attrs.swift b/test/ASTGen/attrs.swift index 114e75edd1a24..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 diff --git a/test/Concurrency/Runtime/nonisolated_inherits_isolation.swift b/test/Concurrency/Runtime/nonisolated_inherits_isolation.swift index e6bad2c008b64..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 diff --git a/test/Concurrency/attr_execution/adoption_mode.swift b/test/Concurrency/attr_execution/adoption_mode.swift index 02ec00ca136b5..6ce3737b4e924 100644 --- a/test/Concurrency/attr_execution/adoption_mode.swift +++ b/test/Concurrency/attr_execution/adoption_mode.swift @@ -1,7 +1,6 @@ -// 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 { diff --git a/test/Concurrency/attr_execution/attr_execution.swift b/test/Concurrency/attr_execution/attr_execution.swift index 8ed41f1cce28b..e7c600789fb67 100644 --- a/test/Concurrency/attr_execution/attr_execution.swift +++ b/test/Concurrency/attr_execution/attr_execution.swift @@ -1,6 +1,5 @@ -// 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 diff --git a/test/Concurrency/attr_execution/conversions.swift b/test/Concurrency/attr_execution/conversions.swift index 94a4c32596571..75a996f093af9 100644 --- a/test/Concurrency/attr_execution/conversions.swift +++ b/test/Concurrency/attr_execution/conversions.swift @@ -1,7 +1,6 @@ -// 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 { diff --git a/test/Concurrency/attr_execution/conversions_silgen.swift b/test/Concurrency/attr_execution/conversions_silgen.swift index 60091dd12e445..64cc5b920d16d 100644 --- a/test/Concurrency/attr_execution/conversions_silgen.swift +++ b/test/Concurrency/attr_execution/conversions_silgen.swift @@ -1,12 +1,11 @@ -// 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 // diff --git a/test/Concurrency/attr_execution/protocols_silgen.swift b/test/Concurrency/attr_execution/protocols_silgen.swift index 935a101d63053..37bdaa54649bb 100644 --- a/test/Concurrency/attr_execution/protocols_silgen.swift +++ b/test/Concurrency/attr_execution/protocols_silgen.swift @@ -1,12 +1,11 @@ -// 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 { nonisolated(nonsending) func callerTest() async 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 3d260b0faf4c7..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" diff --git a/test/ModuleInterface/attrs.swift b/test/ModuleInterface/attrs.swift index ed11b83944ce7..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 } diff --git a/test/ModuleInterface/execution_behavior_attrs.swift b/test/ModuleInterface/execution_behavior_attrs.swift index 9a1b0eb92e3a0..f513d15ddf21b 100644 --- a/test/ModuleInterface/execution_behavior_attrs.swift +++ b/test/ModuleInterface/execution_behavior_attrs.swift @@ -1,9 +1,9 @@ -// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -module-name execution_attr -enable-experimental-feature ExecutionAttribute +// 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: swift_feature_ExecutionAttribute +// REQUIRES: concurrency public struct Test { // CHECK: nonisolated(nonsending) public init() async diff --git a/test/Parse/execution_behavior_attrs.swift b/test/Parse/execution_behavior_attrs.swift index a4b51e23336db..1c41593d124aa 100644 --- a/test/Parse/execution_behavior_attrs.swift +++ b/test/Parse/execution_behavior_attrs.swift @@ -1,7 +1,6 @@ -// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature ExecutionAttribute +// RUN: %target-typecheck-verify-swift -disable-availability-checking // REQUIRES: concurrency -// REQUIRES: swift_feature_ExecutionAttribute typealias F = @concurrent () async -> Void diff --git a/test/SILGen/execution_attr.swift b/test/SILGen/execution_attr.swift index acbce63d35c3e..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 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 e7b81d537371e..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 diff --git a/test/attr/execution_behavior_attrs.swift b/test/attr/execution_behavior_attrs.swift index 61ffad7d7c4e4..90a9a818c0c30 100644 --- a/test/attr/execution_behavior_attrs.swift +++ b/test/attr/execution_behavior_attrs.swift @@ -1,7 +1,6 @@ -// 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 // FIXME: Bad parser diagnostic on C++ side nonisolated(something) func invalidAttr() async {} // expected-error {{cannot find 'nonisolated' in scope}} From 3906980f589ef03ec79bcbb1a6768584ad4a804e Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 10 Apr 2025 16:45:56 -0700 Subject: [PATCH 11/14] [AST] NFC: Add a convenient way to create implicit `NonisolatedAttr`s --- include/swift/AST/Attr.h | 14 ++++++++------ lib/ClangImporter/ImportDecl.cpp | 7 +++---- lib/ClangImporter/SwiftDeclSynthesizer.cpp | 4 +--- lib/Sema/CSGen.cpp | 4 ++-- lib/Sema/CodeSynthesis.cpp | 3 +-- lib/Sema/CodeSynthesisDistributedActor.cpp | 9 +++------ .../DerivedConformance/DerivedConformanceActor.cpp | 3 +-- .../DerivedConformanceCaseIterable.cpp | 3 +-- .../DerivedConformanceDistributedActor.cpp | 9 +++------ .../DerivedConformanceEquatableHashable.cpp | 6 ++---- lib/Sema/TypeCheckConcurrency.cpp | 6 ++++-- 11 files changed, 29 insertions(+), 39 deletions(-) diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index d9bc17ab67d75..0c4de231462ab 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -2978,14 +2978,9 @@ class NonisolatedAttr final : public DeclAttribute { NonIsolatedModifier modifier, bool implicit) : DeclAttribute(DeclAttrKind::Nonisolated, atLoc, range, implicit) { Bits.NonisolatedAttr.Modifier = static_cast(modifier); + assert((getModifier() == modifier) && "not enough bits for modifier"); } - NonisolatedAttr(bool unsafe, bool implicit) - : NonisolatedAttr({}, {}, - unsafe ? NonIsolatedModifier::Unsafe - : NonIsolatedModifier::None, - implicit) {} - NonIsolatedModifier getModifier() const { return static_cast(Bits.NonisolatedAttr.Modifier); } @@ -2995,6 +2990,13 @@ class NonisolatedAttr final : public DeclAttribute { 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; } 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/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index dd62be4ded543..e3b267dadbab9 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -4585,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/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/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/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 3687caea7364f..7de922e041531 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -5691,8 +5691,10 @@ static void addAttributesForActorIsolation(ValueDecl *value, 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: { From f00d8082dbff462d0c93d2a6d7b214459c0828c2 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 10 Apr 2025 17:48:42 -0700 Subject: [PATCH 12/14] [Parse] Tighten constraints in `canParseNonisolatedAsTypeModifier` Accept it only if it's spelled `nonisolated(nonsending)` and nothing else to minimize any possible source compatibility impact. --- lib/Parse/ParseType.cpp | 18 ++++++++++-------- test/Parse/execution_behavior_attrs.swift | 7 +++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 5e16612a2e580..b2376063d9b01 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -1749,17 +1749,19 @@ bool Parser::canParseNonisolatedAsTypeModifier() { if (Tok.isAtStartOfLine()) return false; - // Always requires `(<>)` - if (!Tok.is(tok::l_paren)) + // Always requires `(nonsending)`, together + // we don't want eagerly interpret something + // like `nonisolated(0)` as a modifier. + + if (!consumeIf(tok::l_paren)) return false; - // Consume argument list - skipSingle(); + if (!Tok.isContextualKeyword("nonsending")) + return false; - // if consumed '(...)' ended up being followed - // by `[async, throws, ...] -> ...` this means - // the `nonisolated` is invalid as a modifier. - return !isAtFunctionTypeArrow(); + consumeToken(); + + return consumeIf(tok::r_paren); } bool Parser::canParseTypeScalar() { diff --git a/test/Parse/execution_behavior_attrs.swift b/test/Parse/execution_behavior_attrs.swift index 1c41593d124aa..6397a35b8e70e 100644 --- a/test/Parse/execution_behavior_attrs.swift +++ b/test/Parse/execution_behavior_attrs.swift @@ -77,3 +77,10 @@ do { _ = [nonisolated()] } + +do { + func nonisolated(_: Int) -> Int { 42 } + + nonisolated(0) // expected-warning {{result of call to 'nonisolated' is unused}} + print("hello") +} From 2b4ba84e64dbca8c40aea207ea7b77482bffc2b8 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 11 Apr 2025 11:56:31 -0700 Subject: [PATCH 13/14] [Diagnostics] Update educational note for `AsyncCallerExecution` feature to match `@execution` attribute split --- userdocs/diagnostics/async-caller-execution.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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`. From 734b1f1705be779def53455eb19b1d4bb9e05208 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 11 Apr 2025 15:47:47 -0700 Subject: [PATCH 14/14] [Frontend] Add a feature to guard use of `@concurrent` and `nonisolated(nonsending)` in swift interface files --- include/swift/Basic/Features.def | 1 + lib/AST/FeatureSet.cpp | 51 +++++++++++++ .../execution_behavior_attrs.swift | 72 +++++++++++++++++-- 3 files changed, 119 insertions(+), 5 deletions(-) diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index 05c6f18406854..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) diff --git a/lib/AST/FeatureSet.cpp b/lib/AST/FeatureSet.cpp index de70a31a620fc..b17039fa98489 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -502,6 +502,57 @@ static bool usesFeatureBuiltinEmplaceTypedThrows(Decl *decl) { return false; } +static bool usesFeatureAsyncExecutionBehaviorAttributes(Decl *decl) { + // Explicit `@concurrent` attribute on the declaration. + if (decl->getAttrs().hasAttribute()) + return true; + + // 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 (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 = 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 `nonisolated(nonsending)` attribute. + if (auto *PL = VD->getParameterList()) { + if (llvm::any_of(*PL, [&](const ParamDecl *P) { + return hasCallerIsolatedAttr(P->getTypeRepr()); + })) + return true; + } + + // Check if result type has explicit `nonisolated(nonsending)` attribute. + if (hasCallerIsolatedAttr(VD->getResultTypeRepr())) + return true; + + return false; +} + // ---------------------------------------------------------------------------- // MARK: - FeatureSet // ---------------------------------------------------------------------------- diff --git a/test/ModuleInterface/execution_behavior_attrs.swift b/test/ModuleInterface/execution_behavior_attrs.swift index f513d15ddf21b..b9a73348f87d2 100644 --- a/test/ModuleInterface/execution_behavior_attrs.swift +++ b/test/ModuleInterface/execution_behavior_attrs.swift @@ -6,22 +6,58 @@ // REQUIRES: concurrency public struct Test { - // CHECK: nonisolated(nonsending) public init() async + // CHECK: #if compiler(>=5.3) && $AsyncExecutionBehaviorAttributes + // CHECK-NEXT: nonisolated(nonsending) public init() async + // CHECK-NEXT: #endif nonisolated(nonsending) public init() async { } - // CHECK: @concurrent public func test() 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: public func other(_: nonisolated(nonsending) () async -> Swift.Void) + // 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: nonisolated(nonsending) public var testOnVar: Swift.Int { + // 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 { @@ -29,14 +65,40 @@ public struct Test { } } - // CHECK: nonisolated(nonsending) public subscript(onSubscript _: Swift.Int) -> Swift.Bool { + // 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 + } + } }