Skip to content

Commit 7d531f1

Browse files
authored
Merge pull request #36291 from DougGregor/global-actors-and-property-wrappers
2 parents 794afba + 2b6bda2 commit 7d531f1

File tree

9 files changed

+323
-27
lines changed

9 files changed

+323
-27
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4406,6 +4406,11 @@ ERROR(actorindependent_local_var,none,
44064406
"'@actorIndependent' can not be applied to local variables",
44074407
())
44084408

4409+
ERROR(actor_instance_property_wrapper,none,
4410+
"%0 property in property wrapper type %1 cannot be isolated to "
4411+
"the actor instance; consider @actorIndependent",
4412+
(Identifier, Identifier))
4413+
44094414
ERROR(concurrency_lib_missing,none,
44104415
"missing '%0' declaration, probably because the '_Concurrency' "
44114416
"module was not imported", (StringRef))
@@ -4437,8 +4442,6 @@ ERROR(global_actor_on_actor_class,none,
44374442
"actor class %0 cannot have a global actor", (Identifier))
44384443
ERROR(global_actor_on_local_variable,none,
44394444
"local variable %0 cannot have a global actor", (DeclName))
4440-
ERROR(global_actor_on_struct_property,none,
4441-
"stored property %0 of a struct cannot have a global actor", (DeclName))
44424445
ERROR(global_actor_non_unsafe_init,none,
44434446
"global actor attribute %0 argument can only be '(unsafe)'", (Type))
44444447

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 84 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,36 @@ using namespace swift;
2929
/// Determine whether it makes sense to infer an attribute in the given
3030
/// context.
3131
static bool shouldInferAttributeInContext(const DeclContext *dc) {
32-
auto sourceFile = dc->getParentSourceFile();
33-
if (!sourceFile)
34-
return false;
32+
if (auto *file = dyn_cast<FileUnit>(dc->getModuleScopeContext())) {
33+
switch (file->getKind()) {
34+
case FileUnitKind::Source:
35+
// Check what kind of source file we have.
36+
if (auto sourceFile = dc->getParentSourceFile()) {
37+
switch (sourceFile->Kind) {
38+
case SourceFileKind::Interface:
39+
// Interfaces have explicitly called-out ConcurrentValue conformances.
40+
return false;
3541

36-
switch (sourceFile->Kind) {
37-
case SourceFileKind::Interface:
38-
case SourceFileKind::SIL:
39-
return false;
42+
case SourceFileKind::Library:
43+
case SourceFileKind::Main:
44+
case SourceFileKind::SIL:
45+
return true;
46+
}
47+
}
48+
break;
4049

41-
case SourceFileKind::Library:
42-
case SourceFileKind::Main:
43-
return true;
50+
case FileUnitKind::Builtin:
51+
case FileUnitKind::SerializedAST:
52+
case FileUnitKind::Synthesized:
53+
return false;
54+
55+
case FileUnitKind::ClangModule:
56+
case FileUnitKind::DWARFModule:
57+
return true;
58+
}
4459
}
60+
61+
return false;
4562
}
4663

4764
/// Check whether the @asyncHandler attribute can be applied to the given
@@ -458,15 +475,6 @@ GlobalActorAttributeRequest::evaluate(
458475
.highlight(globalActorAttr->getRangeWithAt());
459476
return None;
460477
}
461-
462-
// Global actors don't make sense on a stored property of a struct.
463-
if (var->hasStorage() && var->getDeclContext()->getSelfStructDecl() &&
464-
var->isInstanceMember()) {
465-
var->diagnose(diag::global_actor_on_struct_property, var->getName())
466-
.highlight(globalActorAttr->getRangeWithAt());
467-
return None;
468-
}
469-
470478
}
471479
} else if (isa<ExtensionDecl>(decl)) {
472480
// Extensions are okay.
@@ -2344,7 +2352,8 @@ ActorIsolation ActorIsolationRequest::evaluate(
23442352
}
23452353

23462354
// Function used when returning an inferred isolation.
2347-
auto inferredIsolation = [&](ActorIsolation inferred) {
2355+
auto inferredIsolation = [&](
2356+
ActorIsolation inferred, bool propagateUnsafe = false) {
23482357
// Add an implicit attribute to capture the actor isolation that was
23492358
// inferred, so that (e.g.) it will be printed and serialized.
23502359
ASTContext &ctx = value->getASTContext();
@@ -2357,13 +2366,19 @@ ActorIsolation ActorIsolationRequest::evaluate(
23572366
break;
23582367

23592368
case ActorIsolation::GlobalActorUnsafe:
2360-
// Don't infer unsafe global actor isolation.
2361-
return ActorIsolation::forUnspecified();
2369+
if (!propagateUnsafe && !value->hasClangNode()) {
2370+
// Don't infer unsafe global actor isolation.
2371+
return ActorIsolation::forUnspecified();
2372+
}
2373+
2374+
LLVM_FALLTHROUGH;
23622375

23632376
case ActorIsolation::GlobalActor: {
23642377
auto typeExpr = TypeExpr::createImplicit(inferred.getGlobalActor(), ctx);
23652378
auto attr = CustomAttr::create(
23662379
ctx, SourceLoc(), typeExpr, /*implicit=*/true);
2380+
if (inferred == ActorIsolation::GlobalActorUnsafe)
2381+
attr->setArgIsUnsafe(true);
23672382
value->getAttrs().add(attr);
23682383
break;
23692384
}
@@ -2400,6 +2415,46 @@ ActorIsolation ActorIsolationRequest::evaluate(
24002415
return getActorIsolation(accessor->getStorage());
24012416
}
24022417

2418+
if (auto var = dyn_cast<VarDecl>(value)) {
2419+
// If this is a variable with a property wrapper, infer from the property
2420+
// wrapper's wrappedValue.
2421+
if (auto wrapperInfo = var->getAttachedPropertyWrapperTypeInfo(0)) {
2422+
if (auto wrappedValue = wrapperInfo.valueVar) {
2423+
if (auto isolation = getActorIsolation(wrappedValue))
2424+
return inferredIsolation(isolation, /*propagateUnsafe=*/true);
2425+
}
2426+
}
2427+
2428+
// If this is the backing storage for a property wrapper, infer from the
2429+
// type of the outermost property wrapper.
2430+
if (auto originalVar = var->getOriginalWrappedProperty(
2431+
PropertyWrapperSynthesizedPropertyKind::Backing)) {
2432+
if (auto backingType =
2433+
originalVar->getPropertyWrapperBackingPropertyType()) {
2434+
if (auto backingNominal = backingType->getAnyNominal()) {
2435+
if (!isa<ClassDecl>(backingNominal) ||
2436+
!cast<ClassDecl>(backingNominal)->isActor()) {
2437+
if (auto isolation = getActorIsolation(backingNominal))
2438+
return inferredIsolation(isolation, /*propagateUnsafe=*/true);
2439+
}
2440+
}
2441+
}
2442+
}
2443+
2444+
// If this is the projected property for a property wrapper, infer from
2445+
// the property wrapper's projectedValue.
2446+
if (auto originalVar = var->getOriginalWrappedProperty(
2447+
PropertyWrapperSynthesizedPropertyKind::Projection)) {
2448+
if (auto wrapperInfo =
2449+
originalVar->getAttachedPropertyWrapperTypeInfo(0)) {
2450+
if (auto projectedValue = wrapperInfo.projectedValueVar) {
2451+
if (auto isolation = getActorIsolation(projectedValue))
2452+
return inferredIsolation(isolation, /*propagateUnsafe=*/true);
2453+
}
2454+
}
2455+
}
2456+
}
2457+
24032458
if (shouldInferAttributeInContext(value->getDeclContext())) {
24042459
// If the declaration witnesses a protocol requirement that is isolated,
24052460
// use that.
@@ -2577,6 +2632,13 @@ static bool shouldDiagnoseExistingDataRaces(const DeclContext *dc) {
25772632
// features.
25782633
if (func->getAttrs().hasAttribute<AsyncHandlerAttr>())
25792634
return true;
2635+
2636+
// If we're in an accessor declaration, also check the storage
2637+
// declaration.
2638+
if (auto accessor = dyn_cast<AccessorDecl>(decl)) {
2639+
if (getIsolationFromAttributes(accessor->getStorage()))
2640+
return true;
2641+
}
25802642
}
25812643
}
25822644

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1766,6 +1766,29 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
17661766
});
17671767
}
17681768

1769+
/// If the given pattern binding has a property wrapper, check the
1770+
/// isolation and effects of the backing storage initializer.
1771+
void checkPropertyWrapperBackingInitializer(PatternBindingDecl *PBD) {
1772+
auto singleVar = PBD->getSingleVar();
1773+
if (!singleVar)
1774+
return;
1775+
1776+
if (!singleVar->hasAttachedPropertyWrapper())
1777+
return;
1778+
1779+
auto backingInfo = singleVar->getPropertyWrapperBackingPropertyInfo();
1780+
if (!backingInfo)
1781+
return;
1782+
1783+
auto backingPBD = backingInfo.backingVar->getParentPatternBinding();
1784+
if (!backingPBD)
1785+
return;
1786+
1787+
if (auto initializer = backingInfo.getInitFromWrappedValue()) {
1788+
checkPropertyWrapperActorIsolation(backingPBD, initializer);
1789+
TypeChecker::checkPropertyWrapperEffects(backingPBD, initializer);
1790+
}
1791+
}
17691792

17701793
void visitPatternBindingDecl(PatternBindingDecl *PBD) {
17711794
DeclContext *DC = PBD->getDeclContext();
@@ -1913,6 +1936,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
19131936
}
19141937
}
19151938
}
1939+
1940+
checkPropertyWrapperBackingInitializer(PBD);
19161941
}
19171942

