Skip to content

Commit 2762405

Browse files
committed
[Concurrency] Introduce @actorIndependent attribute.
Introduce a new attribute `@actorIndependent` that specifies that a given declaration is considered to be independent of any actor. Actor-independent declarations do not have access to actor-isolated state, even when they are declared as instance members of the actor. On the other hand, actor-independent declarations can be used to conform to (synchronous) requirements in protocols.
1 parent ab4c584 commit 2762405

16 files changed

+434
-28
lines changed

include/swift/AST/ASTTypeIDZone.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//
1616
//===----------------------------------------------------------------------===//
1717

18+
SWIFT_TYPEID(ActorIsolation)
1819
SWIFT_TYPEID(AncestryFlags)
1920
SWIFT_TYPEID(CtorInitializerKind)
2021
SWIFT_TYPEID(FunctionBuilderBodyPreCheck)

include/swift/AST/ASTTypeIDs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
namespace swift {
2424

2525
class AbstractFunctionDecl;
26+
class ActorIsolation;
2627
class BraceStmt;
2728
class ClosureExpr;
2829
class CodeCompletionCallbacksFactory;

include/swift/AST/ActorIsolation.h

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//===--- ActorIsolation.h - Actor isolation ---------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file provides a description of actor isolation state.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
#ifndef SWIFT_AST_ACTORISOLATIONSTATE_H
17+
#define SWIFT_AST_ACTORISOLATIONSTATE_H
18+
19+
#include "llvm/ADT/Hashing.h"
20+
21+
namespace llvm {
22+
class raw_ostream;
23+
}
24+
25+
namespace swift {
26+
class ClassDecl;
27+
28+
/// Describes the actor isolation of a given declaration, which determines
29+
/// the actors with which it can interact.
30+
class ActorIsolation {
31+
public:
32+
enum Kind {
33+
/// The actor isolation has not been specified. It is assumed to be
34+
/// unsafe to interact with this declaration from any actor.
35+
Unspecified = 0,
36+
/// The declaration is isolated to the instance of an actor class.
37+
/// For example, a mutable stored property or synchronous function within
38+
/// the actor is isolated to the instance of that actor.
39+
ActorInstance,
40+
/// The declaration can refer to actor-isolated state, but can also be
41+
//// referenced from outside the actor.
42+
ActorPrivileged,
43+
/// The declaration is explicitly specified to be independent of any actor,
44+
/// meaning that it can be used from any actor but is also unable to
45+
/// refer to the isolated state of any given actor.
46+
Independent,
47+
};
48+
49+
private:
50+
Kind kind;
51+
ClassDecl *actor;
52+
53+
ActorIsolation(Kind kind, ClassDecl *actor) : kind(kind), actor(actor) { }
54+
55+
public:
56+
static ActorIsolation forUnspecified() {
57+
return ActorIsolation(Unspecified, nullptr);
58+
}
59+
60+
static ActorIsolation forIndependent() {
61+
return ActorIsolation(Independent, nullptr);
62+
}
63+
64+
static ActorIsolation forActorPrivileged(ClassDecl *actor) {
65+
return ActorIsolation(ActorPrivileged, actor);
66+
}
67+
68+
static ActorIsolation forActorInstance(ClassDecl *actor) {
69+
return ActorIsolation(ActorInstance, actor);
70+
}
71+
72+
Kind getKind() const { return kind; }
73+
74+
operator Kind() const { return getKind(); }
75+
76+
ClassDecl *getActor() const {
77+
assert(getKind() == ActorInstance || getKind() == ActorPrivileged);
78+
return actor;
79+
}
80+
81+
friend bool operator==(const ActorIsolation &lhs,
82+
const ActorIsolation &rhs) {
83+
if (lhs.kind != rhs.kind)
84+
return false;
85+
86+
switch (lhs.kind) {
87+
case Independent:
88+
case Unspecified:
89+
return true;
90+
91+
case ActorInstance:
92+
case ActorPrivileged:
93+
return lhs.actor == rhs.actor;
94+
}
95+
}
96+
97+
friend bool operator!=(const ActorIsolation &lhs,
98+
const ActorIsolation &rhs) {
99+
return !(lhs == rhs);
100+
}
101+
102+
friend llvm::hash_code hash_value(const ActorIsolation &state) {
103+
return llvm::hash_combine(state.kind, state.actor);
104+
}
105+
};
106+
107+
void simple_display(llvm::raw_ostream &out, const ActorIsolation &state);
108+
109+
} // end namespace swift
110+
111+
#endif /* SWIFT_AST_ACTORISOLATIONSTATE_H */

include/swift/AST/Attr.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,12 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(actor, Actor,
572572
APIBreakingToAdd | APIBreakingToRemove,
573573
102)
574574

575+
SIMPLE_DECL_ATTR(actorIndependent, ActorIndependent,
576+
OnFunc | OnVar | OnSubscript | ConcurrencyOnly |
577+
ABIStableToAdd | ABIStableToRemove |
578+
APIStableToAdd | APIBreakingToRemove,
579+
103)
580+
575581
#undef TYPE_ATTR
576582
#undef DECL_ATTR_ALIAS
577583
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/DiagnosticsSema.def

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4146,6 +4146,10 @@ ERROR(actor_isolated_non_self_reference,none,
41464146
"actor-isolated %0 %1 can only be referenced "
41474147
"%select{inside the actor|on 'self'}2",
41484148
(DescriptiveDeclKind, DeclName, bool))
4149+
ERROR(actor_isolated_self_independent_context,none,
4150+
"actor-isolated %0 %1 can not be referenced from an "
4151+
"'@actorIndependent' context",
4152+
(DescriptiveDeclKind, DeclName))
41494153
WARNING(concurrent_access_local,none,
41504154
"local %0 %1 is unsafe to reference in code that may execute "
41514155
"concurrently",
@@ -4170,6 +4174,24 @@ NOTE(actor_isolated_witness_could_be_async_handler,none,
41704174
"did you mean to make it an asychronous handler?",
41714175
(DescriptiveDeclKind, DeclName))
41724176

4177+
ERROR(actorisolated_let,none,
4178+
"'@actorIsolated' is meaningless on 'let' declarations because "
4179+
"they are immutable",
4180+
())
4181+
ERROR(actorisolated_mutable_storage,none,
4182+
"'@actorIsolated' can not be applied to stored properties",
4183+
())
4184+
ERROR(actorisolated_local_var,none,
4185+
"'@actorIsolated' can not be applied to local variables",
4186+
())
4187+
ERROR(actorisolated_not_actor_member,none,
4188+
"'@actorIsolated' can only be applied to actor members and "
4189+
"global/static variables",
4190+
())
4191+
ERROR(actorisolated_not_actor_instance_member,none,
4192+
"'@actorIsolated' can only be applied to instance members of actors",
4193+
())
4194+
41734195
//------------------------------------------------------------------------------
41744196
// MARK: Type Check Types
41754197
//------------------------------------------------------------------------------

include/swift/AST/TypeCheckRequests.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#ifndef SWIFT_TYPE_CHECK_REQUESTS_H
1717
#define SWIFT_TYPE_CHECK_REQUESTS_H
1818

19+
#include "swift/AST/ActorIsolation.h"
1920
#include "swift/AST/AnyFunctionRef.h"
2021
#include "swift/AST/ASTTypeIDs.h"
2122
#include "swift/AST/GenericSignature.h"
@@ -817,6 +818,24 @@ class IsActorRequest :
817818
bool isCached() const { return true; }
818819
};
819820

821+
/// Determine the actor isolation for the given declaration.
822+
class ActorIsolationRequest :
823+
public SimpleRequest<ActorIsolationRequest,
824+
ActorIsolation(ValueDecl *),
825+
RequestFlags::Cached> {
826+
public:
827+
using SimpleRequest::SimpleRequest;
828+
829+
private:
830+
friend SimpleRequest;
831+
832+
ActorIsolation evaluate(Evaluator &evaluator, ValueDecl *value) const;
833+
834+
public:
835+
// Caching
836+
bool isCached() const { return true; }
837+
};
838+
820839
/// Request whether the storage has a mutating getter.
821840
class IsGetterMutatingRequest :
822841
public SimpleRequest<IsGetterMutatingRequest,

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ SWIFT_REQUEST(TypeChecker, IsAsyncHandlerRequest, bool(FuncDecl *),
8585
Cached, NoLocationInfo)
8686
SWIFT_REQUEST(TypeChecker, IsActorRequest, bool(ClassDecl *),
8787
Cached, NoLocationInfo)
88+
SWIFT_REQUEST(TypeChecker, ActorIsolationRequest,
89+
ActorIsolationState(ValueDecl *),
90+
Cached, NoLocationInfo)
8891
SWIFT_REQUEST(TypeChecker, FunctionOperatorRequest, OperatorDecl *(FuncDecl *),
8992
Cached, NoLocationInfo)
9093
SWIFT_REQUEST(NameLookup, GenericSignatureRequest,

lib/AST/TypeCheckRequests.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,3 +1496,25 @@ void CustomAttrTypeRequest::cacheResult(Type value) const {
14961496
auto *attr = std::get<0>(getStorage());
14971497
attr->setType(value);
14981498
}
1499+
1500+
1501+
void swift::simple_display(
1502+
llvm::raw_ostream &out, const ActorIsolation &state) {
1503+
switch (state) {
1504+
case ActorIsolation::ActorInstance:
1505+
out << "actor-isolated to instance of " << state.getActor()->getName();
1506+
break;
1507+
1508+
case ActorIsolation::ActorPrivileged:
1509+
out << "actor-privileged to instance of " << state.getActor()->getName();
1510+
break;
1511+
1512+
case ActorIsolation::Independent:
1513+
out << "actor-independent";
1514+
break;
1515+
1516+
case ActorIsolation::Unspecified:
1517+
out << "unspecified actor isolation";
1518+
break;
1519+
}
1520+
}

lib/Sema/TypeCheckAttr.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,53 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
276276

277277
(void)classDecl->isActor();
278278
}
279+
280+
void visitActorIndependentAttr(ActorIndependentAttr *attr) {
281+
// @actorIndependent can be applied to global and static/class variables
282+
// that do not have storage.
283+
auto dc = D->getDeclContext();
284+
if (auto var = dyn_cast<VarDecl>(D)) {
285+
// @actorIndependent is meaningless on a `let`.
286+
if (var->isLet()) {
287+
diagnoseAndRemoveAttr(attr, diag::actorisolated_let);
288+
return;
289+
}
290+
291+
// @actorIndependent can not be applied to stored properties.
292+
if (var->hasStorage()) {
293+
diagnoseAndRemoveAttr(attr, diag::actorisolated_mutable_storage);
294+
return;
295+
}
296+
297+
// @actorIndependent can not be applied to local properties.
298+
if (dc->isLocalContext()) {
299+
diagnoseAndRemoveAttr(attr, diag::actorisolated_local_var);
300+
return;
301+
}
302+
303+
// If this is a static or global variable, we're all set.
304+
if (dc->isModuleScopeContext() ||
305+
(dc->isTypeContext() && var->isStatic())) {
306+
return;
307+
}
308+
309+
// Otherwise, fall through to make sure we're in an appropriate
310+
// context.
311+
}
312+
313+
// @actorIndependent only makes sense on an actor instance member.
314+
if (!dc->getSelfClassDecl() ||
315+
!dc->getSelfClassDecl()->isActor()) {
316+
diagnoseAndRemoveAttr(attr, diag::actorisolated_not_actor_member);
317+
return;
318+
}
319+
320+
if (!cast<ValueDecl>(D)->isInstanceMember()) {
321+
diagnoseAndRemoveAttr(
322+
attr, diag::actorisolated_not_actor_instance_member);
323+
return;
324+
}
325+
}
279326
};
280327
} // end anonymous namespace
281328

0 commit comments

Comments
 (0)