Skip to content

Commit 0b1e2fe

Browse files
committed
[Concurrency] Don't allow initializing global actor isolated stored
properties with non-Sendable type from across isolation boundaries.
1 parent a3fa3bf commit 0b1e2fe

File tree

3 files changed

+35
-8
lines changed

3 files changed

+35
-8
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5885,6 +5885,23 @@ ActorReferenceResult ActorReferenceResult::forReference(
58855885
return forSameConcurrencyDomain(declIsolation);
58865886
}
58875887

5888+
// Initializing a global actor isolated stored property with a value
5889+
// effectively passes that value from the init context into the global
5890+
// actor context. This is only okay to do if the property type is Sendable.
5891+
if (declIsolation.isGlobalActor() && isStoredProperty(declRef.getDecl())) {
5892+
auto *init = dyn_cast<ConstructorDecl>(fromDC);
5893+
if (init && init->isDesignatedInit()) {
5894+
auto type =
5895+
fromDC->mapTypeIntoContext(declRef.getDecl()->getInterfaceType());
5896+
if (!isSendableType(fromDC->getParentModule(), type)) {
5897+
// Treat the decl isolation as 'preconcurrency' to downgrade violations
5898+
// to warnings, because violating Sendable here is accepted by the
5899+
// Swift 5.9 compiler.
5900+
return forEntersActor(declIsolation, Flags::Preconcurrency);
5901+
}
5902+
}
5903+
}
5904+
58885905
// If there is an instance and it is checked by flow isolation, treat it
58895906
// as being in the same concurrency domain.
58905907
if (actorInstance &&
@@ -5903,13 +5920,8 @@ ActorReferenceResult ActorReferenceResult::forReference(
59035920

59045921
// If there is an instance that corresponds to 'self',
59055922
// we are in a constructor or destructor, and we have a stored property of
5906-
// global-actor-qualified type, pretend we are in the same concurrency
5907-
// domain.
5908-
// FIXME: This is an odd carve-out that probably shouldn't have been allowed.
5909-
// It should at the very least be diagnosed, and either subsumed by flow
5910-
// isolation or banned outright.
5911-
// FIXME: At the very least, we should consistently use
5912-
// isActorInitOrDeInitContext here, but it only wants to think about actors.
5923+
// global-actor-qualified type, then we have problems if the stored property
5924+
// type is non-Sendable. Note that if we get here, the type must be Sendable.
59135925
if (actorInstance && actorInstance->isSelf() &&
59145926
isNonInheritedStorage(declRef.getDecl(), fromDC) &&
59155927
declIsolation.isGlobalActor() &&

test/Concurrency/global_actor_inference.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,17 +324,30 @@ struct WrapperOnActor<Wrapped: Sendable> {
324324
public struct WrapperOnMainActor<Wrapped> {
325325
// Make sure inference of @MainActor on wrappedValue doesn't crash.
326326

327+
// expected-note@+1 {{mutation of this property is only permitted within the actor}}
327328
public var wrappedValue: Wrapped
328329

329330
public var accessCount: Int
330331

331332
nonisolated public init(wrappedValue: Wrapped) {
333+
// expected-warning@+1 {{main actor-isolated property 'wrappedValue' can not be mutated from a non-isolated context; this is an error in Swift 6}}
332334
self.wrappedValue = wrappedValue
333335
}
334336
}
335337

336338
@propertyWrapper
337-
public struct WrapperOnMainActor2<Wrapped> {
339+
public struct WrapperOnMainActorNonSendable<Wrapped> {
340+
// expected-note@+1 {{mutation of this property is only permitted within the actor}}
341+
@MainActor public var wrappedValue: Wrapped
342+
343+
public init(wrappedValue: Wrapped) {
344+
// expected-warning@+1 {{main actor-isolated property 'wrappedValue' can not be mutated from a non-isolated context; this is an error in Swift 6}}
345+
self.wrappedValue = wrappedValue
346+
}
347+
}
348+
349+
@propertyWrapper
350+
public struct WrapperOnMainActorSendable<Wrapped: Sendable> {
338351
@MainActor public var wrappedValue: Wrapped
339352

340353
public init(wrappedValue: Wrapped) {

test/Concurrency/global_actor_inference_swift6.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,13 @@ struct WrapperOnActor<Wrapped: Sendable> {
6969
public struct WrapperOnMainActor<Wrapped> {
7070
// Make sure inference of @MainActor on wrappedValue doesn't crash.
7171

72+
// expected-note@+1 {{mutation of this property is only permitted within the actor}}
7273
public var wrappedValue: Wrapped // expected-note {{property declared here}}
7374

7475
public var accessCount: Int
7576

7677
nonisolated public init(wrappedValue: Wrapped) {
78+
// expected-error@+1 {{main actor-isolated property 'wrappedValue' can not be mutated from a non-isolated context}}
7779
self.wrappedValue = wrappedValue
7880
}
7981
}

0 commit comments

Comments
 (0)