19181943
void visitSubscriptDecl(SubscriptDecl *SD) {

lib/Sema/TypeCheckPropertyWrapper.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,22 @@ static VarDecl *findValueProperty(ASTContext &ctx, NominalTypeDecl *nominal,
8282
return nullptr;
8383
}
8484

85+
// The property must not be isolated to an actor instance.
86+
switch (auto isolation = getActorIsolation(var)) {
87+
case ActorIsolation::ActorInstance:
88+
var->diagnose(
89+
diag::actor_instance_property_wrapper, var->getName(),
90+
nominal->getName());
91+
return nullptr;
92+
93+
case ActorIsolation::GlobalActor:
94+
case ActorIsolation::GlobalActorUnsafe:
95+
case ActorIsolation::Independent:
96+
case ActorIsolation::IndependentUnsafe:
97+
case ActorIsolation::Unspecified:
98+
break;
99+
}
100+
85101
return var;
86102
}
87103

lib/Sema/TypeCheckStorage.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2528,8 +2528,6 @@ static void typeCheckSynthesizedWrapperInitializer(
25282528
dyn_cast_or_null<Initializer>(pbd->getInitContext(i))) {
25292529
TypeChecker::contextualizeInitializer(initializerContext, initializer);
25302530
}
2531-
checkPropertyWrapperActorIsolation(pbd, initializer);
2532-
TypeChecker::checkPropertyWrapperEffects(pbd, initializer);
25332531
}
25342532

