From cd9741507b23f7946bff290b53e1c9652578d4db Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 1 Apr 2025 15:21:03 -0700 Subject: [PATCH 01/15] [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 604ee08627678..da60477f14a7e 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8513,40 +8513,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 d7f2b76851f37..0c03ae8cbe714 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; } } @@ -8161,7 +8163,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(); } @@ -8170,8 +8172,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(); } @@ -8181,7 +8183,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 3483e6d3c33e7..33650a204e40d 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -4204,7 +4204,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()) { @@ -4214,20 +4215,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 8598ec670dcfa4ceb9739252ba3d70a630ec298b Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 1 Apr 2025 16:51:57 -0700 Subject: [PATCH 02/15] [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 654d9cf221688..a5d7de47f65c0 100644 --- a/include/swift/AST/DeclAttr.def +++ b/include/swift/AST/DeclAttr.def @@ -879,7 +879,13 @@ SIMPLE_DECL_ATTR(constInitialized, ConstInitialized, 168) DECL_ATTR_FEATURE_REQUIREMENT(ConstInitialized, CompileTimeValues) -LAST_DECL_ATTR(ConstInitialized) +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 19b8d407b9401..0c30759982538 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -4925,6 +4925,7 @@ class PrintAttribute : public AttributeVisitor, TRIVIAL_ATTR_PRINTER(Used, used) TRIVIAL_ATTR_PRINTER(WarnUnqualifiedAccess, warn_unqualified_access) TRIVIAL_ATTR_PRINTER(WeakLinked, weak_linked) + TRIVIAL_ATTR_PRINTER(Concurrent, concurrent) #undef TRIVIAL_ATTR_PRINTER diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 16a63d977f9cd..27b1b550eb5f0 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -8757,6 +8757,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 87c59a0d786c5..3b4cb1008c3b8 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -511,6 +511,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 bc91febfee879..de3ea48e991e3 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 c0c3ffba9a8b6..b163d1fb3b5c0 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 0c03ae8cbe714..1b6e05184dc07 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); @@ -243,6 +243,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(); @@ -4317,6 +4333,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; @@ -4331,7 +4348,9 @@ static void checkGlobalActorAttr( if (executionAttr) { attributes.push_back(executionAttr); } - + if (concurrentAttr) { + attributes.push_back(concurrentAttr); + } if (attributes.size() == 1) return; @@ -8152,13 +8171,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 @@ -8191,6 +8210,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 7dea9c2053e10..69946c2d728de 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4903,6 +4903,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) { @@ -4914,11 +4915,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); @@ -4943,6 +4947,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 85a113951a1e4..2efc125128a44 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1593,6 +1593,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 0be4d380df55f..c4297f41d86ae 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 = 934; // custom AvailabilityDomains +const uint16_t SWIFTMODULE_VERSION_MINOR = 935; // @concurrent attribute /// A standard hash seed used for all string hashes in a serialized module. /// From 7c6ec33400e565dbf75ade4030fc3dd1d9e3f110 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 1 Apr 2025 16:53:51 -0700 Subject: [PATCH 03/15] [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 4429477f708ee..a21bf7109251d 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 873f562a4a6f1c708fd43c2383c7fc6b191e4c14 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 1 Apr 2025 17:57:13 -0700 Subject: [PATCH 04/15] [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 33650a204e40d..a558f17a5b7f1 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -4201,11 +4201,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()) { @@ -4214,29 +4214,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()) { @@ -4248,6 +4252,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 4a973f7b4b434adcf2e42dc0240a08506f1960cf Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 2 Apr 2025 15:31:03 -0700 Subject: [PATCH 05/15] [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 0c30759982538..fcb015ee44313 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 27b1b550eb5f0..16a63d977f9cd 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -8757,9 +8757,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 de3ea48e991e3..1077f5642b06d 100644 --- a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift @@ -370,7 +370,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 a21bf7109251d..7cebe4bce6f57 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 79ecf9f2b1c89..43ab6f9c142e0 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 = getFeatureName(feature); 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 69946c2d728de..da126b2fdc7ab 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4940,8 +4940,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 a558f17a5b7f1..69c729ef052ea 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -4244,9 +4244,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 effaa641cc9b7..2aac83d417e4e 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 d8c64c1ff03820d001925da28ef64d425a29c625 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 4 Apr 2025 09:20:08 -0700 Subject: [PATCH 06/15] [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 9f6d49eb6bf36..3a8247336aae0 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 da60477f14a7e..f0b1c49de1361 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8514,11 +8514,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, @@ -8526,21 +8531,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 fcb015ee44313..bddee814fe2d0 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); } @@ -5182,6 +5184,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 16a63d977f9cd..553e2587a6f16 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -8757,6 +8757,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 1077f5642b06d..3a4d26d33c0e9 100644 --- a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift @@ -1415,27 +1415,25 @@ extension ASTGenVisitor { // FIXME: This is a decl modifier func generateNonisolatedAttr(attribute node: AttributeSyntax) -> BridgedNonisolatedAttr? { - let isUnsafe = self.generateSingleAttrOption( + let modifier: BridgedNonIsolatedModifier? = self.generateSingleAttrOption( attribute: node, { switch $0.rawText { - case "unsafe": - return true - default: - // FIXME: Diagnose. - return nil + case "unsafe": return .unsafe + case "nonsending": return .nonSending + default: return nil } }, - valueIfOmitted: false + valueIfOmitted: BridgedNonIsolatedModifier.none ) - guard let isUnsafe else { + guard let modifier else { return nil } return .createParsed( self.ctx, atLoc: self.generateSourceLoc(node.atSign), range: self.generateAttrSourceRange(node), - isUnsafe: isUnsafe + modifier: modifier ) } @@ -2409,12 +2407,14 @@ extension ASTGenVisitor { } func generateNonisolatedAttr(declModifier node: DeclModifierSyntax) -> BridgedNonisolatedAttr? { - let isUnsafe: Bool + let modifier: BridgedNonIsolatedModifier switch node.detail?.detail.rawText { case "unsafe": - isUnsafe = true + modifier = .unsafe + case "nonsending": + modifier = .nonSending case nil: - isUnsafe = false + modifier = .none case let text?: // TODO: Diagnose _ = text @@ -2425,7 +2425,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 7cebe4bce6f57..c70603815d7f2 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 43ab6f9c142e0..4f35b5b716607 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 1b6e05184dc07..d9e171f03d66b 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -257,6 +257,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) { @@ -7556,6 +7562,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 da126b2fdc7ab..a951b9c035917 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4951,8 +4951,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 911a654d323e3..75692e6a81624 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -6523,11 +6523,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 c4297f41d86ae..2a87b038f8b20 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 = 935; // @concurrent attribute +const uint16_t SWIFTMODULE_VERSION_MINOR = 936; // nonisolated(nonsending) /// A standard hash seed used for all string hashes in a serialized module. /// @@ -2556,7 +2556,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 f6ef02b0dde08..e6d2703695f8f 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3476,9 +3476,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 fde841704c16f37833012841b009745e996c4427 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 7 Apr 2025 16:18:40 -0700 Subject: [PATCH 07/15] [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 6d3f9b400f73b..ccf158242f1f1 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -2169,5 +2169,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 f0b1c49de1361..8f3a69512b2f8 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8510,7 +8510,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, @@ -8530,6 +8530,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", @@ -8552,14 +8564,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 bddee814fe2d0..498ce65b1c4c5 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 306145cbf9c5a..06deeead2c423 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 c70603815d7f2..81be48adaf226 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 5ac469fe59cf3..293af427066ef 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); } @@ -1728,6 +1732,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); @@ -1735,6 +1767,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 69c729ef052ea..6d1ce41e7455e 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -2327,6 +2327,8 @@ namespace { TypeResolutionOptions options); NeverNullType resolveSendingTypeRepr(SendingTypeRepr *repr, TypeResolutionOptions options); + NeverNullType resolveCallerIsolatedTypeRepr(CallerIsolatedTypeRepr *repr, + TypeResolutionOptions options); NeverNullType resolveCompileTimeLiteralTypeRepr(CompileTimeLiteralTypeRepr *repr, TypeResolutionOptions options); @@ -2733,7 +2735,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); } @@ -2756,6 +2759,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); @@ -5281,6 +5287,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) { @@ -6401,6 +6470,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker { case TypeReprKind::PackElement: case TypeReprKind::LifetimeDependent: case TypeReprKind::Integer: + case TypeReprKind::CallerIsolated: return false; } } From 06f880e65c1bdf768149a2884615cf39ada6213c Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 8 Apr 2025 18:20:23 -0700 Subject: [PATCH 08/15] [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 3a8247336aae0..a8ebd4288806b 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 @@ -4042,28 +4006,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 1a5b7ed7ec12b..bbfd1af27bef2 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -8149,8 +8149,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 a5d7de47f65c0..22e2e01472792 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 ccf158242f1f1..6f59698f0fbe4 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -1697,14 +1697,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 8f3a69512b2f8..726bd5dccecde 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8510,7 +8510,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 498ce65b1c4c5..88e67a74a01bd 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: @@ -4935,11 +4929,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")); @@ -6348,7 +6337,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 cf7f9bb5c967b..2e1b0065b3bb3 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3305,7 +3305,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(); } @@ -6500,8 +6500,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 553e2587a6f16..e97f01618a9e5 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -8755,19 +8755,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 3b4cb1008c3b8..1c411dc369dbf 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -504,17 +504,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; @@ -522,7 +520,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; }); @@ -536,12 +534,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 3a4d26d33c0e9..6e4cc53e0ff95 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: @@ -360,32 +358,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 81be48adaf226..4b420556499b6 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, - getFeatureName(Feature::ExecutionAttribute)); - 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 4f35b5b716607..77be854b30a92 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 b163d1fb3b5c0..a41b31857ef4a 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 d9e171f03d66b..5f618001f51b4 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -243,21 +243,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, @@ -4338,7 +4326,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; @@ -4351,9 +4338,6 @@ static void checkGlobalActorAttr( if (nonisolatedAttr) { attributes.push_back(nonisolatedAttr); } - if (executionAttr) { - attributes.push_back(executionAttr); - } if (concurrentAttr) { attributes.push_back(concurrentAttr); } @@ -8191,11 +8175,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()) { @@ -8229,10 +8208,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 a951b9c035917..63221f6299786 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4902,7 +4902,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. @@ -4913,16 +4912,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); @@ -4930,21 +4926,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); @@ -5719,8 +5700,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: { @@ -5913,10 +5895,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 2efc125128a44..db1751500b461 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1600,7 +1600,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 6d1ce41e7455e..3c0568cd08253 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -4245,17 +4245,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 75692e6a81624..bf39813449887 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -5932,14 +5932,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 2a87b038f8b20..a2cfa9e35c5be 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 = 936; // nonisolated(nonsending) +const uint16_t SWIFTMODULE_VERSION_MINOR = 937; // remove @execution attr /// A standard hash seed used for all string hashes in a serialized module. /// @@ -2393,11 +2393,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 e6d2703695f8f..c21bcf5bd73bc 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -2943,15 +2943,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 2aac83d417e4e..5438834e70cfd 100644 --- a/test/ModuleInterface/attrs.swift +++ b/test/ModuleInterface/attrs.swift @@ -91,6 +91,6 @@ 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 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 031d3bcc2b66bff091debecdcd1f21d5be364fba Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 9 Apr 2025 00:05:16 -0700 Subject: [PATCH 09/15] [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 ce776f90d456c..f44f694c726d3 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 9490186f7796c..ac4a9876d38f0 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 63221f6299786..a303851929216 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -2719,16 +2719,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; } @@ -2751,9 +2751,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: @@ -2769,7 +2769,7 @@ namespace { } case FunctionTypeIsolation::Kind::NonIsolated: { - // nonisolated synchronous <-> @execution(concurrent) + // nonisolated synchronous <-> @concurrent if (fromFnType->isAsync() != toFnType->isAsync()) { diagnoseNonSendableParametersAndResult( toFnType, /*downgradeToWarning=*/true); @@ -2791,10 +2791,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 3c0568cd08253..c3cd5160b1aab 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -4240,8 +4240,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 3896f8fd77a783749df597ebdb2921d140c45b4b Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 9 Apr 2025 00:25:55 -0700 Subject: [PATCH 10/15] [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 22e2e01472792..54f25db2a931c 100644 --- a/include/swift/AST/DeclAttr.def +++ b/include/swift/AST/DeclAttr.def @@ -879,7 +879,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 8c2773f282e71..bf5fcc83084e4 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -397,9 +397,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 6390946ac85d9..bfc0e09d4ec2e 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -486,10 +486,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 2e1b0065b3bb3..b830c53c2cdff 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3301,14 +3301,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 1c411dc369dbf..f823727e64185 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -503,48 +503,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 6cf7505401f2c..b7fda6f209720 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 @@ -325,6 +328,7 @@ struct _S { // ON_MEMBER_LAST-DAG: Keyword/None: freestanding[#Declaration Attribute#]; name=freestanding // 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: 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 @@ -397,6 +401,7 @@ func dummy2() {} // KEYWORD_LAST-DAG: Keyword/None: attached[#Declaration Attribute#]; name=attached // 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: 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 5438834e70cfd..543635eefb9f7 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 826176a28a59962c23046221d7d407e25076ff2a Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 10 Apr 2025 16:45:56 -0700 Subject: [PATCH 11/15] [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 a8ebd4288806b..e7a3b9d88353d 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 3e69f5e470cd3..9d3f233f1b827 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -8784,8 +8784,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; } @@ -8918,8 +8917,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 1346130bdee77..69b16e0f44919 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -1743,8 +1743,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 a303851929216..9391caf61e011 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -5706,8 +5706,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 c3c5a55668c58f8fb94c78a632f64bad4bd428e5 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 10 Apr 2025 17:48:42 -0700 Subject: [PATCH 12/15] [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 293af427066ef..18cfad4d45e5e 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -1747,17 +1747,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 dafc31ae083e1235d67a0948c18837c82cf8d80a Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 11 Apr 2025 11:56:31 -0700 Subject: [PATCH 13/15] [Diagnostics] Update educational note for `AsyncCallerExecution` feature to match `@execution` attribute split --- userdocs/diagnostics/async-caller-execution.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/userdocs/diagnostics/async-caller-execution.md b/userdocs/diagnostics/async-caller-execution.md index 58e6f5fef2965..fea7c70b4b94b 100644 --- a/userdocs/diagnostics/async-caller-execution.md +++ b/userdocs/diagnostics/async-caller-execution.md @@ -3,11 +3,14 @@ Proposed in [SE-0461], this feature changes the behavior of nonisolated async functions to run on the actor to which the caller is isolated (if any) by default, and provides an explicit way to express the execution semantics for -these functions: -* The `@execution(concurrent)` attribute specifies that a function must always +these functions. + +This feature was proposed in [SE-0461](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0461-async-function-isolation.md) + +* 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 e98ba2d0bca99f788fa849d6a5fb3f0d69c08fb4 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 11 Apr 2025 15:47:47 -0700 Subject: [PATCH 14/15] [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 bfc0e09d4ec2e..cb55dbe0c9ebe 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -255,6 +255,7 @@ 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(IsolatedConformances, 470, "Global-actor isolated conformances") +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 f823727e64185..aa4fc3704b935 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -503,6 +503,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 + } + } } From c8c7eef43ea01867fc397c5b3d68448716ec5938 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 15 Apr 2025 00:08:17 -0700 Subject: [PATCH 15/15] [Docs] NFC: Remove last remaining references to `@execution` attribute (cherry picked from commit 4b1695b999171d27fad647e85ae0b3dc35827254) --- docs/ABI/Mangling.rst | 2 +- userdocs/diagnostics/sending-risks-data-race.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index 1dba89461ded3..ea37b36afc9ad 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -761,7 +761,7 @@ Types sending-result ::= 'YT' // -> sending T #endif #if SWIFT_RUNTIME_VERSION >= 6.2 - function-isolation :== 'YC' // @execution(caller) on function type + function-isolation :== 'YC' // nonisolated(nonsending) on function type #endif differentiable ::= 'Yjf' // @differentiable(_forward) on function type differentiable ::= 'Yjr' // @differentiable(reverse) on function type diff --git a/userdocs/diagnostics/sending-risks-data-race.md b/userdocs/diagnostics/sending-risks-data-race.md index 2f7d65c187e53..2e6247b05756e 100644 --- a/userdocs/diagnostics/sending-risks-data-race.md +++ b/userdocs/diagnostics/sending-risks-data-race.md @@ -29,13 +29,13 @@ await person.printNameConcurrently() This happens because the `printNameConcurrently` function runs off of the main actor, and the `onMainActor` function suspends while waiting for `printNameConcurrently` to complete. While suspended, the main actor can run other tasks that still have access to `person`, which can lead to a data race. -The most common fix is to change the `async` method to run on the caller's actor using the `@execution(caller)` attribute: +The most common fix is to change the `async` method to run on the caller's actor using the `nonisolated(nonsending)` specifier: ```swift class Person { var name: String = "" - @execution(caller) + nonisolated(nonsending) func printNameConcurrently() async { print(name) } @@ -49,4 +49,4 @@ func onMainActor(person: Person) async { This eliminates the risk of data-races because `printNameConcurrently` continues to run on the main actor, so all access to `person` is serialized. -You can also enable the `AsyncCallerExecution` upcoming feature to make `@execution(caller)` the default for async functions on non-`Sendable` types. \ No newline at end of file +You can also enable the `AsyncCallerExecution` upcoming feature to make `nonisolated(nonsending)` the default for async functions on non-`Sendable` types.