From 4e663f1795c09f6fe853d7516948476521932dda Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Sun, 30 Mar 2025 23:09:51 +0100 Subject: [PATCH 1/4] Sema: Fix isolation source when inferring from type context --- lib/Sema/TypeCheckConcurrency.cpp | 17 +++++++++++------ .../actor_call_implicitly_async.swift | 1 + test/Concurrency/actor_isolation.swift | 14 +++++++++++--- test/Concurrency/actor_isolation_unsafe.swift | 2 ++ test/Concurrency/global_actor_inference.swift | 12 +++++++++--- .../isolated_default_arguments.swift | 2 ++ test/Concurrency/objc_async_overload.swift | 1 + .../preconcurrency_conformances.swift | 3 ++- test/Concurrency/predates_concurrency.swift | 4 ++++ .../predates_concurrency_swift6.swift | 1 + 10 files changed, 44 insertions(+), 13 deletions(-) diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 019c98dbc7f32..b6c0903887dbb 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -6174,10 +6174,8 @@ static InferredActorIsolation computeActorIsolation(Evaluator &evaluator, // attributes, use that. if (auto ext = dyn_cast(value->getDeclContext())) { if (auto isolationFromAttr = getIsolationFromAttributes(ext)) { - return { - inferredIsolation(*isolationFromAttr, onlyGlobal), - IsolationSource(ext, IsolationSource::Explicit) - }; + return {inferredIsolation(*isolationFromAttr, onlyGlobal), + IsolationSource(ext, IsolationSource::LexicalContext)}; } } @@ -6197,8 +6195,15 @@ static InferredActorIsolation computeActorIsolation(Evaluator &evaluator, isolation = ActorIsolation::forCallerIsolationInheriting(); } - return {inferredIsolation(isolation, onlyGlobal), - selfTypeIsolation.source}; + // If the type context has explicit isolation, this one is inferred from + // context. + auto isolationSource = selfTypeIsolation.source; + if (isolationSource.kind == IsolationSource::Explicit) { + isolationSource = + IsolationSource(selfTypeDecl, IsolationSource::LexicalContext); + } + + return {inferredIsolation(isolation, onlyGlobal), isolationSource}; } } } diff --git a/test/Concurrency/actor_call_implicitly_async.swift b/test/Concurrency/actor_call_implicitly_async.swift index 6c79a12a0e994..59b00d3759775 100644 --- a/test/Concurrency/actor_call_implicitly_async.swift +++ b/test/Concurrency/actor_call_implicitly_async.swift @@ -571,6 +571,7 @@ func tryTheActorSubscripts(a : SubscriptA, t : SubscriptT, at : SubscriptAT) asy @MainActor final class IsolatedOperator: @preconcurrency Equatable { + // expected-note@+1 {{main actor isolation inferred from enclosing context}} static func == (lhs: IsolatedOperator, rhs: IsolatedOperator) -> Bool { lhs.num == rhs.num } diff --git a/test/Concurrency/actor_isolation.swift b/test/Concurrency/actor_isolation.swift index 19e1adf9c5945..aa06616434d0e 100644 --- a/test/Concurrency/actor_isolation.swift +++ b/test/Concurrency/actor_isolation.swift @@ -867,7 +867,9 @@ actor LazyActor { class SomeClassInActor { enum ID: String { case best } - func inActor() { } // expected-note{{calls to instance method 'inActor()' from outside of its actor context are implicitly asynchronous}} + func inActor() { } + // expected-note@-1 {{calls to instance method 'inActor()' from outside of its actor context are implicitly asynchronous}} + // expected-note@-2 {{main actor isolation inferred from enclosing context}} } @available(SwiftStdlib 5.1, *) @@ -1029,7 +1031,9 @@ class SomeClassWithInits { static var shared = SomeClassWithInits() // expected-note 2{{static property declared here}} - init() { // expected-note{{calls to initializer 'init()' from outside of its actor context are implicitly asynchronous}} + init() { + // expected-note@-1 {{calls to initializer 'init()' from outside of its actor context are implicitly asynchronous}} + // expected-note@-2 {{main actor isolation inferred from enclosing context}} self.mutableState = 42 self.otherMutableState = 17 @@ -1043,8 +1047,11 @@ class SomeClassWithInits { } func isolated() { } + // expected-note@-1 {{main actor isolation inferred from enclosing context}} - static func staticIsolated() { // expected-note{{calls to static method 'staticIsolated()' from outside of its actor context are implicitly asynchronous}} + static func staticIsolated() { + // expected-note@-1 {{calls to static method 'staticIsolated()' from outside of its actor context are implicitly asynchronous}} + // expected-note@-2 {{main actor isolation inferred from enclosing context}} _ = SomeClassWithInits.shared } @@ -1482,6 +1489,7 @@ final class MainActorInit: Sendable { } func f() {} + // expected-note@-1 3 {{main actor isolation inferred from enclosing context}} } actor DunkTracker { diff --git a/test/Concurrency/actor_isolation_unsafe.swift b/test/Concurrency/actor_isolation_unsafe.swift index b026c2720509b..ffdf61eecea45 100644 --- a/test/Concurrency/actor_isolation_unsafe.swift +++ b/test/Concurrency/actor_isolation_unsafe.swift @@ -59,6 +59,8 @@ struct S4_P1: P1 { protocol P2 { func f() // expected-note{{calls to instance method 'f()' from outside of its actor context are implicitly asynchronous}} // expected-complete-tns-note @-1 {{calls to instance method 'f()' from outside of its actor context are implicitly asynchronous}} + // expected-complete-tns-note@-2 {{main actor isolation inferred from enclosing context}} + // expected-note@-3 {{main actor isolation inferred from enclosing context}} nonisolated func g() } diff --git a/test/Concurrency/global_actor_inference.swift b/test/Concurrency/global_actor_inference.swift index 25411b6864c96..4c0bb34d55433 100644 --- a/test/Concurrency/global_actor_inference.swift +++ b/test/Concurrency/global_actor_inference.swift @@ -137,11 +137,15 @@ class Object: Interface { // Global actor inference for classes and extensions // ---------------------------------------------------------------------- @SomeGlobalActor class C3 { - func method1() { } // expected-note {{calls to instance method 'method1()' from outside of its actor context are implicitly asynchronous}} + func method1() { } + // expected-note@-1 {{calls to instance method 'method1()' from outside of its actor context are implicitly asynchronous}} + // expected-note@-2 {{global actor 'SomeGlobalActor' isolation inferred from enclosing context}} } extension C3 { - func method2() { } // expected-note {{calls to instance method 'method2()' from outside of its actor context are implicitly asynchronous}} + func method2() { } + // expected-note@-1 {{calls to instance method 'method2()' from outside of its actor context are implicitly asynchronous}} + // expected-note@-2 {{global actor 'SomeGlobalActor' isolation inferred from enclosing context}} } class C4: C3 { @@ -159,7 +163,9 @@ class C5 { } @SomeGlobalActor extension C5 { - func method2() { } // expected-note {{calls to instance method 'method2()' from outside of its actor context are implicitly asynchronous}} + func method2() { } + // expected-note@-1 {{calls to instance method 'method2()' from outside of its actor context are implicitly asynchronous}} + // expected-note@-2 {{global actor 'SomeGlobalActor' isolation inferred from enclosing context}} } @OtherGlobalActor func testGlobalActorInference(c3: C3, c4: C4, c5: C5) { diff --git a/test/Concurrency/isolated_default_arguments.swift b/test/Concurrency/isolated_default_arguments.swift index a5c07d7beb4d9..74fe542277ef4 100644 --- a/test/Concurrency/isolated_default_arguments.swift +++ b/test/Concurrency/isolated_default_arguments.swift @@ -123,6 +123,7 @@ func closureWithIsolatedParam( } ) {} +// expected-note@+3 3 {{main actor isolation inferred from enclosing context}} // expected-note@+2 3 {{calls to initializer 'init(required:x:y:)' from outside of its actor context are implicitly asynchronous}} @MainActor struct S1 { @@ -135,6 +136,7 @@ struct S1 { static var z: Int = requiresMainActor() } +// expected-note@+3 3 {{global actor 'SomeGlobalActor' isolation inferred from enclosing context}} // expected-note@+2 3 {{calls to initializer 'init(required:x:y:)' from outside of its actor context are implicitly asynchronous}} @SomeGlobalActor struct S2 { diff --git a/test/Concurrency/objc_async_overload.swift b/test/Concurrency/objc_async_overload.swift index 78a99a7a42e37..6997762c138e3 100644 --- a/test/Concurrency/objc_async_overload.swift +++ b/test/Concurrency/objc_async_overload.swift @@ -54,6 +54,7 @@ extension Delegate { @MainActor class C { func finish() { } // expected-note@-1 {{calls to instance method 'finish()' from outside of its actor context are implicitly asynchronous}} + // expected-note@-2 {{main actor isolation inferred from enclosing context}} func handle(_ req: Request, with delegate: Delegate) { delegate.makeRequest1(req) { diff --git a/test/Concurrency/preconcurrency_conformances.swift b/test/Concurrency/preconcurrency_conformances.swift index 6b2a397123217..389c140755392 100644 --- a/test/Concurrency/preconcurrency_conformances.swift +++ b/test/Concurrency/preconcurrency_conformances.swift @@ -50,7 +50,8 @@ struct Value : @preconcurrency TestSendability { // expected-note@-1 2 {{property declared here}} func test(_: NonSendable?) -> [NonSendable] { - // expected-note@-1 2 {{calls to instance method 'test' from outside of its actor context are implicitly asynchronous}} + // expected-note@-1 2 {{calls to instance method 'test' from outside of its actor context are implicitly asynchronous}} + // expected-note@-2 2 {{main actor isolation inferred from enclosing context}} [] } } diff --git a/test/Concurrency/predates_concurrency.swift b/test/Concurrency/predates_concurrency.swift index 545ece6378488..4e2adf0db576a 100644 --- a/test/Concurrency/predates_concurrency.swift +++ b/test/Concurrency/predates_concurrency.swift @@ -73,11 +73,14 @@ func testElsewhere(x: X) { // expected-complete-tns-note @-1 {{calls to global function 'onMainActorAlways()' from outside of its actor context are implicitly asynchronous}} @preconcurrency @MainActor class MyModelClass { +// expected-expected-minimal-targeted-note@-1 {{main actor isolation inferred from enclosing context}} // default init() is 'nonisolated' in '-strict-concurrency=complete' func f() { } // expected-complete-tns-note @-1 {{calls to instance method 'f()' from outside of its actor context are implicitly asynchronous}} + // expected-complete-tns-note@-2 {{main actor isolation inferred from enclosing context}} + // expected-note@-3 {{main actor isolation inferred from enclosing context}} } func testCalls(x: X) { @@ -238,6 +241,7 @@ extension MainActorPreconcurrency: NotIsolated { func requirement() {} // expected-complete-tns-note@-1 {{main actor-isolated instance method 'requirement()' cannot satisfy nonisolated requirement}} // expected-complete-tns-note@-2 {{calls to instance method 'requirement()' from outside of its actor context are implicitly asynchronous}} + // expected-complete-tns-note@-3 {{main actor isolation inferred from enclosing context}} class Nested { diff --git a/test/Concurrency/predates_concurrency_swift6.swift b/test/Concurrency/predates_concurrency_swift6.swift index be5919eec051a..ff62f7f0483e5 100644 --- a/test/Concurrency/predates_concurrency_swift6.swift +++ b/test/Concurrency/predates_concurrency_swift6.swift @@ -59,6 +59,7 @@ func testElsewhere(x: X) { @preconcurrency @MainActor class MyModelClass { func f() { } // expected-note@-1{{are implicitly asynchronous}} + // expected-note@-2 2 {{main actor isolation inferred from enclosing context}} } func testCalls(x: X) { From f297d7e88ebc33bdc23a2c2571b89d681e58ca1f Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 28 Mar 2025 03:13:44 +0000 Subject: [PATCH 2/4] Sema: Ban global actor on getters in a future lang mode Global actor attributes were hitherto allowed on getters and (until Swift 6) other accessors, but intendedly ignored in favor of the enclosing `var` or `subscript` declaration's isolation when accessing the storage declaration. This change deprecates the getter case as well, to become an error in the next language mode. Also do a better job at suggesting to move the attribute to the storage: * Tighten up the condition for when the attr is legal on the storage. * Don't suggest if the storage already specifies some kind of explicit isolation. * Highlight the attr. * Also remove the attr from the accessor. --- lib/Sema/TypeCheckConcurrency.cpp | 123 +++++----- test/attr/global_actor/Inputs/accessors.swift | 228 ++++++++++++++++++ .../Inputs/accessors_global_var.swift | 46 ++++ .../accessors_global_actor_conflict.swift | 40 +++ .../accessors_global_var_swift5.swift | 3 + .../accessors_global_var_swift6.swift | 3 + .../accessors_global_var_swift7.swift | 4 + test/attr/global_actor/accessors_swift5.swift | 3 + test/attr/global_actor/accessors_swift6.swift | 3 + test/attr/global_actor/accessors_swift7.swift | 4 + .../{ => global_actor}/global_actor.swift | 71 +----- test/attr/global_actor/storage_invalid.swift | 29 +++ test/attr/global_actor/storage_valid.swift | 30 +++ 13 files changed, 451 insertions(+), 136 deletions(-) create mode 100644 test/attr/global_actor/Inputs/accessors.swift create mode 100644 test/attr/global_actor/Inputs/accessors_global_var.swift create mode 100644 test/attr/global_actor/accessors_global_actor_conflict.swift create mode 100644 test/attr/global_actor/accessors_global_var_swift5.swift create mode 100644 test/attr/global_actor/accessors_global_var_swift6.swift create mode 100644 test/attr/global_actor/accessors_global_var_swift7.swift create mode 100644 test/attr/global_actor/accessors_swift5.swift create mode 100644 test/attr/global_actor/accessors_swift6.swift create mode 100644 test/attr/global_actor/accessors_swift7.swift rename test/attr/{ => global_actor}/global_actor.swift (71%) create mode 100644 test/attr/global_actor/storage_invalid.swift create mode 100644 test/attr/global_actor/storage_valid.swift diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index b6c0903887dbb..cd5dce3e5f568 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -402,27 +402,10 @@ GlobalActorAttributeRequest::evaluate( if (decl->getDeclContext()->getParentSourceFile() == nullptr) return result; - auto isStoredInstancePropertyOfStruct = [](VarDecl *var) { - if (var->isStatic() || !var->isOrdinaryStoredProperty()) - return false; - - auto *nominal = var->getDeclContext()->getSelfNominalTypeDecl(); - return isa_and_nonnull(nominal) && - !isWrappedValueOfPropWrapper(var); - }; + auto *const globalActorAttr = result->first; - auto globalActorAttr = result->first; - if (auto nominal = dyn_cast(decl)) { - // Nominal types are okay... - if (auto classDecl = dyn_cast(nominal)){ - if (classDecl->isActor()) { - // ... except for actors. - nominal->diagnose(diag::global_actor_on_actor_class, nominal->getName()) - .highlight(globalActorAttr->getRangeWithAt()); - return std::nullopt; - } - } - } else if (auto storage = dyn_cast(decl)) { + const auto isGlobalActorAnErrorOnStorage = [&](AbstractStorageDecl *storage, + bool diagnose) { // Subscripts and properties are fine... if (auto var = dyn_cast(storage)) { @@ -431,65 +414,73 @@ GlobalActorAttributeRequest::evaluate( (var->getDeclContext()->isAsyncContext() || var->getASTContext().LangOpts.StrictConcurrencyLevel >= StrictConcurrency::Complete)) { - var->diagnose(diag::global_actor_top_level_var) - .highlight(globalActorAttr->getRangeWithAt()); - return std::nullopt; + if (diagnose) { + var->diagnose(diag::global_actor_top_level_var) + .highlight(globalActorAttr->getRangeWithAt()); + } + return true; } // ... and not if it's local property if (var->getDeclContext()->isLocalContext()) { - var->diagnose(diag::global_actor_on_local_variable, var->getName()) + if (diagnose) { + var->diagnose(diag::global_actor_on_local_variable, var->getName()) + .highlight(globalActorAttr->getRangeWithAt()); + } + return true; + } + } + + return false; + }; + + if (auto nominal = dyn_cast(decl)) { + // Nominal types are okay... + if (auto classDecl = dyn_cast(nominal)) { + if (classDecl->isActor()) { + // ... except for actors. + nominal->diagnose(diag::global_actor_on_actor_class, nominal->getName()) .highlight(globalActorAttr->getRangeWithAt()); return std::nullopt; } } - } else if (isa(decl)) { - // Extensions are okay. - } else if (isa(decl) || isa(decl) || - isa(decl)) { - // None of the accessors/addressors besides a getter are allowed - // to have a global actor attribute. - if (auto *accessor = dyn_cast(decl)) { - if (!accessor->isGetter()) { - decl->diagnose(diag::global_actor_disallowed, decl) - .warnUntilSwiftVersion(6) - .fixItRemove(globalActorAttr->getRangeWithAt()); - - auto &ctx = decl->getASTContext(); - auto *storage = accessor->getStorage(); - // Let's suggest to move the attribute to the storage if - // this is an accessor/addressor of a property of subscript. - if (storage->getDeclContext()->isTypeContext()) { - auto canMoveAttr = [&]() { - // If enclosing declaration has a global actor, - // skip the suggestion. - if (storage->getGlobalActorAttr()) - return false; - - // Global actor attribute cannot be applied to - // an instance stored property of a struct. - if (auto *var = dyn_cast(storage)) { - return !isStoredInstancePropertyOfStruct(var); - } + } else if (auto storage = dyn_cast(decl)) { + if (isGlobalActorAnErrorOnStorage(storage, /*diagnose=*/true)) { + return std::nullopt; + } + } else if (auto *accessor = dyn_cast(decl)) { + auto &ctx = accessor->getASTContext(); + const auto attrRange = globalActorAttr->getRangeWithAt(); + const unsigned langModeForError = accessor->isGetter() ? 7 : 6; - return true; - }; + // Complain about a global actor attribute on an accessor. + accessor->diagnose(diag::global_actor_disallowed, decl) + .highlight(attrRange) + .warnUntilSwiftVersion(langModeForError); - if (canMoveAttr()) { - decl->diagnose(diag::move_global_actor_attr_to_storage_decl, - storage) - .fixItInsert( - storage->getAttributeInsertionLoc(/*forModifier=*/false), - llvm::Twine("@", result->second->getNameStr()).str()); - } - } + auto *storage = accessor->getStorage(); - // In Swift 6, once the diag above is an error, it is disallowed. - if (ctx.isSwiftVersionAtLeast(6)) - return std::nullopt; + // Suggest to move the attribute to the storage if it is legal and the + // storage does not specify some kind of explicit isolation. + if (!isGlobalActorAnErrorOnStorage(storage, /*diagnose=*/false)) { + auto storageIsolation = getInferredActorIsolation(storage); + if (storageIsolation.source.kind != IsolationSource::Explicit) { + accessor + ->diagnose(diag::move_global_actor_attr_to_storage_decl, storage) + .highlight(attrRange) + .fixItRemove(attrRange) + .fixItInsertAttribute(storage->getAttributeInsertionLoc( + globalActorAttr->isDeclModifier()), + globalActorAttr); } } - // Functions are okay. + + // Fail if we emitted an error. + if (ctx.isSwiftVersionAtLeast(langModeForError)) + return std::nullopt; + + } else if (isa(decl) || isa(decl)) { + // Other functions and extensions are okay. } else { // Everything else is disallowed. decl->diagnose(diag::global_actor_disallowed, decl); diff --git a/test/attr/global_actor/Inputs/accessors.swift b/test/attr/global_actor/Inputs/accessors.swift new file mode 100644 index 0000000000000..d535494fa7fe4 --- /dev/null +++ b/test/attr/global_actor/Inputs/accessors.swift @@ -0,0 +1,228 @@ +actor SomeActor {} + +@globalActor +struct GA1 { + static let shared = SomeActor() +} + +@globalActor +struct GA2 { + static let shared = SomeActor() +} + +@globalActor +struct GenericGlobalActor { + static var shared: SomeActor { SomeActor() } +} + +// Global actor on top-level var accessors. No fix-it in Swift 6+: global actor +// not allowed on top-level var under complete strict concurrency. + +var topLevelObserved: Int = 0 { + @GA1 willSet {} + // expected-swift6+-error@-1:8 {{willSet observer cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:8 {{willSet observer cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-swift5-note@-3:8 {{move global actor attribute to var 'topLevelObserved'}}{{3-8=}}{{-1:1-1=@GA1 }}{{none}} + @GA1 didSet {} + // expected-swift6+-error@-1:8 {{didSet observer cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:8 {{didSet observer cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-swift5-note@-3:8 {{move global actor attribute to var 'topLevelObserved'}}{{3-8=}}{{-5:1-1=@GA1 }}{{none}} +} + +var topLevelComputed: Int { + @GA1 get {} + // expected-swift7-error@-1:8 {{getter cannot have a global actor}}{{none}} + // expected-swift6-warning@-2:8 {{getter cannot have a global actor; this will be an error in a future Swift language mode}}{{none}} + // expected-swift5-warning@-3:8 {{getter cannot have a global actor; this will be an error in a future Swift language mode}}{{none}} + // expected-swift5-note@-4:8 {{move global actor attribute to var 'topLevelComputed'}}{{3-8=}}{{-1:1-1=@GA1 }}{{none}} + @GA1 set {} + // expected-swift6+-error@-1:8 {{setter cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:8 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-swift5-note@-3:8 {{move global actor attribute to var 'topLevelComputed'}}{{3-8=}}{{-6:1-1=@GA1 }}{{none}} + @GA1 _modify {} + // expected-swift6+-error@-1:8 {{_modify accessor cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:8 {{_modify accessor cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-swift5-note@-3:8 {{move global actor attribute to var 'topLevelComputed'}}{{3-8=}}{{-10:1-1=@GA1 }}{{none}} +} + +var topLevelComputedRead: Int { + @GA1 _read {} + // expected-swift6+-error@-1:8 {{_read accessor cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:8 {{_read accessor cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-swift5-note@-3:8 {{move global actor attribute to var 'topLevelComputedRead'}}{{3-8=}}{{-1:1-1=@GA1 }}{{none}} +} + +// Global actor on local var accessors. No fix-it: global actor on local var is +// not allowed. +do { + var observed: Int = 0 { + @GA1 willSet {} + // expected-swift6+-error@-1:10 {{willSet observer cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:10 {{willSet observer cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + @GA1 didSet {} + // expected-swift6+-error@-1:10 {{didSet observer cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:10 {{didSet observer cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + } + observed = 0 + let _ = observed + + var computed: Int { + @GA1 get {} + // expected-swift7-error@-1:10 {{getter cannot have a global actor}}{{none}} + // expected-swift6-warning@-2:10 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} + // expected-swift5-warning@-3:10 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} + @GA1 set {} + // expected-swift6+-error@-1:10 {{setter cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:10 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + @GA1 _modify {} + // expected-swift6+-error@-1:10 {{_modify accessor cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:10 {{_modify accessor cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + } + + var computedRead: Int { + @GA1 _read {} + // expected-swift6+-error@-1:10 {{_read accessor cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:10 {{_read accessor cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + } +} + +// Global actor on property/subscript accessors. +do { + @GA1 struct S { + var observed: Int { + @GA1 willSet {} + // expected-swift6+-error@-1:12 {{willSet observer cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:12 {{willSet observer cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-note@-3:12 {{move global actor attribute to property 'observed'}}{{7-12=}}{{-1:5-5=@GA1 }}{{none}} + @GA1 didSet {} + // expected-swift6+-error@-1:12 {{didSet observer cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:12 {{didSet observer cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-note@-3:12 {{move global actor attribute to property 'observed'}}{{7-12=}}{{-5:5-5=@GA1 }}{{none}} + } + + var computed: Int { + @GA1 get {} + // expected-swift7-error@-1:12 {{getter cannot have a global actor}}{{none}} + // expected-swift6-warning@-2:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} + // expected-swift5-warning@-3:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} + // expected-note@-4:12 {{move global actor attribute to property 'computed'}}{{7-12=}}{{-1:5-5=@GA1 }}{{none}} + @GA1 set {} + // expected-swift6+-error@-1:12 {{setter cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:12 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-note@-3:12 {{move global actor attribute to property 'computed'}}{{7-12=}}{{-6:5-5=@GA1 }}{{none}} + @GA1 _modify {} + // expected-swift6+-error@-1:12 {{_modify accessor cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:12 {{_modify accessor cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-note@-3:12 {{move global actor attribute to property 'computed'}}{{7-12=}}{{-10:5-5=@GA1 }}{{none}} + @GA1 init {} + // expected-swift6+-error@-1:12 {{init accessor cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:12 {{init accessor cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-note@-3:12 {{move global actor attribute to property 'computed'}}{{7-12=}}{{-14:5-5=@GA1 }}{{none}} + } + + subscript(subscript _: Int) -> Int { + @GA1 get {} + // expected-swift7-error@-1:12 {{getter cannot have a global actor}}{{none}} + // expected-swift6-warning@-2:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} + // expected-swift5-warning@-3:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} + // expected-note@-4:12 {{move global actor attribute to subscript 'subscript(subscript:)'}}{{7-12=}}{{-1:5-5=@GA1 }}{{none}} + @GA1 set {} + // expected-swift6+-error@-1:12 {{setter cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:12 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-note@-3:12 {{move global actor attribute to subscript 'subscript(subscript:)'}}{{7-12=}}{{-6:5-5=@GA1 }}{{none}} + @GA1 _modify {} + // expected-swift6+-error@-1:12 {{_modify accessor cannot have a global actor}} + // expected-swift5-warning@-2:12 {{_modify accessor cannot have a global actor; this is an error in the Swift 6 language mode}} + // expected-note@-3:12 {{move global actor attribute to subscript 'subscript(subscript:)'}}{{7-12=}}{{-10:5-5=@GA1 }}{{none}} + } + + var computedRead: Int { + @GA1 _read {} + // expected-swift6+-error@-1:12 {{_read accessor cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:12 {{_read accessor cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-note@-3:12 {{move global actor attribute to property 'computedRead'}}{{7-12=}}{{-1:5-5=@GA1 }}{{none}} + } + + subscript(subscriptRead _: Int) -> Int { + @GA1 _read {} + // expected-swift6+-error@-1:12 {{_read accessor cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:12 {{_read accessor cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-note@-3:12 {{move global actor attribute to subscript 'subscript(subscriptRead:)'}}{{7-12=}}{{-1:5-5=@GA1 }}{{none}} + } + + // No fix-it: storage explicitly isolated. + @GA1 var computedIsolated: Int { + @GA2 set {} + // expected-swift6+-error@-1:12 {{setter cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:12 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + get {} + } + + // No fix-it: storage explicitly isolated. + @GA1 subscript(subscriptIsolated _: Int) -> Int { + @GA1 set {} + // expected-swift6+-error@-1:12 {{setter cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:12 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + get {} + } + + // No fix-it: storage explicitly isolated. + nonisolated var computedNonisolated: Int { + @GA1 set {} + // expected-swift6+-error@-1:12 {{setter cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:12 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + get {} + } + + // No fix-it: storage explicitly isolated. + nonisolated subscript(subscriptNonisolated _: Int) -> Int { + @GA1 set {} + // expected-swift6+-error@-1:12 {{setter cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:12 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + get {} + } + } +} + +// Global actor on protocol requirement accessors. +do { + @GA1 protocol P { + var property: Int { + @GA1 get + // expected-swift7-error@-1:12 {{getter cannot have a global actor}}{{none}} + // expected-swift6-warning@-2:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} + // expected-swift5-warning@-3:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} + // expected-note@-4:12 {{move global actor attribute to property 'property'}}{{7-12=}}{{-1:5-5=@GA1 }}{{none}} + @GA1 set + // expected-swift6+-error@-1:12 {{setter cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:12 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-note@-3:12 {{move global actor attribute to property 'property'}}{{7-12=}}{{-6:5-5=@GA1 }}{{none}} + } + + subscript(_: Int) -> Int { + @GA1 get + // expected-swift7-error@-1:12 {{getter cannot have a global actor}}{{none}} + // expected-swift6-warning@-2:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} + // expected-swift5-warning@-3:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} + // expected-note@-4:12 {{move global actor attribute to subscript 'subscript(_:)'}}{{7-12=}}{{-1:5-5=@GA1 }}{{none}} + @GA1 set + // expected-swift6+-error@-1:12 {{setter cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:12 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-note@-3:12 {{move global actor attribute to subscript 'subscript(_:)'}}{{7-12=}}{{-6:5-5=@GA1 }}{{none}} + } + } +} + +// Test fix-it with generic actor. +do { + @GenericGlobalActor struct S { + var property: Int { + @GenericGlobalActor set {} + // expected-swift6+-error@-1:32 {{setter cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:32 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-note@-3:32 {{move global actor attribute to property 'property'}}{{7-32=}}{{-1:5-5=@GenericGlobalActor }}{{none}} + get {} + } + } +} + diff --git a/test/attr/global_actor/Inputs/accessors_global_var.swift b/test/attr/global_actor/Inputs/accessors_global_var.swift new file mode 100644 index 0000000000000..3dbe31b4fe852 --- /dev/null +++ b/test/attr/global_actor/Inputs/accessors_global_var.swift @@ -0,0 +1,46 @@ +actor SomeActor {} + +@globalActor +struct GA1 { + static let shared = SomeActor() +} + +// Global actor on global var accessors. + +// expected-swift6+-error@+4 {{not concurrency-safe}} +// expected-swift6+-note@+3 {{disable concurrency-safety}} +// expected-swift6+-note@+2 {{add '@MainActor'}} +// expected-swift6+-note@+1 {{convert 'globalObserved' to a 'let'}} +var globalObserved: Int = 0 { + @GA1 willSet {} + // expected-swift6+-error@-1:8 {{willSet observer cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:8 {{willSet observer cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-note@-3:8 {{move global actor attribute to var 'globalObserved'}}{{3-8=}}{{-1:1-1=@GA1 }}{{none}} + @GA1 didSet {} + // expected-swift6+-error@-1:8 {{didSet observer cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:8 {{didSet observer cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-note@-3:8 {{move global actor attribute to var 'globalObserved'}}{{3-8=}}{{-5:1-1=@GA1 }}{{none}} +} + +var globalComputed: Int { + @GA1 get {} + // expected-swift7-error@-1:8 {{getter cannot have a global actor}}{{none}} + // expected-swift6-warning@-2:8 {{getter cannot have a global actor; this will be an error in a future Swift language mode}}{{none}} + // expected-swift5-warning@-3:8 {{getter cannot have a global actor; this will be an error in a future Swift language mode}}{{none}} + // expected-note@-4:8 {{move global actor attribute to var 'globalComputed'}}{{3-8=}}{{-1:1-1=@GA1 }}{{none}} + @GA1 set {} + // expected-swift6+-error@-1:8 {{setter cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:8 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-note@-3:8 {{move global actor attribute to var 'globalComputed'}}{{3-8=}}{{-6:1-1=@GA1 }}{{none}} + @GA1 _modify {} + // expected-swift6+-error@-1:8 {{_modify accessor cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:8 {{_modify accessor cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-note@-3:8 {{move global actor attribute to var 'globalComputed'}}{{3-8=}}{{-10:1-1=@GA1 }}{{none}} +} + +var globalComputedRead: Int { + @GA1 _read {} + // expected-swift6+-error@-1:8 {{_read accessor cannot have a global actor}}{{none}} + // expected-swift5-warning@-2:8 {{_read accessor cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + // expected-note@-3:8 {{move global actor attribute to var 'globalComputedRead'}}{{3-8=}}{{-1:1-1=@GA1 }}{{none}} +} diff --git a/test/attr/global_actor/accessors_global_actor_conflict.swift b/test/attr/global_actor/accessors_global_actor_conflict.swift new file mode 100644 index 0000000000000..444ce6129c371 --- /dev/null +++ b/test/attr/global_actor/accessors_global_actor_conflict.swift @@ -0,0 +1,40 @@ +// RUN: %target-swift-frontend -typecheck -verify -swift-version 5 %s + +// REQUIRES: concurrency + +actor SomeActor {} + +@globalActor +struct GA1 { + static let shared = SomeActor() +} + +@globalActor +struct GA2 { + static let shared = SomeActor() +} + +// Global actor on local var/let accessors. No fix-it: global actor on local +// var/let is not allowed. +do { + var conflict: Int { + get {} + @GA1 @GA2 set {} + // expected-error@-1 {{declaration can not have multiple global actor attributes ('GA2' and 'GA1')}}{{none}} + // expected-warning@-2 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + } +} + +// Global actor on property/subscript accessors. +do { + struct S { + var conflict: Int { + get {} + // FIXME: The note/fix-it isn't helpful here. We should probably not treat the decl as isolated to either when there is a conflict. + // expected-note@+2 {{move global actor attribute to property 'conflict'}}{{12-17=}}{{-5:5-5=@GA2 }}{{none}} + // expected-error@+1 {{declaration can not have multiple global actor attributes ('GA2' and 'GA1')}}{{none}} + @GA1 @GA2 set {} + // expected-warning@-1 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} + } + } +} diff --git a/test/attr/global_actor/accessors_global_var_swift5.swift b/test/attr/global_actor/accessors_global_var_swift5.swift new file mode 100644 index 0000000000000..f05b6e1a3d505 --- /dev/null +++ b/test/attr/global_actor/accessors_global_var_swift5.swift @@ -0,0 +1,3 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -swift-version 5 -verify -verify-additional-prefix swift5- %S/Inputs/accessors_global_var.swift + +// REQUIRES: concurrency diff --git a/test/attr/global_actor/accessors_global_var_swift6.swift b/test/attr/global_actor/accessors_global_var_swift6.swift new file mode 100644 index 0000000000000..f98ebebd462da --- /dev/null +++ b/test/attr/global_actor/accessors_global_var_swift6.swift @@ -0,0 +1,3 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -swift-version 6 -verify -verify-additional-prefix swift6- -verify-additional-prefix swift6+- %S/Inputs/accessors_global_var.swift + +// REQUIRES: concurrency diff --git a/test/attr/global_actor/accessors_global_var_swift7.swift b/test/attr/global_actor/accessors_global_var_swift7.swift new file mode 100644 index 0000000000000..cd9e3f87baa07 --- /dev/null +++ b/test/attr/global_actor/accessors_global_var_swift7.swift @@ -0,0 +1,4 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -swift-version 7 -verify -verify-additional-prefix swift7- -verify-additional-prefix swift6+- %S/Inputs/accessors_global_var.swift + +// REQUIRES: asserts +// REQUIRES: concurrency diff --git a/test/attr/global_actor/accessors_swift5.swift b/test/attr/global_actor/accessors_swift5.swift new file mode 100644 index 0000000000000..0161fa70bf0dc --- /dev/null +++ b/test/attr/global_actor/accessors_swift5.swift @@ -0,0 +1,3 @@ +// RUN: %target-swift-frontend -typecheck -swift-version 5 -verify -verify-additional-prefix swift5- %S/Inputs/accessors.swift + +// REQUIRES: concurrency diff --git a/test/attr/global_actor/accessors_swift6.swift b/test/attr/global_actor/accessors_swift6.swift new file mode 100644 index 0000000000000..a5e1cb40e2044 --- /dev/null +++ b/test/attr/global_actor/accessors_swift6.swift @@ -0,0 +1,3 @@ +// RUN: %target-swift-frontend -typecheck -swift-version 6 -verify -verify-additional-prefix swift6- -verify-additional-prefix swift6+- %S/Inputs/accessors.swift + +// REQUIRES: concurrency diff --git a/test/attr/global_actor/accessors_swift7.swift b/test/attr/global_actor/accessors_swift7.swift new file mode 100644 index 0000000000000..520fadca17479 --- /dev/null +++ b/test/attr/global_actor/accessors_swift7.swift @@ -0,0 +1,4 @@ +// RUN: %target-swift-frontend -typecheck -swift-version 7 -verify -verify-additional-prefix swift7- -verify-additional-prefix swift6+- %S/Inputs/accessors.swift + +// REQUIRES: asserts +// REQUIRES: concurrency diff --git a/test/attr/global_actor.swift b/test/attr/global_actor/global_actor.swift similarity index 71% rename from test/attr/global_actor.swift rename to test/attr/global_actor/global_actor.swift index da21d2f257d8a..c421a67ecb424 100644 --- a/test/attr/global_actor.swift +++ b/test/attr/global_actor/global_actor.swift @@ -61,19 +61,7 @@ struct OtherGlobalActor { static let shared = SomeActor() } -@GA1 func f() { - @GA1 let x = 17 // expected-error{{local variable 'x' cannot have a global actor}} - _ = x -} - -@GA1 struct X { - @GA1 var member: Int -} - -struct Y { - @GA1 subscript(i: Int) -> Int { i } -} - +struct Y {} @GA1 extension Y { } @GA1 func g() { } @@ -149,60 +137,3 @@ public struct PublicGA { @InternalGA open class OpenClassInternalGA {} // expected-error {{open class 'OpenClassInternalGA' cannot have internal global actor 'InternalGA'}} @PackageGA open class OpenClassPackageGA {} // expected-error {{open class 'OpenClassPackageGA' cannot have package global actor 'PackageGA'}} @PublicGA open class OpenClassPublicGA {} - -// rdar://99281333 - no accessors/addressors/observers expect to 'get' are allowed to have a global actor attribute -do { - class TestInvalidAccessors { - var test1: Int { - get { 42 } - @GA1 - set { } // expected-warning {{setter cannot have a global actor}} {{-1:7-11=}} - // expected-note@-1 {{move global actor attribute to property 'test1'}} {{-3:5-5=@GA1}} - - @GA1 _modify { fatalError() } // expected-warning {{_modify accessor cannot have a global actor}} {{7-12=}} - // expected-note@-1 {{move global actor attribute to property 'test1'}} {{-6:5-5=@GA1}} - } - - func local() { - var test: Bool { - get { false } - - @GA1 - set { } // expected-warning {{setter cannot have a global actor}} - } - } - - @GA1 var testAlreadyWithGlobal: String { - get { "" } - @GA1 set { } // expected-warning {{setter cannot have a global actor}} {{7-12=}} - } - } - - struct TestStruct { - var test1: Int { - get { 42 } - @GA1 - set { } // expected-warning {{setter cannot have a global actor}} {{-1:7-11=}} - // expected-note@-1 {{move global actor attribute to property 'test1'}} {{-3:5-5=@GA1}} - @GA1 _modify { fatalError() } // expected-warning {{_modify accessor cannot have a global actor}} {{7-12=}} - // expected-note@-1 {{move global actor attribute to property 'test1'}} {{-5:5-5=@GA1}} - } - - var test2: Int { - @GA1 willSet { // expected-warning {{willSet observer cannot have a global actor}} {{7-12=}} - // expected-note@-1 {{move global actor attribute to property 'test2'}} {{-1:5-5=@GA1}} - } - } - - subscript(x: Int) -> Bool { - get { true } - @GA1 set { } // expected-warning {{setter cannot have a global actor}} {{7-12=}} - // expected-note@-1 {{move global actor attribute to subscript 'subscript(_:)'}} {{-2:5-5=@GA1}} - } - - @GA1 subscript(y: Bool) -> String { - get { "" } - @GA1 set { } // expected-warning {{setter cannot have a global actor}} {{7-12=}} - } - } -} diff --git a/test/attr/global_actor/storage_invalid.swift b/test/attr/global_actor/storage_invalid.swift new file mode 100644 index 0000000000000..ffe4544cc67d1 --- /dev/null +++ b/test/attr/global_actor/storage_invalid.swift @@ -0,0 +1,29 @@ +// RUN: %target-swift-frontend -typecheck -verify -swift-version 5 %s + +// REQUIRES: concurrency + +actor SomeActor {} + +@globalActor +struct GA1 { + static let shared = SomeActor() +} + +@globalActor +struct GA2 { + static let shared = SomeActor() +} + +// Global actor on local var/let. +do { + @GA1 let stored: Int + // expected-error@-1:12 {{local variable 'stored' cannot have a global actor}}{{none}} + let _ = stored + @GA1 var computed: Int {0} + // expected-error@-1:12 {{local variable 'computed' cannot have a global actor}}{{none}} + + // FIXME: This diag is superfluous. The attr is not allowed anyway. + // expected-error@+1 {{declaration can not have multiple global actor attributes ('GA2' and 'GA1')}}{{none}} + @GA1 @GA2 var conflict: Int {0} + // expected-error@-1 {{local variable 'conflict' cannot have a global actor}}{{none}} +} diff --git a/test/attr/global_actor/storage_valid.swift b/test/attr/global_actor/storage_valid.swift new file mode 100644 index 0000000000000..0669bea1795ee --- /dev/null +++ b/test/attr/global_actor/storage_valid.swift @@ -0,0 +1,30 @@ +// RUN: %target-swift-frontend -typecheck -verify -swift-version 5 %s + +// REQUIRES: concurrency + +actor SomeActor {} + +@globalActor +struct GA1 { + static let shared = SomeActor() +} + +// Global actor on global var/let. + +@GA1 let isolatedGlobalStoredLet: Int = 0 +@GA1 var isolatedGlobalStoredVar: Int = 0 +@GA1 var isolatedGlobalComputed: Int {0} + +// Global actor on properties/subscripts. +do { + struct VarLet { + @GA1 let stored: Int + @GA1 var computed: Int {0} + @GA1 subscript(_: Int) -> Int {0} + } + @GA1 struct VarLetRedundantIsolation { + @GA1 let stored: Int + @GA1 var computed: Int {0} + @GA1 subscript(_: Int) -> Int {0} + } +} From 524dc34bd7356413be70d5a5c33e6cebcc844bbf Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Sat, 29 Mar 2025 01:33:06 +0000 Subject: [PATCH 3/4] [NFC] Factor out actor isolation inference tests into subdirectory --- .../Inputs/other_global_actor.swift} | 0 .../global_actor.swift} | 4 ++-- .../global_actor_swift6.swift} | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename test/Concurrency/{Inputs/other_global_actor_inference.swift => ActorIsolationInference/Inputs/other_global_actor.swift} (100%) rename test/Concurrency/{global_actor_inference.swift => ActorIsolationInference/global_actor.swift} (99%) rename test/Concurrency/{global_actor_inference_swift6.swift => ActorIsolationInference/global_actor_swift6.swift} (96%) diff --git a/test/Concurrency/Inputs/other_global_actor_inference.swift b/test/Concurrency/ActorIsolationInference/Inputs/other_global_actor.swift similarity index 100% rename from test/Concurrency/Inputs/other_global_actor_inference.swift rename to test/Concurrency/ActorIsolationInference/Inputs/other_global_actor.swift diff --git a/test/Concurrency/global_actor_inference.swift b/test/Concurrency/ActorIsolationInference/global_actor.swift similarity index 99% rename from test/Concurrency/global_actor_inference.swift rename to test/Concurrency/ActorIsolationInference/global_actor.swift index 4c0bb34d55433..f64c605426749 100644 --- a/test/Concurrency/global_actor_inference.swift +++ b/test/Concurrency/ActorIsolationInference/global_actor.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -emit-module -emit-module-path %t/other_global_actor_inference.swiftmodule -module-name other_global_actor_inference -strict-concurrency=complete %S/Inputs/other_global_actor_inference.swift -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-module -emit-module-path %t/other_global_actor.swiftmodule -module-name other_global_actor -strict-concurrency=complete %S/Inputs/other_global_actor.swift -enable-upcoming-feature GlobalActorIsolatedTypesUsability // RUN: %target-swift-frontend -I %t -disable-availability-checking %s -emit-sil -o /dev/null -verify -verify-additional-prefix minimal-targeted- -enable-upcoming-feature GlobalActorIsolatedTypesUsability // RUN: %target-swift-frontend -I %t -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=targeted -verify-additional-prefix minimal-targeted- -enable-upcoming-feature GlobalActorIsolatedTypesUsability // RUN: %target-swift-frontend -I %t -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -verify-additional-prefix complete-tns- -enable-upcoming-feature GlobalActorIsolatedTypesUsability @@ -10,7 +10,7 @@ // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability // REQUIRES: swift_feature_RegionBasedIsolation -import other_global_actor_inference +import other_global_actor actor SomeActor { } diff --git a/test/Concurrency/global_actor_inference_swift6.swift b/test/Concurrency/ActorIsolationInference/global_actor_swift6.swift similarity index 96% rename from test/Concurrency/global_actor_inference_swift6.swift rename to test/Concurrency/ActorIsolationInference/global_actor_swift6.swift index 8ddf537e0d800..a462ea408c58b 100644 --- a/test/Concurrency/global_actor_inference_swift6.swift +++ b/test/Concurrency/ActorIsolationInference/global_actor_swift6.swift @@ -1,12 +1,12 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -swift-version 6 -emit-module -emit-module-path %t/other_global_actor_inference.swiftmodule -module-name other_global_actor_inference -strict-concurrency=complete %S/Inputs/other_global_actor_inference.swift +// RUN: %target-swift-frontend -swift-version 6 -emit-module -emit-module-path %t/other_global_actor.swiftmodule -module-name other_global_actor -strict-concurrency=complete %S/Inputs/other_global_actor.swift // RUN: %target-swift-frontend -swift-version 6 -I %t -disable-availability-checking %s -emit-sil -o /dev/null -verify // REQUIRES: concurrency -import other_global_actor_inference +import other_global_actor actor SomeActor { } From fd7e187c553d92b29e8253b9fee1a97fb56d44a2 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Sat, 29 Mar 2025 05:05:45 +0000 Subject: [PATCH 4/4] Sema: Ignore global actor attr on accessors in Swift 6 Accesses to storage declarations are checked relative to the storage's isolation, not the accessor's, whereas accessors are checked relative to their own isolation. This inconsistency exposes a data race safety hole because global actor attributes are allowed on accessors in Swift 5 and even in Swift 6 on getters. This fixes the bug by inferring an accessor's actor isolation from its from its storage declaration in Swift 6 and onward. Expected source compatibility impact is negligible. First, an accessor with a global actor attribute is not a common pattern. Second, this change will only affect clients that depend on resilient dynamic libraries that declare such an accessor as inlinable. --- include/swift/AST/DiagnosticsSema.def | 3 + lib/Sema/TypeCheckConcurrency.cpp | 57 ++++--- .../Inputs/global_actor_accessors.swift | 154 ++++++++++++++++++ .../global_actor_accessors_swift5.swift | 3 + .../global_actor_accessors_swift6.swift | 3 + test/attr/global_actor/Inputs/accessors.swift | 46 +++--- .../Inputs/accessors_global_var.swift | 9 +- 7 files changed, 231 insertions(+), 44 deletions(-) create mode 100644 test/Concurrency/ActorIsolationInference/Inputs/global_actor_accessors.swift create mode 100644 test/Concurrency/ActorIsolationInference/global_actor_accessors_swift5.swift create mode 100644 test/Concurrency/ActorIsolationInference/global_actor_accessors_swift6.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index f70c156e316a5..67055f067422e 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -6016,6 +6016,9 @@ ERROR(multiple_global_actors,none, (Identifier, Identifier)) ERROR(global_actor_disallowed,none, "%kindonly0 cannot have a global actor", (const Decl *)) +NOTE(global_actor_attr_is_ignored,none, + "global actor attribute is ignored", ()) + ERROR(global_actor_on_actor_class,none, "actor %0 cannot have a global actor", (Identifier)) ERROR(global_actor_on_local_variable,none, diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index cd5dce3e5f568..306bdedc1c33a 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -348,6 +348,10 @@ swift::checkGlobalActorAttributes(SourceLoc loc, DeclContext *dc, return std::make_pair(globalActorAttr, globalActorNominal); } +static bool shouldIgnoreGlobalActorOnAccessor(const ASTContext &ctx) { + return ctx.isSwiftVersionAtLeast(6); +} + std::optional> GlobalActorAttributeRequest::evaluate( Evaluator &evaluator, @@ -452,12 +456,18 @@ GlobalActorAttributeRequest::evaluate( auto &ctx = accessor->getASTContext(); const auto attrRange = globalActorAttr->getRangeWithAt(); const unsigned langModeForError = accessor->isGetter() ? 7 : 6; + const bool isError = ctx.isSwiftVersionAtLeast(langModeForError); // Complain about a global actor attribute on an accessor. accessor->diagnose(diag::global_actor_disallowed, decl) .highlight(attrRange) .warnUntilSwiftVersion(langModeForError); + if (!isError && shouldIgnoreGlobalActorOnAccessor(ctx)) { + ctx.Diags.diagnose(attrRange.Start, diag::global_actor_attr_is_ignored) + .highlight(attrRange); + } + auto *storage = accessor->getStorage(); // Suggest to move the attribute to the storage if it is legal and the @@ -476,7 +486,7 @@ GlobalActorAttributeRequest::evaluate( } // Fail if we emitted an error. - if (ctx.isSwiftVersionAtLeast(langModeForError)) + if (isError) return std::nullopt; } else if (isa(decl) || isa(decl)) { @@ -5458,9 +5468,11 @@ getActorIsolationForMainFuncDecl(FuncDecl *fnDecl) { /// Check rules related to global actor attributes on a class declaration. /// /// \returns true if an error occurred. -static bool checkClassGlobalActorIsolation( - ClassDecl *classDecl, ActorIsolation isolation) { - assert(isolation.isGlobalActor()); +static bool checkClassIsolation(ClassDecl *classDecl, + ActorIsolation isolation) { + if (!isolation.isGlobalActor()) { + return false; + } // A class can only be annotated with a global actor if it has no // superclass, the superclass is annotated with the same global actor, or @@ -5900,8 +5912,7 @@ static InferredActorIsolation computeActorIsolation(Evaluator &evaluator, if (isolationFromAttr && isolationFromAttr->isGlobalActor()) { if (!areTypesEqual(isolationFromAttr->getGlobalActor(), mainIsolation->getGlobalActor())) { - fd->getASTContext().Diags.diagnose( - fd->getLoc(), diag::main_function_must_be_mainActor); + fd->diagnose(diag::main_function_must_be_mainActor); } } return { @@ -5911,17 +5922,29 @@ static InferredActorIsolation computeActorIsolation(Evaluator &evaluator, } } - // If this declaration has one of the actor isolation attributes, report - // that. + // If this declaration has one of the actor isolation attributes, consider + // reporting that. if (isolationFromAttr) { - // Classes with global actors have additional rules regarding inheritance. - if (isolationFromAttr->isGlobalActor()) { - if (auto classDecl = dyn_cast(value)) - checkClassGlobalActorIsolation(classDecl, *isolationFromAttr); + if (isa(value) && shouldIgnoreGlobalActorOnAccessor(ctx)) { + // Global actor attributes on accessors are deprecated, whereas other + // isolation attributes are unconditionally unapplicable to accessors. + // + // In Swift 6 mode and onward, disregard the global actor attribute and + // proceed to infer the isolation from the storage declaration. + } else { + // Classes with global actors have additional rules regarding inheritance. + if (auto classDecl = dyn_cast(value)) { + checkClassIsolation(classDecl, *isolationFromAttr); + } + + return {*isolationFromAttr, + IsolationSource(/*source*/ nullptr, IsolationSource::Explicit)}; } + } - return {*isolationFromAttr, - IsolationSource(/*source*/ nullptr, IsolationSource::Explicit)}; + // For an accessor, use the actor isolation of its storage declaration. + if (auto *accessor = dyn_cast(value)) { + return getInferredActorIsolation(accessor->getStorage()); } InferredActorIsolation defaultIsolation; @@ -6037,12 +6060,6 @@ static InferredActorIsolation computeActorIsolation(Evaluator &evaluator, } } - // If this is an accessor, use the actor isolation of its storage - // declaration. - if (auto accessor = dyn_cast(value)) { - return getInferredActorIsolation(accessor->getStorage()); - } - if (auto var = dyn_cast(value)) { auto &ctx = var->getASTContext(); if (!ctx.LangOpts.isConcurrencyModelTaskToThread() && diff --git a/test/Concurrency/ActorIsolationInference/Inputs/global_actor_accessors.swift b/test/Concurrency/ActorIsolationInference/Inputs/global_actor_accessors.swift new file mode 100644 index 0000000000000..a607ef8a621db --- /dev/null +++ b/test/Concurrency/ActorIsolationInference/Inputs/global_actor_accessors.swift @@ -0,0 +1,154 @@ +actor SomeActor {} + +@globalActor +struct GA1 { + static let shared = SomeActor() +} +@globalActor +struct GA2 { + static let shared = SomeActor() +} + +// expected-swift6-note@+1 * {{calls to global function 'ga2()' from outside of its actor context are implicitly asynchronous}} +@GA2 func ga2() {} + +// Global actor on global var accessors. + +@GA1 var globalObserved: Int = 0 { + // expected-swift6-error@+2 {{cannot have a global actor}} + // expected-swift5-warning@+1 {{cannot have a global actor}} + @GA2 willSet { + ga2() + // expected-swift6-error@-1 {{call to global actor 'GA2'-isolated global function 'ga2()' in a synchronous global actor 'GA1'-isolated context}} + } + // expected-swift6-error@+2 {{cannot have a global actor}} + // expected-swift5-warning@+1 {{cannot have a global actor}} + @GA2 didSet { + ga2() + // expected-swift6-error@-1 {{call to global actor 'GA2'-isolated global function 'ga2()' in a synchronous global actor 'GA1'-isolated context}} + } +} + +@GA1 var globalComputed: Int { + // expected-swift6-note@+3 {{global actor attribute is ignored}} + // expected-swift6-warning@+2 {{cannot have a global actor}} + // expected-swift5-warning@+1 {{cannot have a global actor}} + @GA2 get { + ga2() + // expected-swift6-error@-1 {{call to global actor 'GA2'-isolated global function 'ga2()' in a synchronous global actor 'GA1'-isolated context}} + + return 0 + } + // expected-swift6-error@+2 {{cannot have a global actor}} + // expected-swift5-warning@+1 {{cannot have a global actor}} + @GA2 set { + ga2() + // expected-swift6-error@-1 {{call to global actor 'GA2'-isolated global function 'ga2()' in a synchronous global actor 'GA1'-isolated context}} + } + // expected-swift6-error@+2 {{cannot have a global actor}} + // expected-swift5-warning@+1 {{cannot have a global actor}} + @GA2 _modify { + ga2() + // expected-swift6-error@-1 {{call to global actor 'GA2'-isolated global function 'ga2()' in a synchronous global actor 'GA1'-isolated context}} + } +} + +@GA1 var globalComputedRead: Int { + // expected-swift6-error@+2 {{cannot have a global actor}} + // expected-swift5-warning@+1 {{cannot have a global actor}} + @GA2 _read { + ga2() + // expected-swift6-error@+-1 {{call to global actor 'GA2'-isolated global function 'ga2()' in a synchronous global actor 'GA1'-isolated context}} + } +} + +@GA1 func testGlobalStorageDeclActorIsolation() { + let _ = globalObserved + globalObserved = 0 + + let _ = globalComputed + globalComputed = 0 + + let _ = globalComputedRead +} + +// Global actor on property/subscript accessors. + +@GA1 struct TypeContext { + nonisolated init() {} + + var observed: Int { + // expected-swift6-error@+3 {{cannot have a global actor}} + // expected-swift5-warning@+2 {{cannot have a global actor}} + // expected-note@+1 {{move global actor}} + @GA2 willSet { + ga2() + // expected-swift6-error@-1 {{call to global actor 'GA2'-isolated global function 'ga2()' in a synchronous global actor 'GA1'-isolated context}} + } + // expected-swift6-error@+3 {{cannot have a global actor}} + // expected-swift5-warning@+2 {{cannot have a global actor}} + // expected-note@+1 {{move global actor}} + @GA2 didSet { + ga2() + // expected-swift6-error@-1 {{call to global actor 'GA2'-isolated global function 'ga2()' in a synchronous global actor 'GA1'-isolated context}} + } + } + + var computed: Int { + // expected-swift6-note@+4 {{global actor attribute is ignored}} + // expected-swift6-warning@+3 {{cannot have a global actor}} + // expected-swift5-warning@+2 {{cannot have a global actor}} + // expected-note@+1 {{move global actor}} + @GA2 get { + ga2() + // expected-swift6-error@-1 {{call to global actor 'GA2'-isolated global function 'ga2()' in a synchronous global actor 'GA1'-isolated context}} + + return 0 + } + // expected-swift6-error@+3 {{cannot have a global actor}} + // expected-swift5-warning@+2 {{cannot have a global actor}} + // expected-note@+1 {{move global actor}} + @GA2 set { + ga2() + // expected-swift6-error@-1 {{call to global actor 'GA2'-isolated global function 'ga2()' in a synchronous global actor 'GA1'-isolated context}} + } + // expected-swift6-error@+3 {{cannot have a global actor}} + // expected-swift5-warning@+2 {{cannot have a global actor}} + // expected-note@+1 {{move global actor}} + @GA2 _modify { + ga2() + // expected-swift6-error@-1 {{call to global actor 'GA2'-isolated global function 'ga2()' in a synchronous global actor 'GA1'-isolated context}} + } + // expected-swift6-error@+3 {{cannot have a global actor}} + // expected-swift5-warning@+2 {{cannot have a global actor}} + // expected-note@+1 {{move global actor}} + @GA2 init { + ga2() + // expected-swift6-error@-1 {{call to global actor 'GA2'-isolated global function 'ga2()' in a synchronous global actor 'GA1'-isolated context}} + } + } + + var computedRead: Int { + // expected-swift6-error@+3 {{cannot have a global actor}} + // expected-swift5-warning@+2 {{cannot have a global actor}} + // expected-note@+1 {{move global actor}} + @GA2 _read { + ga2() + // expected-swift6-error@-1 {{call to global actor 'GA2'-isolated global function 'ga2()' in a synchronous global actor 'GA1'-isolated context}} + } + } +} + +@GA1 func testMemberStorageDeclActorIsolation() { + var c = TypeContext() + + let _ = c.observed + c.observed = 0 + + let _ = c.computed + c.computed = 0 + + let _ = c.computedRead +} + + diff --git a/test/Concurrency/ActorIsolationInference/global_actor_accessors_swift5.swift b/test/Concurrency/ActorIsolationInference/global_actor_accessors_swift5.swift new file mode 100644 index 0000000000000..994e47bf36e57 --- /dev/null +++ b/test/Concurrency/ActorIsolationInference/global_actor_accessors_swift5.swift @@ -0,0 +1,3 @@ +// RUN: %target-swift-frontend -typecheck -verify -swift-version 5 -parse-as-library -verify-additional-prefix swift5- %S/Inputs/global_actor_accessors.swift + +// REQUIRES: concurrency diff --git a/test/Concurrency/ActorIsolationInference/global_actor_accessors_swift6.swift b/test/Concurrency/ActorIsolationInference/global_actor_accessors_swift6.swift new file mode 100644 index 0000000000000..b3ad43b37c646 --- /dev/null +++ b/test/Concurrency/ActorIsolationInference/global_actor_accessors_swift6.swift @@ -0,0 +1,3 @@ +// RUN: %target-swift-frontend -typecheck -verify -swift-version 6 -parse-as-library -verify-additional-prefix swift6- -verify-additional-prefix swift6+- %S/Inputs/global_actor_accessors.swift + +// REQUIRES: concurrency diff --git a/test/attr/global_actor/Inputs/accessors.swift b/test/attr/global_actor/Inputs/accessors.swift index d535494fa7fe4..46b19c6a7e991 100644 --- a/test/attr/global_actor/Inputs/accessors.swift +++ b/test/attr/global_actor/Inputs/accessors.swift @@ -33,16 +33,17 @@ var topLevelComputed: Int { @GA1 get {} // expected-swift7-error@-1:8 {{getter cannot have a global actor}}{{none}} // expected-swift6-warning@-2:8 {{getter cannot have a global actor; this will be an error in a future Swift language mode}}{{none}} - // expected-swift5-warning@-3:8 {{getter cannot have a global actor; this will be an error in a future Swift language mode}}{{none}} - // expected-swift5-note@-4:8 {{move global actor attribute to var 'topLevelComputed'}}{{3-8=}}{{-1:1-1=@GA1 }}{{none}} + // expected-swift6-note@-3:3 {{global actor attribute is ignored}}{{none}} + // expected-swift5-warning@-4:8 {{getter cannot have a global actor; this will be an error in a future Swift language mode}}{{none}} + // expected-swift5-note@-5:8 {{move global actor attribute to var 'topLevelComputed'}}{{3-8=}}{{-1:1-1=@GA1 }}{{none}} @GA1 set {} // expected-swift6+-error@-1:8 {{setter cannot have a global actor}}{{none}} // expected-swift5-warning@-2:8 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} - // expected-swift5-note@-3:8 {{move global actor attribute to var 'topLevelComputed'}}{{3-8=}}{{-6:1-1=@GA1 }}{{none}} + // expected-swift5-note@-3:8 {{move global actor attribute to var 'topLevelComputed'}}{{3-8=}}{{-7:1-1=@GA1 }}{{none}} @GA1 _modify {} // expected-swift6+-error@-1:8 {{_modify accessor cannot have a global actor}}{{none}} // expected-swift5-warning@-2:8 {{_modify accessor cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} - // expected-swift5-note@-3:8 {{move global actor attribute to var 'topLevelComputed'}}{{3-8=}}{{-10:1-1=@GA1 }}{{none}} + // expected-swift5-note@-3:8 {{move global actor attribute to var 'topLevelComputed'}}{{3-8=}}{{-11:1-1=@GA1 }}{{none}} } var topLevelComputedRead: Int { @@ -70,7 +71,8 @@ do { @GA1 get {} // expected-swift7-error@-1:10 {{getter cannot have a global actor}}{{none}} // expected-swift6-warning@-2:10 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} - // expected-swift5-warning@-3:10 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} + // expected-swift6-note@-3:5 {{global actor attribute is ignored}}{{none}} + // expected-swift5-warning@-4:10 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} @GA1 set {} // expected-swift6+-error@-1:10 {{setter cannot have a global actor}}{{none}} // expected-swift5-warning@-2:10 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} @@ -104,36 +106,38 @@ do { @GA1 get {} // expected-swift7-error@-1:12 {{getter cannot have a global actor}}{{none}} // expected-swift6-warning@-2:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} - // expected-swift5-warning@-3:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} - // expected-note@-4:12 {{move global actor attribute to property 'computed'}}{{7-12=}}{{-1:5-5=@GA1 }}{{none}} + // expected-swift6-note@-3:7 {{global actor attribute is ignored}}{{none}} + // expected-swift5-warning@-4:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} + // expected-note@-5:12 {{move global actor attribute to property 'computed'}}{{7-12=}}{{-1:5-5=@GA1 }}{{none}} @GA1 set {} // expected-swift6+-error@-1:12 {{setter cannot have a global actor}}{{none}} // expected-swift5-warning@-2:12 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} - // expected-note@-3:12 {{move global actor attribute to property 'computed'}}{{7-12=}}{{-6:5-5=@GA1 }}{{none}} + // expected-note@-3:12 {{move global actor attribute to property 'computed'}}{{7-12=}}{{-7:5-5=@GA1 }}{{none}} @GA1 _modify {} // expected-swift6+-error@-1:12 {{_modify accessor cannot have a global actor}}{{none}} // expected-swift5-warning@-2:12 {{_modify accessor cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} - // expected-note@-3:12 {{move global actor attribute to property 'computed'}}{{7-12=}}{{-10:5-5=@GA1 }}{{none}} + // expected-note@-3:12 {{move global actor attribute to property 'computed'}}{{7-12=}}{{-11:5-5=@GA1 }}{{none}} @GA1 init {} // expected-swift6+-error@-1:12 {{init accessor cannot have a global actor}}{{none}} // expected-swift5-warning@-2:12 {{init accessor cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} - // expected-note@-3:12 {{move global actor attribute to property 'computed'}}{{7-12=}}{{-14:5-5=@GA1 }}{{none}} + // expected-note@-3:12 {{move global actor attribute to property 'computed'}}{{7-12=}}{{-15:5-5=@GA1 }}{{none}} } subscript(subscript _: Int) -> Int { @GA1 get {} // expected-swift7-error@-1:12 {{getter cannot have a global actor}}{{none}} // expected-swift6-warning@-2:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} - // expected-swift5-warning@-3:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} - // expected-note@-4:12 {{move global actor attribute to subscript 'subscript(subscript:)'}}{{7-12=}}{{-1:5-5=@GA1 }}{{none}} + // expected-swift6-note@-3:7 {{global actor attribute is ignored}}{{none}} + // expected-swift5-warning@-4:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} + // expected-note@-5:12 {{move global actor attribute to subscript 'subscript(subscript:)'}}{{7-12=}}{{-1:5-5=@GA1 }}{{none}} @GA1 set {} // expected-swift6+-error@-1:12 {{setter cannot have a global actor}}{{none}} // expected-swift5-warning@-2:12 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} - // expected-note@-3:12 {{move global actor attribute to subscript 'subscript(subscript:)'}}{{7-12=}}{{-6:5-5=@GA1 }}{{none}} + // expected-note@-3:12 {{move global actor attribute to subscript 'subscript(subscript:)'}}{{7-12=}}{{-7:5-5=@GA1 }}{{none}} @GA1 _modify {} // expected-swift6+-error@-1:12 {{_modify accessor cannot have a global actor}} // expected-swift5-warning@-2:12 {{_modify accessor cannot have a global actor; this is an error in the Swift 6 language mode}} - // expected-note@-3:12 {{move global actor attribute to subscript 'subscript(subscript:)'}}{{7-12=}}{{-10:5-5=@GA1 }}{{none}} + // expected-note@-3:12 {{move global actor attribute to subscript 'subscript(subscript:)'}}{{7-12=}}{{-11:5-5=@GA1 }}{{none}} } var computedRead: Int { @@ -191,24 +195,26 @@ do { @GA1 get // expected-swift7-error@-1:12 {{getter cannot have a global actor}}{{none}} // expected-swift6-warning@-2:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} - // expected-swift5-warning@-3:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} - // expected-note@-4:12 {{move global actor attribute to property 'property'}}{{7-12=}}{{-1:5-5=@GA1 }}{{none}} + // expected-swift6-note@-3:7 {{global actor attribute is ignored}}{{none}} + // expected-swift5-warning@-4:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} + // expected-note@-5:12 {{move global actor attribute to property 'property'}}{{7-12=}}{{-1:5-5=@GA1 }}{{none}} @GA1 set // expected-swift6+-error@-1:12 {{setter cannot have a global actor}}{{none}} // expected-swift5-warning@-2:12 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} - // expected-note@-3:12 {{move global actor attribute to property 'property'}}{{7-12=}}{{-6:5-5=@GA1 }}{{none}} + // expected-note@-3:12 {{move global actor attribute to property 'property'}}{{7-12=}}{{-7:5-5=@GA1 }}{{none}} } subscript(_: Int) -> Int { @GA1 get // expected-swift7-error@-1:12 {{getter cannot have a global actor}}{{none}} // expected-swift6-warning@-2:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} - // expected-swift5-warning@-3:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} - // expected-note@-4:12 {{move global actor attribute to subscript 'subscript(_:)'}}{{7-12=}}{{-1:5-5=@GA1 }}{{none}} + // expected-swift6-note@-3:7 {{global actor attribute is ignored}}{{none}} + // expected-swift5-warning@-4:12 {{getter cannot have a global actor; this will be an error in a future Swift language}}{{none}} + // expected-note@-5:12 {{move global actor attribute to subscript 'subscript(_:)'}}{{7-12=}}{{-1:5-5=@GA1 }}{{none}} @GA1 set // expected-swift6+-error@-1:12 {{setter cannot have a global actor}}{{none}} // expected-swift5-warning@-2:12 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} - // expected-note@-3:12 {{move global actor attribute to subscript 'subscript(_:)'}}{{7-12=}}{{-6:5-5=@GA1 }}{{none}} + // expected-note@-3:12 {{move global actor attribute to subscript 'subscript(_:)'}}{{7-12=}}{{-7:5-5=@GA1 }}{{none}} } } } diff --git a/test/attr/global_actor/Inputs/accessors_global_var.swift b/test/attr/global_actor/Inputs/accessors_global_var.swift index 3dbe31b4fe852..a0a3855379867 100644 --- a/test/attr/global_actor/Inputs/accessors_global_var.swift +++ b/test/attr/global_actor/Inputs/accessors_global_var.swift @@ -26,16 +26,17 @@ var globalComputed: Int { @GA1 get {} // expected-swift7-error@-1:8 {{getter cannot have a global actor}}{{none}} // expected-swift6-warning@-2:8 {{getter cannot have a global actor; this will be an error in a future Swift language mode}}{{none}} - // expected-swift5-warning@-3:8 {{getter cannot have a global actor; this will be an error in a future Swift language mode}}{{none}} - // expected-note@-4:8 {{move global actor attribute to var 'globalComputed'}}{{3-8=}}{{-1:1-1=@GA1 }}{{none}} + // expected-swift6-note@-3:3 {{global actor attribute is ignored}}{{none}} + // expected-swift5-warning@-4:8 {{getter cannot have a global actor; this will be an error in a future Swift language mode}}{{none}} + // expected-note@-5:8 {{move global actor attribute to var 'globalComputed'}}{{3-8=}}{{-1:1-1=@GA1 }}{{none}} @GA1 set {} // expected-swift6+-error@-1:8 {{setter cannot have a global actor}}{{none}} // expected-swift5-warning@-2:8 {{setter cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} - // expected-note@-3:8 {{move global actor attribute to var 'globalComputed'}}{{3-8=}}{{-6:1-1=@GA1 }}{{none}} + // expected-note@-3:8 {{move global actor attribute to var 'globalComputed'}}{{3-8=}}{{-7:1-1=@GA1 }}{{none}} @GA1 _modify {} // expected-swift6+-error@-1:8 {{_modify accessor cannot have a global actor}}{{none}} // expected-swift5-warning@-2:8 {{_modify accessor cannot have a global actor; this is an error in the Swift 6 language mode}}{{none}} - // expected-note@-3:8 {{move global actor attribute to var 'globalComputed'}}{{3-8=}}{{-10:1-1=@GA1 }}{{none}} + // expected-note@-3:8 {{move global actor attribute to var 'globalComputed'}}{{3-8=}}{{-11:1-1=@GA1 }}{{none}} } var globalComputedRead: Int {