Files
swift-mirror/include/swift/AST/ActorIsolation.h
Doug Gregor 43ce118340 Simplify override isolation checking.
Improve the equality check for actor isolation to prevent differences
between "unsafe" global actor and global actor isolation from causing
inequality. The operation here is about conceptual equality, not
precise storage semantics. This allows us to simplify override
isolation checking and, likely, other places I haven't seen yet.
2021-12-02 18:26:07 -08:00

177 lines
5.5 KiB
C++

//===--- ActorIsolation.h - Actor isolation ---------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file provides a description of actor isolation state.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_AST_ACTORISOLATIONSTATE_H
#define SWIFT_AST_ACTORISOLATIONSTATE_H
#include "swift/AST/Type.h"
#include "llvm/ADT/Hashing.h"
namespace llvm {
class raw_ostream;
}
namespace swift {
class DeclContext;
class ModuleDecl;
class NominalTypeDecl;
class SubstitutionMap;
/// Determine whether the given types are (canonically) equal, declared here
/// to avoid having to include Types.h.
bool areTypesEqual(Type type1, Type type2);
/// Determine whether the given type is suitable as a concurrent value type.
bool isSendableType(ModuleDecl *module, Type type);
/// Describes the actor isolation of a given declaration, which determines
/// the actors with which it can interact.
class ActorIsolation {
public:
enum Kind {
/// The actor isolation has not been specified. It is assumed to be
/// unsafe to interact with this declaration from any actor.
Unspecified = 0,
/// The declaration is isolated to the instance of an actor.
/// For example, a mutable stored property or synchronous function within
/// the actor is isolated to the instance of that actor.
ActorInstance,
/// The declaration is isolated to a (potentially) distributed actor.
/// Distributed actors may access _their_ state (same as 'ActorInstance')
/// however others may not access any properties on other distributed actors.
DistributedActorInstance,
/// 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,
/// The declaration is isolated to a global actor but with the "unsafe"
/// annotation, which means that we only enforce the isolation if we're
/// coming from something with specific isolation.
GlobalActorUnsafe,
};
private:
Kind kind;
union {
NominalTypeDecl *actor;
Type globalActor;
void *pointer;
};
ActorIsolation(Kind kind, NominalTypeDecl *actor)
: kind(kind), actor(actor) { }
ActorIsolation(Kind kind, Type globalActor)
: kind(kind), globalActor(globalActor) { }
public:
static ActorIsolation forUnspecified() {
return ActorIsolation(Unspecified, nullptr);
}
static ActorIsolation forIndependent() {
return ActorIsolation(Independent, nullptr);
}
static ActorIsolation forActorInstance(NominalTypeDecl *actor) {
return ActorIsolation(ActorInstance, actor);
}
static ActorIsolation forDistributedActorInstance(NominalTypeDecl *actor) {
return ActorIsolation(DistributedActorInstance, actor);
}
static ActorIsolation forGlobalActor(Type globalActor, bool unsafe) {
return ActorIsolation(
unsafe ? GlobalActorUnsafe : GlobalActor, globalActor);
}
Kind getKind() const { return kind; }
operator Kind() const { return getKind(); }
bool isUnspecified() const { return kind == Unspecified; }
bool isIndependent() const { return kind == Independent; }
NominalTypeDecl *getActor() const {
assert(getKind() == ActorInstance || getKind() == DistributedActorInstance);
return actor;
}
bool isGlobalActor() const {
return getKind() == GlobalActor || getKind() == GlobalActorUnsafe;
}
Type getGlobalActor() const {
assert(isGlobalActor());
return globalActor;
}
/// Determine whether this isolation will require substitution to be
/// evaluated.
bool requiresSubstitution() const;
/// Substitute into types within the actor isolation.
ActorIsolation subst(SubstitutionMap subs) const;
friend bool operator==(const ActorIsolation &lhs,
const ActorIsolation &rhs) {
if (lhs.isGlobalActor() && rhs.isGlobalActor())
return areTypesEqual(lhs.globalActor, rhs.globalActor);
if (lhs.kind != rhs.kind)
return false;
switch (lhs.kind) {
case Independent:
case Unspecified:
return true;
case ActorInstance:
case DistributedActorInstance:
return lhs.actor == rhs.actor;
case GlobalActor:
case GlobalActorUnsafe:
llvm_unreachable("Global actors handled above");
}
}
friend bool operator!=(const ActorIsolation &lhs,
const ActorIsolation &rhs) {
return !(lhs == rhs);
}
friend llvm::hash_code hash_value(const ActorIsolation &state) {
return llvm::hash_combine(state.kind, state.pointer);
}
};
/// Determine how the given value declaration is isolated.
ActorIsolation getActorIsolation(ValueDecl *value);
/// Determine how the given declaration context is isolated.
ActorIsolation getActorIsolationOfContext(DeclContext *dc);
void simple_display(llvm::raw_ostream &out, const ActorIsolation &state);
} // end namespace swift
#endif /* SWIFT_AST_ACTORISOLATIONSTATE_H */