Skip to content

Commit 172e487

Browse files
committed
[TypeChecker] Disallow use of global actor attributes of setters, addressors, and observers
No other accessor besides a getter could be marked as async and adding @mainactor global accessor on setters and other accessor kinds would mean disconnecting them from a getter in terms of isolation, so let's keep things simple and allow global actor attribute on getters and/or enclosing declaration only. Resolves: rdar://99281333
1 parent d8bfa5a commit 172e487

File tree

3 files changed

+107
-14
lines changed

3 files changed

+107
-14
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5615,6 +5615,8 @@ ERROR(global_actor_access,none,
56155615
ERROR(global_actor_not_usable_from_inline,none,
56165616
"global actor for %kind0 must be '@usableFromInline' or public",
56175617
(const ValueDecl *))
5618+
NOTE(move_global_actor_attr_to_storage_decl,none,
5619+
"move global actor attribute to %kind0", (const ValueDecl *))
56185620

56195621
ERROR(actor_isolation_multiple_attr,none,
56205622
"%kind0 has multiple actor-isolation attributes ('%1' and '%2')",

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,15 @@ GlobalActorAttributeRequest::evaluate(
372372
if (decl->getDeclContext()->getParentSourceFile() == nullptr)
373373
return result;
374374

375+
auto isInstancePropertyOfStruct = [](VarDecl *var) {
376+
if (var->isStatic())
377+
return false;
378+
379+
auto *nominal = var->getDeclContext()->getSelfNominalTypeDecl();
380+
return isa_and_nonnull<StructDecl>(nominal) &&
381+
!isWrappedValueOfPropWrapper(var);
382+
};
383+
375384
auto globalActorAttr = result->first;
376385
if (auto nominal = dyn_cast<NominalTypeDecl>(decl)) {
377386
// Nominal types are okay...
@@ -405,25 +414,53 @@ GlobalActorAttributeRequest::evaluate(
405414
}
406415

407416
// ... and not if it's the instance storage of a struct
408-
if (!var->isStatic() && var->isOrdinaryStoredProperty()) {
409-
if (auto *nominal = var->getDeclContext()->getSelfNominalTypeDecl()) {
410-
if (isa<StructDecl>(nominal) && !isWrappedValueOfPropWrapper(var)) {
411-
412-
var->diagnose(diag::global_actor_on_storage_of_value_type,
413-
var->getName())
414-
.highlight(globalActorAttr->getRangeWithAt())
415-
.warnUntilSwiftVersion(6);
416-
417-
// In Swift 6, once the diag above is an error, it is disallowed.
418-
if (var->getASTContext().isSwiftVersionAtLeast(6))
419-
return llvm::None;
420-
}
421-
}
417+
if (var->isOrdinaryStoredProperty() && isInstancePropertyOfStruct(var)) {
418+
var->diagnose(diag::global_actor_on_storage_of_value_type,
419+
var->getName())
420+
.highlight(globalActorAttr->getRangeWithAt())
421+
.warnUntilSwiftVersion(6);
422+
423+
// In Swift 6, once the diag above is an error, it is disallowed.
424+
if (var->getASTContext().isSwiftVersionAtLeast(6))
425+
return llvm::None;
422426
}
423427
}
424428
} else if (isa<ExtensionDecl>(decl)) {
425429
// Extensions are okay.
426430
} else if (isa<ConstructorDecl>(decl) || isa<FuncDecl>(decl)) {
431+
// None of the accessors/addressors besides a getter are allowed
432+
// to have a global actor attribute.
433+
if (auto *accessor = dyn_cast<AccessorDecl>(decl)) {
434+
if (!accessor->isGetter()) {
435+
decl->diagnose(diag::global_actor_disallowed,
436+
decl->getDescriptiveKind())
437+
.fixItRemove(globalActorAttr->getRangeWithAt());
438+
439+
auto *storage = accessor->getStorage();
440+
// Let's suggest to move the attribute to the storage if
441+
// this is an accessor/addressor of a property of subscript.
442+
if (storage->getDeclContext()->isTypeContext()) {
443+
// If enclosing declaration has a global actor,
444+
// skip the suggestion.
445+
if (storage->getGlobalActorAttr())
446+
return llvm::None;
447+
448+
// Global actor attribute cannot be applied to
449+
// an instance property of a struct.
450+
if (auto *var = dyn_cast<VarDecl>(storage)) {
451+
if (isInstancePropertyOfStruct(var))
452+
return llvm::None;
453+
}
454+
455+
decl->diagnose(diag::move_global_actor_attr_to_storage_decl, storage)
456+
.fixItInsert(
457+
storage->getAttributeInsertionLoc(/*forModifier=*/false),
458+
llvm::Twine("@", result->second->getNameStr()).str());
459+
}
460+
461+
return llvm::None;
462+
}
463+
}
427464
// Functions are okay.
428465
} else {
429466
// Everything else is disallowed.

test/attr/global_actor.swift

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,57 @@ public struct PublicGA {
149149
@InternalGA open class OpenClassInternalGA {} // expected-error {{open class 'OpenClassInternalGA' cannot have internal global actor 'InternalGA'}}
150150
@PackageGA open class OpenClassPackageGA {} // expected-error {{open class 'OpenClassPackageGA' cannot have package global actor 'PackageGA'}}
151151
@PublicGA open class OpenClassPublicGA {}
152+
153+
// rdar://99281333 - no accessors/addressors/observers expect to 'get' are allowed to have a global actor attribute
154+
do {
155+
class TestInvalidAccessors {
156+
var test1: Int {
157+
get { 42 }
158+
@GA1
159+
set { } // expected-error {{setter cannot have a global actor}} {{158:7-11=}}
160+
// expected-note@-1 {{move global actor attribute to property 'test1'}} {{156:5-5=@GA1}}
161+
162+
@GA1 _modify { fatalError() } // expected-error {{_modify accessor cannot have a global actor}} {{7-12=}}
163+
// expected-note@-1 {{move global actor attribute to property 'test1'}} {{156:5-5=@GA1}}
164+
}
165+
166+
func local() {
167+
var test: Bool {
168+
get { false }
169+
170+
@GA1
171+
set { } // expected-error {{setter cannot have a global actor}}
172+
}
173+
}
174+
175+
@GA1 var testAlreadyWithGlobal: String {
176+
get { "" }
177+
@GA1 set { } // expected-error {{setter cannot have a global actor}} {{7-12=}}
178+
}
179+
}
180+
181+
struct TestStruct {
182+
var test1: Int {
183+
get { 42 }
184+
@GA1
185+
set { } // expected-error {{setter cannot have a global actor}} {{184:7-11=}}
186+
@GA1 _modify { fatalError() } // expected-error {{_modify accessor cannot have a global actor}} {{7-12=}}
187+
}
188+
189+
var test2: Int {
190+
@GA1 willSet { // expected-error {{willSet observer cannot have a global actor}} {{7-12=}}
191+
}
192+
}
193+
194+
subscript(x: Int) -> Bool {
195+
get { true }
196+
@GA1 set { } // expected-error {{setter cannot have a global actor}} {{7-12=}}
197+
// expected-note@-1 {{move global actor attribute to subscript 'subscript(_:)'}} {{194:5-5=@GA1}}
198+
}
199+
200+
@GA1 subscript(y: Bool) -> String {
201+
get { "" }
202+
@GA1 set { } // expected-error {{setter cannot have a global actor}} {{7-12=}}
203+
}
204+
}
205+
}

0 commit comments

Comments
 (0)