Skip to content

Commit 09d1215

Browse files
committed
Declarations within Actor-conforming protocols are actor-isolated.
The Actor protocol is used only to describe actors. When a protocol's Self type conforms to the actor protocol, any instance declarations on the protocol or extensions thereof are considered to be actor-isolated to 'self'. Because the instance requirements of such a protocol are actor-isolated to 'self', they can be witnessed by actor-isolated instance declarations on an actor type. For example: ```swift protocol P: Actor { func f() // okay, actor-isolated to self } extension P { func g() { f() } // okay, actor-islated to self } actor MyActor: P { func f() { } // okay, witnesses actor-isolated requirement } ```
1 parent 30bfe4d commit 09d1215

File tree

11 files changed

+150
-38
lines changed

11 files changed

+150
-38
lines changed

include/swift/AST/ActorIsolation.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,14 @@ class ActorIsolation {
6565
private:
6666
Kind kind;
6767
union {
68-
ClassDecl *actor;
68+
NominalTypeDecl *actor;
6969
Type globalActor;
7070
void *pointer;
7171
};
7272

73-
ActorIsolation(Kind kind, ClassDecl *actor) : kind(kind), actor(actor) { }
73+
ActorIsolation(Kind kind, NominalTypeDecl *actor)
74+
: kind(kind), actor(actor) { }
75+
7476
ActorIsolation(Kind kind, Type globalActor)
7577
: kind(kind), globalActor(globalActor) { }
7678

@@ -93,7 +95,7 @@ class ActorIsolation {
9395
return ActorIsolation(isoKind, nullptr);
9496
}
9597

96-
static ActorIsolation forActorInstance(ClassDecl *actor) {
98+
static ActorIsolation forActorInstance(NominalTypeDecl *actor) {
9799
return ActorIsolation(ActorInstance, actor);
98100
}
99101

@@ -108,7 +110,7 @@ class ActorIsolation {
108110

109111
bool isUnspecified() const { return kind == Unspecified; }
110112

111-
ClassDecl *getActor() const {
113+
NominalTypeDecl *getActor() const {
112114
assert(getKind() == ActorInstance);
113115
return actor;
114116
}

include/swift/AST/Decl.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3159,6 +3159,11 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
31593159
/// with placeholders for unimportable stored properties.
31603160
ArrayRef<Decl *> getStoredPropertiesAndMissingMemberPlaceholders() const;
31613161

3162+
/// Whether this nominal type qualifies as an actor, meaning that it is
3163+
/// either an actor type or a protocol whose `Self` type conforms to the
3164+
/// `Actor` protocol.
3165+
bool isActor() const;
3166+
31623167
/// Return the range of semantics attributes attached to this NominalTypeDecl.
31633168
auto getSemanticsAttrs() const
31643169
-> decltype(getAttrs().getSemanticsAttrs()) {
@@ -3699,9 +3704,6 @@ class ClassDecl final : public NominalTypeDecl {
36993704
return getForeignClassKind() != ForeignKind::Normal;
37003705
}
37013706

3702-
/// Whether the class is an actor.
3703-
bool isActor() const;
3704-
37053707
/// Whether the class is (known to be) a default actor.
37063708
bool isDefaultActor() const;
37073709

include/swift/AST/TypeCheckRequests.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -917,18 +917,18 @@ class CanBeAsyncHandlerRequest :
917917
bool isCached() const { return true; }
918918
};
919919

920-
/// Determine whether the given class is an actor.
920+
/// Determine whether the given nominal type is an actor.
921921
class IsActorRequest :
922922
public SimpleRequest<IsActorRequest,
923-
bool(ClassDecl *),
923+
bool(NominalTypeDecl *),
924924
RequestFlags::Cached> {
925925
public:
926926
using SimpleRequest::SimpleRequest;
927927

928928
private:
929929
friend SimpleRequest;
930930

931-
bool evaluate(Evaluator &evaluator, ClassDecl *classDecl) const;
931+
bool evaluate(Evaluator &evaluator, NominalTypeDecl *nominal) const;
932932

933933
public:
934934
// Caching

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ SWIFT_REQUEST(TypeChecker, IsAsyncHandlerRequest, bool(FuncDecl *),
9494
Cached, NoLocationInfo)
9595
SWIFT_REQUEST(TypeChecker, CanBeAsyncHandlerRequest, bool(FuncDecl *),
9696
Cached, NoLocationInfo)
97-
SWIFT_REQUEST(TypeChecker, IsActorRequest, bool(ClassDecl *),
97+
SWIFT_REQUEST(TypeChecker, IsActorRequest, bool(NominalTypeDecl *),
9898
Cached, NoLocationInfo)
9999
SWIFT_REQUEST(TypeChecker, IsDefaultActorRequest, bool(ClassDecl *),
100100
Cached, NoLocationInfo)

include/swift/AST/Types.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,9 @@ class alignas(1 << TypeAlignInBits) TypeBase {
731731
/// Break an existential down into a set of constraints.
732732
ExistentialLayout getExistentialLayout();
733733

734+
/// Determines whether this type is an actor type.
735+
bool isActorType();
736+
734737
/// Determines the element type of a known
735738
/// [Autoreleasing]Unsafe[Mutable][Raw]Pointer variant, or returns null if the
736739
/// type is not a pointer.

lib/AST/Decl.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3763,6 +3763,14 @@ PropertyWrapperTypeInfo NominalTypeDecl::getPropertyWrapperTypeInfo() const {
37633763
PropertyWrapperTypeInfo());
37643764
}
37653765

3766+
bool NominalTypeDecl::isActor() const {
3767+
auto mutableThis = const_cast<NominalTypeDecl *>(this);
3768+
return evaluateOrDefault(getASTContext().evaluator,
3769+
IsActorRequest{mutableThis},
3770+
false);
3771+
}
3772+
3773+
37663774
GenericTypeDecl::GenericTypeDecl(DeclKind K, DeclContext *DC,
37673775
Identifier name, SourceLoc nameLoc,
37683776
ArrayRef<TypeLoc> inherited,
@@ -4203,13 +4211,6 @@ GetDestructorRequest::evaluate(Evaluator &evaluator, ClassDecl *CD) const {
42034211
return DD;
42044212
}
42054213

4206-
bool ClassDecl::isActor() const {
4207-
auto mutableThis = const_cast<ClassDecl *>(this);
4208-
return evaluateOrDefault(getASTContext().evaluator,
4209-
IsActorRequest{mutableThis},
4210-
false);
4211-
}
4212-
42134214
bool ClassDecl::isDefaultActor() const {
42144215
auto mutableThis = const_cast<ClassDecl *>(this);
42154216
return evaluateOrDefault(getASTContext().evaluator,

lib/AST/Type.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,46 @@ bool CanType::isTypeErasedGenericClassTypeImpl(CanType type) {
358358
return false;
359359
}
360360

361+
bool TypeBase::isActorType() {
362+
// Nominal types: check whether the declaration is an actor.
363+
if (auto nominal = getAnyNominal())
364+
return nominal->isActor();
365+
366+
// Archetypes check for conformance to Actor.
367+
if (auto archetype = getAs<ArchetypeType>()) {
368+
auto actorProto = getASTContext().getProtocol(KnownProtocolKind::Actor);
369+
if (!actorProto)
370+
return false;
371+
372+
auto interfaceType = archetype->getInterfaceType();
373+
auto genericEnv = archetype->getGenericEnvironment();
374+
return genericEnv->getGenericSignature()->requiresProtocol(
375+
interfaceType, actorProto);
376+
}
377+
378+
// Existential types: check for Actor protocol.
379+
if (isExistentialType()) {
380+
auto actorProto = getASTContext().getProtocol(KnownProtocolKind::Actor);
381+
if (!actorProto)
382+
return false;
383+
384+
auto layout = getExistentialLayout();
385+
if (auto superclass = layout.getSuperclass()) {
386+
if (superclass->isActorType())
387+
return true;
388+
}
389+
390+
for (auto proto : layout.getProtocols()) {
391+
if (proto->isActorType())
392+
return true;
393+
}
394+
395+
return false;
396+
}
397+
398+
return false;
399+
}
400+
361401
bool TypeBase::isSpecialized() {
362402
Type t = getCanonicalType();
363403

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,31 @@ bool CanBeAsyncHandlerRequest::evaluate(
236236
}
237237

238238
bool IsActorRequest::evaluate(
239-
Evaluator &evaluator, ClassDecl *classDecl) const {
239+
Evaluator &evaluator, NominalTypeDecl *nominal) const {
240+
// Protocols are actors if their `Self` type conforms to `Actor`.
241+
if (auto protocol = dyn_cast<ProtocolDecl>(nominal)) {
242+
// Simple case: we have the Actor protocol itself.
243+
if (protocol->isSpecificProtocol(KnownProtocolKind::Actor))
244+
return true;
245+
246+
auto actorProto = nominal->getASTContext().getProtocol(
247+
KnownProtocolKind::Actor);
248+
if (!actorProto)
249+
return false;
250+
251+
auto selfType = Type(protocol->getProtocolSelfType());
252+
auto genericSig = protocol->getGenericSignature();
253+
if (!genericSig)
254+
return false;
255+
256+
return genericSig->requiresProtocol(selfType, actorProto);
257+
}
258+
259+
// Class declarations are actors if they were declared with "actor".
260+
auto classDecl = dyn_cast<ClassDecl>(nominal);
261+
if (!classDecl)
262+
return false;
263+
240264
bool isExplicitActor = classDecl->isExplicitActor() ||
241265
classDecl->getAttrs().getAttribute<ActorAttr>();
242266

@@ -1362,12 +1386,14 @@ namespace {
13621386
}
13631387

13641388
// Retrieve the nearest enclosing actor context.
1365-
static ClassDecl *getNearestEnclosingActorContext(const DeclContext *dc) {
1389+
static NominalTypeDecl *getNearestEnclosingActorContext(
1390+
const DeclContext *dc) {
13661391
while (!dc->isModuleScopeContext()) {
13671392
if (dc->isTypeContext()) {
1368-
if (auto classDecl = dc->getSelfClassDecl()) {
1369-
if (classDecl->isActor())
1370-
return classDecl;
1393+
// FIXME: Protocol extensions need specific handling here.
1394+
if (auto nominal = dc->getSelfNominalTypeDecl()) {
1395+
if (nominal->isActor())
1396+
return nominal;
13711397
}
13721398
}
13731399

@@ -1962,7 +1988,7 @@ namespace {
19621988
memberLoc, diag::actor_isolated_non_self_reference,
19631989
member->getDescriptiveKind(),
19641990
member->getName(),
1965-
isolation.getActorClass() ==
1991+
isolation.getActorType() ==
19661992
getNearestEnclosingActorContext(getDeclContext()),
19671993
useKind
19681994
);
@@ -2326,9 +2352,18 @@ static Optional<ActorIsolation> getIsolationFromWitnessedRequirements(
23262352
continue;
23272353

23282354
auto requirementIsolation = getActorIsolation(requirement);
2329-
if (requirementIsolation.isUnspecified())
2355+
switch (requirementIsolation) {
2356+
case ActorIsolation::ActorInstance:
2357+
case ActorIsolation::Unspecified:
23302358
continue;
23312359

2360+
case ActorIsolation::GlobalActor:
2361+
case ActorIsolation::GlobalActorUnsafe:
2362+
case ActorIsolation::Independent:
2363+
case ActorIsolation::IndependentUnsafe:
2364+
break;
2365+
}
2366+
23322367
auto witness = conformance->getWitnessDecl(requirement);
23332368
if (witness != value)
23342369
continue;
@@ -2417,12 +2452,13 @@ ActorIsolation ActorIsolationRequest::evaluate(
24172452
}
24182453
}
24192454

2420-
// Check for instance members and initializers of actor classes,
2455+
// Check for instance members and initializers of actor types,
24212456
// which are part of actor-isolated state.
2422-
auto classDecl = value->getDeclContext()->getSelfClassDecl();
2423-
if (classDecl && classDecl->isActor() &&
2424-
(value->isInstanceMember() || isa<ConstructorDecl>(value))) {
2425-
defaultIsolation = ActorIsolation::forActorInstance(classDecl);
2457+
if (auto nominal = value->getDeclContext()->getSelfNominalTypeDecl()) {
2458+
if (nominal->isActor() &&
2459+
(value->isInstanceMember() || isa<ConstructorDecl>(value))) {
2460+
defaultIsolation = ActorIsolation::forActorInstance(nominal);
2461+
}
24262462
}
24272463

24282464
// Function used when returning an inferred isolation.

lib/Sema/TypeCheckConcurrency.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ class ActorIsolationRestriction {
103103
/// The local context that an entity is tied to.
104104
DeclContext *localContext;
105105

106-
/// The actor class that the entity is declared in.
107-
ClassDecl *actorClass;
106+
/// The actor that the entity is declared in.
107+
NominalTypeDecl *actorType;
108108

109109
/// The global actor type.
110110
TypeBase *globalActor;
@@ -123,10 +123,10 @@ class ActorIsolationRestriction {
123123

124124
Kind getKind() const { return kind; }
125125

126-
/// Retrieve the actor class that the declaration is within.
127-
ClassDecl *getActorClass() const {
126+
/// Retrieve the actor type that the declaration is within.
127+
NominalTypeDecl *getActorType() const {
128128
assert(kind == ActorSelf || kind == CrossActorSelf);
129-
return data.actorClass;
129+
return data.actorType;
130130
}
131131

132132
/// Retrieve the actor class that the declaration is within.
@@ -148,10 +148,10 @@ class ActorIsolationRestriction {
148148
/// Accesses to the given declaration can only be made via the 'self' of
149149
/// the current actor or is a cross-actor access.
150150
static ActorIsolationRestriction forActorSelf(
151-
ClassDecl *actorClass, bool isCrossActor) {
151+
NominalTypeDecl *actor, bool isCrossActor) {
152152
ActorIsolationRestriction result(isCrossActor? CrossActorSelf : ActorSelf,
153153
isCrossActor);
154-
result.data.actorClass = actorClass;
154+
result.data.actorType = actor;
155155
return result;
156156
}
157157

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2729,7 +2729,11 @@ bool ConformanceChecker::checkActorIsolation(
27292729
switch (auto witnessRestriction =
27302730
ActorIsolationRestriction::forDeclaration(witness)) {
27312731
case ActorIsolationRestriction::ActorSelf: {
2732-
// Actor-isolated witnesses cannot conform to protocol requirements.
2732+
// An actor-isolated witness can only conform to an actor-isolated
2733+
// requirement.
2734+
if (getActorIsolation(requirement) == ActorIsolation::ActorInstance)
2735+
return false;
2736+
27332737
witness->diagnose(diag::actor_isolated_witness,
27342738
witness->getDescriptiveKind(),
27352739
witness->getName());

0 commit comments

Comments
 (0)