25352533
static PropertyWrapperMutability::Value
@@ -2875,6 +2873,8 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator,
28752873
// Check initializer effects.
28762874
auto *initContext = new (ctx) PropertyWrapperInitializer(
28772875
dc, param, PropertyWrapperInitializer::Kind::WrappedValue);
2876+
TypeChecker::contextualizeInitializer(initContext, wrappedValueInit);
2877+
checkInitializerActorIsolation(initContext, wrappedValueInit);
28782878
TypeChecker::checkInitializerEffects(initContext, wrappedValueInit);
28792879
} else {
28802880
typeCheckSynthesizedWrapperInitializer(

test/ClangImporter/objc_async.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,30 @@ func acceptCV<T: ConcurrentValue>(_: T) { }
9999
func testCV(r: NSRange) {
100100
acceptCV(r)
101101
}
102+
103+
// Global actor (unsafe) isolation.
104+
105+
actor SomeActor { }
106+
107+
@globalActor
108+
struct SomeGlobalActor {
109+
static let shared = SomeActor()
110+
}
111+
112+
class MyButton : NXButton {
113+
@MainActor func testMain() {
114+
onButtonPress() // okay
115+
}
116+
117+
@SomeGlobalActor func testOther() {
118+
onButtonPress() // expected-error{{instance method 'onButtonPress()' isolated to global actor 'MainActor' can not be referenced from different global actor 'SomeGlobalActor'}}
119+
}
120+
121+
func test() {
122+
onButtonPress() // okay
123+
}
124+
}
125+
126+
func testButtons(mb: MyButton) {
127+
mb.onButtonPress()
128+
}

0 commit comments

Comments
 (0)