Skip to content

Commit 3bb86f3

Browse files
authored
Merge pull request #69219 from xedin/rdar-99281333
[TypeChecker] Disallow use of global actor attributes of setters, add…
2 parents e7603eb + a71d62c commit 3bb86f3

File tree

3 files changed

+110
-14
lines changed

3 files changed

+110
-14
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5670,6 +5670,8 @@ ERROR(global_actor_access,none,
56705670
ERROR(global_actor_not_usable_from_inline,none,
56715671
"global actor for %kind0 must be '@usableFromInline' or public",
56725672
(const ValueDecl *))
5673+
NOTE(move_global_actor_attr_to_storage_decl,none,
5674+
"move global actor attribute to %kind0", (const ValueDecl *))
56735675

56745676
ERROR(actor_isolation_multiple_attr,none,
56755677
"%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
@@ -373,6 +373,15 @@ GlobalActorAttributeRequest::evaluate(
373373
if (decl->getDeclContext()->getParentSourceFile() == nullptr)
374374
return result;
375375

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

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

test/attr/global_actor.swift

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,60 @@ 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+
// expected-note@-1 {{move global actor attribute to property 'test1'}} {{182:5-5=@GA1}}
187+
@GA1 _modify { fatalError() } // expected-error {{_modify accessor cannot have a global actor}} {{7-12=}}
188+
// expected-note@-1 {{move global actor attribute to property 'test1'}} {{182:5-5=@GA1}}
189+
}
190+
191+
var test2: Int {
192+
@GA1 willSet { // expected-error {{willSet observer cannot have a global actor}} {{7-12=}}
193+
// expected-note@-1 {{move global actor attribute to property 'test2'}} {{191:5-5=@GA1}}
194+
}
195+
}
196+
197+
subscript(x: Int) -> Bool {
198+
get { true }
199+
@GA1 set { } // expected-error {{setter cannot have a global actor}} {{7-12=}}
200+
// expected-note@-1 {{move global actor attribute to subscript 'subscript(_:)'}} {{197:5-5=@GA1}}
201+
}
202+
203+
@GA1 subscript(y: Bool) -> String {
204+
get { "" }
205+
@GA1 set { } // expected-error {{setter cannot have a global actor}} {{7-12=}}
206+
}
207+
}
208+
}

0 commit comments

Comments
 (0)