Skip to content

Commit 58cd10a

Browse files
authored
Merge pull request swiftlang#36378 from DougGregor/actor-isolatd-protocol-members
Declarations within Actor-conforming protocols are actor-isolated.
2 parents 454f0c4 + 09d1215 commit 58cd10a

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

@@ -1967,7 +1993,7 @@ namespace {
19671993
memberLoc, diag::actor_isolated_non_self_reference,
19681994
member->getDescriptiveKind(),
19691995
member->getName(),
1970-
isolation.getActorClass() ==
1996+
isolation.getActorType() ==
19711997
getNearestEnclosingActorContext(getDeclContext()),
19721998
useKind
19731999
);
@@ -2331,9 +2357,18 @@ static Optional<ActorIsolation> getIsolationFromWitnessedRequirements(
23312357
continue;
23322358

23332359
auto requirementIsolation = getActorIsolation(requirement);
2334-
if (requirementIsolation.isUnspecified())
2360+
switch (requirementIsolation) {
2361+
case ActorIsolation::ActorInstance:
2362+
case ActorIsolation::Unspecified:
23352363
continue;
23362364

2365+
case ActorIsolation::GlobalActor:
2366+
case ActorIsolation::GlobalActorUnsafe:
2367+
case ActorIsolation::Independent:
2368+
case ActorIsolation::IndependentUnsafe:
2369+
break;
2370+
}
2371+
23372372
auto witness = conformance->getWitnessDecl(requirement);
23382373
if (witness != value)
23392374
continue;
@@ -2422,12 +2457,13 @@ ActorIsolation ActorIsolationRequest::evaluate(
24222457
}
24232458
}
24242459

2425-
// Check for instance members and initializers of actor classes,
2460+
// Check for instance members and initializers of actor types,
24262461
// which are part of actor-isolated state.
2427-
auto classDecl = value->getDeclContext()->getSelfClassDecl();
2428-
if (classDecl && classDecl->isActor() &&
2429-
(value->isInstanceMember() || isa<ConstructorDecl>(value))) {
2430-
defaultIsolation = ActorIsolation::forActorInstance(classDecl);
2462+
if (auto nominal = value->getDeclContext()->getSelfNominalTypeDecl()) {
2463+
if (nominal->isActor() &&
2464+
(value->isInstanceMember() || isa<ConstructorDecl>(value))) {
2465+
defaultIsolation = ActorIsolation::forActorInstance(nominal);
2466+
}
24312467
}
24322468

24332469
// 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
@@ -2727,7 +2727,11 @@ bool ConformanceChecker::checkActorIsolation(
27272727
switch (auto witnessRestriction =
27282728
ActorIsolationRestriction::forDeclaration(witness)) {
27292729
case ActorIsolationRestriction::ActorSelf: {
2730-
// Actor-isolated witnesses cannot conform to protocol requirements.
2730+
// An actor-isolated witness can only conform to an actor-isolated
2731+
// requirement.
2732+
if (getActorIsolation(requirement) == ActorIsolation::ActorInstance)
2733+
return false;
2734+
27312735
witness->diagnose(diag::actor_isolated_witness,
27322736
witness->getDescriptiveKind(),
27332737
witness->getName());

0 commit comments

Comments
 (0)