Skip to content

[Concurrency] Global actors #34201

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 29 additions & 11 deletions include/swift/AST/ActorIsolation.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ class raw_ostream;

namespace swift {
class ClassDecl;
class Type;

/// Determine whether the given types are (canonically) equal, declared here
/// to avoid having to include Types.h.
bool areTypesEqual(Type type1, Type type2);

/// Describes the actor isolation of a given declaration, which determines
/// the actors with which it can interact.
Expand All @@ -37,20 +42,26 @@ class ActorIsolation {
/// For example, a mutable stored property or synchronous function within
/// the actor is isolated to the instance of that actor.
ActorInstance,
/// The declaration can refer to actor-isolated state, but can also be
//// referenced from outside the actor.
ActorPrivileged,
/// The declaration is explicitly specified to be independent of any actor,
/// meaning that it can be used from any actor but is also unable to
/// refer to the isolated state of any given actor.
Independent,
/// The declaration is isolated to a global actor. It can refer to other
/// entities with the same global actor.
GlobalActor,
};

private:
Kind kind;
ClassDecl *actor;
union {
ClassDecl *actor;
Type globalActor;
void *pointer;
};

ActorIsolation(Kind kind, ClassDecl *actor) : kind(kind), actor(actor) { }
ActorIsolation(Kind kind, Type globalActor)
: kind(kind), globalActor(globalActor) { }

public:
static ActorIsolation forUnspecified() {
Expand All @@ -61,23 +72,28 @@ class ActorIsolation {
return ActorIsolation(Independent, nullptr);
}

static ActorIsolation forActorPrivileged(ClassDecl *actor) {
return ActorIsolation(ActorPrivileged, actor);
}

static ActorIsolation forActorInstance(ClassDecl *actor) {
return ActorIsolation(ActorInstance, actor);
}

static ActorIsolation forGlobalActor(Type globalActor) {
return ActorIsolation(GlobalActor, globalActor);
}

Kind getKind() const { return kind; }

operator Kind() const { return getKind(); }

ClassDecl *getActor() const {
assert(getKind() == ActorInstance || getKind() == ActorPrivileged);
assert(getKind() == ActorInstance);
return actor;
}

Type getGlobalActor() const {
assert(getKind() == GlobalActor);
return globalActor;
}

friend bool operator==(const ActorIsolation &lhs,
const ActorIsolation &rhs) {
if (lhs.kind != rhs.kind)
Expand All @@ -89,8 +105,10 @@ class ActorIsolation {
return true;

case ActorInstance:
case ActorPrivileged:
return lhs.actor == rhs.actor;

case GlobalActor:
return areTypesEqual(lhs.globalActor, rhs.globalActor);
}
}

Expand All @@ -100,7 +118,7 @@ class ActorIsolation {
}

friend llvm::hash_code hash_value(const ActorIsolation &state) {
return llvm::hash_combine(state.kind, state.actor);
return llvm::hash_combine(state.kind, state.pointer);
}
};

Expand Down
6 changes: 6 additions & 0 deletions include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,12 @@ SIMPLE_DECL_ATTR(actorIndependent, ActorIndependent,
APIStableToAdd | APIBreakingToRemove,
103)

SIMPLE_DECL_ATTR(globalActor, GlobalActor,
OnClass | OnStruct | OnEnum | ConcurrencyOnly |
ABIStableToAdd | ABIBreakingToRemove |
APIStableToAdd | APIBreakingToRemove,
104)

#undef TYPE_ATTR
#undef DECL_ATTR_ALIAS
#undef CONTEXTUAL_DECL_ATTR_ALIAS
Expand Down
26 changes: 26 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,18 @@ class alignas(1 << DeclAlignInBits) Decl {
/// If this returns true, the decl can be safely casted to ValueDecl.
bool isPotentiallyOverridable() const;

/// Returns true if this Decl cannot be seen by any other source file
bool isPrivateToEnclosingFile() const;

/// Retrieve the global actor attribute that applies to this declaration,
/// if any.
///
/// This is the "raw" global actor attribute as written directly on the
/// declaration, along with the nominal type declaration to which it refers,
/// without any inference rules applied.
Optional<std::pair<CustomAttr *, NominalTypeDecl *>>
getGlobalActorAttr() const;

/// If an alternative module name is specified for this decl, e.g. using
/// @_originalDefinedIn attribute, this function returns this module name.
StringRef getAlternateModuleName() const;
Expand Down Expand Up @@ -3172,6 +3184,20 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {

void synthesizeSemanticMembersIfNeeded(DeclName member);

/// Retrieves the static 'shared' property of a global actor type, which
/// is used to extract the actor instance.
///
/// \returns the static 'shared' property for a global actor, or \c nullptr
/// for types that are not global actors.
VarDecl *getGlobalActorInstance() const;

/// Whether this type is a global actor, which can be used as an
/// attribute to decorate declarations for inclusion in the actor-isolated
/// state denoted by this type.
bool isGlobalActor() const {
return getGlobalActorInstance() != nullptr;
}

// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
return D->getKind() >= DeclKind::First_NominalTypeDecl &&
Expand Down
45 changes: 45 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -4153,6 +4153,21 @@ ERROR(actor_isolated_self_independent_context,none,
"actor-isolated %0 %1 can not be referenced from an "
"'@actorIndependent' context",
(DescriptiveDeclKind, DeclName))
ERROR(actor_isolated_global_actor_context,none,
"actor-isolated %0 %1 can not be referenced from context of global "
"actor %2",
(DescriptiveDeclKind, DeclName, Type))
ERROR(global_actor_from_instance_actor_context,none,
"%0 %1 isolated to global actor %2 can not be referenced from actor %3",
(DescriptiveDeclKind, DeclName, Type, DeclName))
ERROR(global_actor_from_other_global_actor_context,none,
"%0 %1 isolated to global actor %2 can not be referenced from "
"different global actor %3",
(DescriptiveDeclKind, DeclName, Type, Type))
ERROR(global_actor_from_independent_context,none,
"%0 %1 isolated to global actor %2 can not be referenced from an "
"'@actorIndependent' context",
(DescriptiveDeclKind, DeclName, Type))
ERROR(actor_isolated_partial_apply,none,
"actor-isolated %0 %1 can not be partially applied",
(DescriptiveDeclKind, DeclName))
Expand Down Expand Up @@ -4205,6 +4220,36 @@ ERROR(enqueue_partial_task_not_in_context,none,
"'enqueue(partialTask:)' can only be implemented in the definition of "
"actor class %0", (Type))

ERROR(global_actor_missing_shared,none,
"global actor %0 requires a static property 'shared' that produces an "
"actor instance", (Identifier))
NOTE(global_actor_shared_not_static,none,
"'shared' property in global actor is not 'static'", ())
NOTE(global_actor_shared_inaccessible,none,
"'shared' property has more restrictive access (%0) than its global actor "
"(%1)",
(StringRef, StringRef))
NOTE(global_actor_shared_constrained_extension,none,
"'shared' property in global actor cannot be in a constrained extension",
())
NOTE(global_actor_shared_non_actor_type,none,
"'shared' property type %0 does not conform to the 'Actor' protocol",
(Type))

ERROR(multiple_global_actors,none,
"declaration can not have multiple global actor attributes (%0 and %1)",
(Identifier, Identifier))
ERROR(global_actor_disallowed,none,
"%0 cannot have a global actor", (DescriptiveDeclKind))
ERROR(global_actor_on_actor_class,none,
"actor class %0 cannot have a global actor", (Identifier))
ERROR(global_actor_on_local_variable,none,
"local variable %0 cannot have a global actor", (DeclName))

ERROR(actor_isolation_multiple_attr,none,
"%0 %1 has multiple actor-isolation attributes ('%2' and '%3')",
(DescriptiveDeclKind, DeclName, StringRef, StringRef))

//------------------------------------------------------------------------------
// MARK: Type Check Types
//------------------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/KnownIdentifiers.def
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ IDENTIFIER(Selector)
IDENTIFIER(self)
IDENTIFIER(Self)
IDENTIFIER(setObject)
IDENTIFIER(shared)
IDENTIFIER(simd)
IDENTIFIER(storage)
IDENTIFIER(stringValue)
Expand Down
49 changes: 49 additions & 0 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,55 @@ class IsActorRequest :
bool isCached() const { return true; }
};

/// Retrieve the static "shared" property within a global actor that provides
/// the actor instance representing the global actor.
///
/// Global actors can be applied to a declaration to indicate that the
/// declaration operations on state that is protected by the global actor.
class GlobalActorInstanceRequest :
public SimpleRequest<GlobalActorInstanceRequest,
VarDecl *(NominalTypeDecl *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

VarDecl *evaluate(Evaluator &evaluator, NominalTypeDecl *nominal) const;

public:
// Caching
bool isCached() const { return true; }
};

using CustomAttrNominalPair = std::pair<CustomAttr *, NominalTypeDecl *>;

/// Request the custom attribute which denotes the global actor for the given
/// declaration.
///
/// This is the "raw" global actor attribute as written directly on the
/// declaration, with any inference rules applied.
class GlobalActorAttributeRequest :
public SimpleRequest<
GlobalActorAttributeRequest,
Optional<CustomAttrNominalPair>(Decl *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

// Evaluation.
Optional<std::pair<CustomAttr *, NominalTypeDecl *>>
evaluate(Evaluator &evaluator, Decl *decl) const;

public:
// Caching
bool isCached() const { return true; }
};

/// Determine the actor isolation for the given declaration.
class ActorIsolationRequest :
public SimpleRequest<ActorIsolationRequest,
Expand Down
6 changes: 6 additions & 0 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ SWIFT_REQUEST(TypeChecker, CanBeAsyncHandlerRequest, bool(FuncDecl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, IsActorRequest, bool(ClassDecl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, GlobalActorInstanceRequest,
VarDecl *(NominalTypeDecl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, GlobalActorAttributeRequest,
Optional<CustomAttrNominalPair>(Decl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, ActorIsolationRequest,
ActorIsolationState(ValueDecl *),
Cached, NoLocationInfo)
Expand Down
2 changes: 2 additions & 0 deletions include/swift/Basic/CTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ SWIFT_TYPEID_NAMED(std::string, String)
SWIFT_TYPEID_NAMED(evaluator::SideEffect, SideEffect)
SWIFT_TYPEID_TEMPLATE1_NAMED(std::vector, Vector, typename T, T)
SWIFT_TYPEID_TEMPLATE1_NAMED(std::unique_ptr, UniquePtr, typename T, T)
SWIFT_TYPEID_TEMPLATE2_NAMED(std::pair, Pair, typename T1, T1, typename T2, T2)

// LLVM ADT types.
SWIFT_TYPEID_TEMPLATE1_NAMED(llvm::TinyPtrVector, TinyPtrVector, typename T, T)
SWIFT_TYPEID_TEMPLATE1_NAMED(llvm::ArrayRef, ArrayRef, typename T, T)
SWIFT_TYPEID_TEMPLATE1_NAMED(llvm::Optional, Optional, typename T, T)
24 changes: 24 additions & 0 deletions include/swift/Basic/DefineTypeIDZone.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ template<> struct TypeIDZoneTypes<Zone::SWIFT_TYPEID_ZONE> {
enum Types : uint8_t {
#define SWIFT_TYPEID_NAMED(Type, Name) Name,
#define SWIFT_TYPEID_TEMPLATE1_NAMED(Template, Name, Param1, Arg1) Name,
#define SWIFT_TYPEID_TEMPLATE2_NAMED(Template, Name, Param1, Arg1, Param2, Arg2) Name,
#include SWIFT_TYPEID_HEADER
#undef SWIFT_TYPEID_NAMED
#undef SWIFT_TYPEID_TEMPLATE1_NAMED
#undef SWIFT_TYPEID_TEMPLATE2_NAMED
};
};

Expand Down Expand Up @@ -77,12 +79,34 @@ public: \
\
template<Param1> const uint64_t TypeID<Template<Arg1>>::value;

#define SWIFT_TYPEID_TEMPLATE2_NAMED(Template, Name, Param1, Arg1, Param2, Arg2) \
template<Param1, Param2> struct TypeID<Template<Arg1, Arg2>> { \
private: \
static const uint64_t templateID = \
formTypeID(static_cast<uint8_t>(Zone::SWIFT_TYPEID_ZONE), \
TypeIDZoneTypes<Zone::SWIFT_TYPEID_ZONE>::Name); \
\
public: \
static const uint64_t value = \
(TypeID<Arg1>::value << 32) | \
(TypeID<Arg2>::value << 16) | \
templateID; \
\
static std::string getName() { \
return std::string(#Name) + "<" + TypeID<Arg1>::getName() + \
", " + TypeID<Arg2>::getName() + ">"; \
} \
}; \
\
template<Param1, Param2> const uint64_t TypeID<Template<Arg1, Arg2>>::value;

#include SWIFT_TYPEID_HEADER

#undef SWIFT_REQUEST

#undef SWIFT_TYPEID_NAMED
#undef SWIFT_TYPEID_TEMPLATE1_NAMED
#undef SWIFT_TYPEID_TEMPLATE2_NAMED

#undef SWIFT_TYPEID
#undef SWIFT_TYPEID_ZONE
Expand Down
13 changes: 12 additions & 1 deletion include/swift/Basic/SimpleDisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "llvm/Support/raw_ostream.h"
#include <tuple>
#include <type_traits>
#include <utility>

namespace swift {
template<typename T>
Expand Down Expand Up @@ -93,7 +94,17 @@ namespace swift {
const std::tuple<Types...> &value) {
simple_display_tuple<0>(out, value);
}


template<typename T1, typename T2>
void simple_display(llvm::raw_ostream &out,
const std::pair<T1, T2> &value) {
out << "(";
simple_display(out, value.first);
out << ", ";
simple_display(out, value.second);
out << ")";
}

template<typename T>
void simple_display(llvm::raw_ostream &out,
const llvm::TinyPtrVector<T> &vector) {
Expand Down
15 changes: 15 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,14 @@ static_assert(sizeof(checkSourceLocType(&ID##Decl::getLoc)) == 2, \
llvm_unreachable("invalid file kind");
}

Optional<CustomAttrNominalPair> Decl::getGlobalActorAttr() const {
auto &ctx = getASTContext();
auto mutableThis = const_cast<Decl *>(this);
return evaluateOrDefault(ctx.evaluator,
GlobalActorAttributeRequest{mutableThis},
None);
}

Expr *AbstractFunctionDecl::getSingleExpressionBody() const {
assert(hasSingleExpressionBody() && "Not a single-expression body");
auto braceStmt = getBody();
Expand Down Expand Up @@ -4044,6 +4052,13 @@ void NominalTypeDecl::synthesizeSemanticMembersIfNeeded(DeclName member) {
}
}

VarDecl *NominalTypeDecl::getGlobalActorInstance() const {
auto mutableThis = const_cast<NominalTypeDecl *>(this);
return evaluateOrDefault(getASTContext().evaluator,
GlobalActorInstanceRequest{mutableThis},
nullptr);
}

ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
MutableArrayRef<TypeLoc> Inherited,
GenericParamList *GenericParams, DeclContext *Parent)
Expand Down
Loading