Skip to content
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
176 changes: 176 additions & 0 deletions lib/AST/ActorIsolation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,186 @@

#include "swift/AST/ActorIsolation.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ConformanceLookup.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"

using namespace swift;

ActorIsolation ActorIsolation::forMainActor(ASTContext &ctx) {
return ActorIsolation::forGlobalActor(
ctx.getMainActorType()->mapTypeOutOfContext());
}

ActorIsolation::ActorIsolation(Kind kind, NominalTypeDecl *actor,
unsigned parameterIndex)
: actorInstance(actor), kind(kind), isolatedByPreconcurrency(false),
silParsed(false), parameterIndex(parameterIndex) {}

ActorIsolation::ActorIsolation(Kind kind, VarDecl *actor,
unsigned parameterIndex)
: actorInstance(actor), kind(kind), isolatedByPreconcurrency(false),
silParsed(false), parameterIndex(parameterIndex) {}

ActorIsolation::ActorIsolation(Kind kind, Expr *actor, unsigned parameterIndex)
: actorInstance(actor), kind(kind), isolatedByPreconcurrency(false),
silParsed(false), parameterIndex(parameterIndex) {}

ActorIsolation::ActorIsolation(Kind kind, Type globalActor)
: globalActor(globalActor), kind(kind), isolatedByPreconcurrency(false),
silParsed(false), parameterIndex(0) {}

ActorIsolation
ActorIsolation::forActorInstanceParameter(Expr *actor,
unsigned parameterIndex) {
auto &ctx = actor->getType()->getASTContext();

// An isolated value of `nil` is statically nonisolated.
// FIXME: Also allow 'Optional.none'
if (isa<NilLiteralExpr>(actor))
return ActorIsolation::forNonisolated(/*unsafe*/ false);

// An isolated value of `<global actor type>.shared` is statically
// global actor isolated.
if (auto *memberRef = dyn_cast<MemberRefExpr>(actor)) {
// Check that the member declaration witnesses the `shared`
// requirement of the `GlobalActor` protocol.
auto declRef = memberRef->getDecl();
auto baseType = memberRef->getBase()->getType()->getMetatypeInstanceType();
if (auto globalActor = ctx.getProtocol(KnownProtocolKind::GlobalActor)) {
auto conformance = checkConformance(baseType, globalActor);
if (conformance &&
conformance.getWitnessByName(baseType, ctx.Id_shared) == declRef) {
return ActorIsolation::forGlobalActor(baseType);
}
}
}

return ActorIsolation(ActorInstance, actor, parameterIndex + 1);
}

ActorIsolation ActorIsolation::forActorInstanceSelf(ValueDecl *decl) {
if (auto *fn = dyn_cast<AbstractFunctionDecl>(decl))
return ActorIsolation(ActorInstance, fn->getImplicitSelfDecl(), 0);

if (auto *storage = dyn_cast<AbstractStorageDecl>(decl)) {
if (auto *fn = storage->getAccessor(AccessorKind::Get)) {
return ActorIsolation(ActorInstance, fn->getImplicitSelfDecl(), 0);
}
}

auto *dc = decl->getDeclContext();
return ActorIsolation(ActorInstance, dc->getSelfNominalTypeDecl(), 0);
}

ActorIsolation ActorIsolation::forActorInstanceSelf(NominalTypeDecl *selfDecl) {
return ActorIsolation(ActorInstance, selfDecl, 0);
}

NominalTypeDecl *ActorIsolation::getActor() const {
assert(getKind() == ActorInstance || getKind() == GlobalActor);

if (silParsed)
return nullptr;

if (getKind() == GlobalActor) {
return getGlobalActor()->getAnyNominal();
}

Type actorType;

if (auto *instance = actorInstance.dyn_cast<VarDecl *>()) {
actorType = instance->getTypeInContext();
} else if (auto *expr = actorInstance.dyn_cast<Expr *>()) {
actorType = expr->getType();
}

if (actorType) {
if (auto wrapped = actorType->getOptionalObjectType()) {
actorType = wrapped;
}
return actorType->getReferenceStorageReferent()->getAnyActor();
}

return actorInstance.get<NominalTypeDecl *>();
}

VarDecl *ActorIsolation::getActorInstance() const {
assert(getKind() == ActorInstance);

if (silParsed)
return nullptr;

return actorInstance.dyn_cast<VarDecl *>();
}

Expr *ActorIsolation::getActorInstanceExpr() const {
assert(getKind() == ActorInstance);

if (silParsed)
return nullptr;

return actorInstance.dyn_cast<Expr *>();
}

bool ActorIsolation::isMainActor() const {
if (silParsed)
return false;

if (isGlobalActor()) {
if (auto *nominal = getGlobalActor()->getAnyNominal())
return nominal->isMainActor();
}

return false;
}

bool ActorIsolation::isDistributedActor() const {
if (silParsed)
return false;

if (getKind() != ActorInstance)
return false;

return getActor()->isDistributedActor();
}

bool ActorIsolation::isEqual(const ActorIsolation &lhs,
const ActorIsolation &rhs) {
if (lhs.getKind() != rhs.getKind())
return false;

switch (lhs.getKind()) {
case Nonisolated:
case NonisolatedUnsafe:
case Unspecified:
return true;

case Erased:
// Different functions with erased isolation have the same *kind* of
// isolation, but we must generally assume that they're not isolated
// the *same way*, which is what this function is apparently supposed
// to answer.
return false;

case ActorInstance: {
auto *lhsActor = lhs.getActorInstance();
auto *rhsActor = rhs.getActorInstance();
if (lhsActor && rhsActor) {
// FIXME: This won't work for arbitrary isolated parameter captures.
if ((lhsActor->isSelfParameter() && rhsActor->isSelfParamCapture()) ||
(lhsActor->isSelfParamCapture() && rhsActor->isSelfParameter())) {
return true;
}
}

// The parameter index doesn't matter; only the actor instance
// values must be equal.
return (lhs.getActor() == rhs.getActor() &&
lhs.actorInstance == rhs.actorInstance);
}

case GlobalActor:
return areTypesEqual(lhs.globalActor, rhs.globalActor);
}
}
177 changes: 0 additions & 177 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11476,183 +11476,6 @@ void swift::simple_display(llvm::raw_ostream &out, AnyFunctionRef fn) {
out << "closure";
}

ActorIsolation::ActorIsolation(Kind kind, NominalTypeDecl *actor,
unsigned parameterIndex)
: actorInstance(actor), kind(kind), isolatedByPreconcurrency(false),
silParsed(false), parameterIndex(parameterIndex) {}

ActorIsolation::ActorIsolation(Kind kind, VarDecl *actor,
unsigned parameterIndex)
: actorInstance(actor), kind(kind), isolatedByPreconcurrency(false),
silParsed(false), parameterIndex(parameterIndex) {}

ActorIsolation::ActorIsolation(Kind kind, Expr *actor,
unsigned parameterIndex)
: actorInstance(actor), kind(kind), isolatedByPreconcurrency(false),
silParsed(false), parameterIndex(parameterIndex) {}

ActorIsolation::ActorIsolation(Kind kind, Type globalActor)
: globalActor(globalActor), kind(kind), isolatedByPreconcurrency(false),
silParsed(false), parameterIndex(0) {}

ActorIsolation
ActorIsolation::forActorInstanceParameter(Expr *actor,
unsigned parameterIndex) {
auto &ctx = actor->getType()->getASTContext();

// An isolated value of `nil` is statically nonisolated.
// FIXME: Also allow 'Optional.none'
if (dyn_cast<NilLiteralExpr>(actor))
return ActorIsolation::forNonisolated(/*unsafe*/false);

// An isolated value of `<global actor type>.shared` is statically
// global actor isolated.
if (auto *memberRef = dyn_cast<MemberRefExpr>(actor)) {
// Check that the member declaration witnesses the `shared`
// requirement of the `GlobalActor` protocol.
auto declRef = memberRef->getDecl();
auto baseType =
memberRef->getBase()->getType()->getMetatypeInstanceType();
if (auto globalActor = ctx.getProtocol(KnownProtocolKind::GlobalActor)) {
auto conformance = checkConformance(baseType, globalActor);
if (conformance &&
conformance.getWitnessByName(baseType, ctx.Id_shared) == declRef) {
return ActorIsolation::forGlobalActor(baseType);
}
}
}

return ActorIsolation(ActorInstance, actor, parameterIndex + 1);
}

ActorIsolation
ActorIsolation::forActorInstanceSelf(ValueDecl *decl) {
if (auto *fn = dyn_cast<AbstractFunctionDecl>(decl))
return ActorIsolation(ActorInstance, fn->getImplicitSelfDecl(), 0);

if (auto *storage = dyn_cast<AbstractStorageDecl>(decl)) {
if (auto *fn = storage->getAccessor(AccessorKind::Get)) {
return ActorIsolation(ActorInstance, fn->getImplicitSelfDecl(), 0);
}
}

auto *dc = decl->getDeclContext();
return ActorIsolation(ActorInstance, dc->getSelfNominalTypeDecl(), 0);
}

ActorIsolation ActorIsolation::forActorInstanceSelf(NominalTypeDecl *selfDecl) {
return ActorIsolation(ActorInstance, selfDecl, 0);
}

NominalTypeDecl *ActorIsolation::getActor() const {
assert(getKind() == ActorInstance || getKind() == GlobalActor);

if (silParsed)
return nullptr;

if (getKind() == GlobalActor) {
return getGlobalActor()->getAnyNominal();
}

Type actorType;

if (auto *instance = actorInstance.dyn_cast<VarDecl *>()) {
actorType = instance->getTypeInContext();
} else if (auto *expr = actorInstance.dyn_cast<Expr *>()) {
actorType = expr->getType();
}

if (actorType) {
if (auto wrapped = actorType->getOptionalObjectType()) {
actorType = wrapped;
}
return actorType
->getReferenceStorageReferent()->getAnyActor();
}

return actorInstance.get<NominalTypeDecl *>();
}

VarDecl *ActorIsolation::getActorInstance() const {
assert(getKind() == ActorInstance);

if (silParsed)
return nullptr;

return actorInstance.dyn_cast<VarDecl *>();
}

Expr *ActorIsolation::getActorInstanceExpr() const {
assert(getKind() == ActorInstance);

if (silParsed)
return nullptr;

return actorInstance.dyn_cast<Expr *>();
}

bool ActorIsolation::isMainActor() const {
if (silParsed)
return false;

if (isGlobalActor()) {
if (auto *nominal = getGlobalActor()->getAnyNominal())
return nominal->isMainActor();
}

return false;
}

bool ActorIsolation::isDistributedActor() const {
if (silParsed)
return false;

if (getKind() != ActorInstance)
return false;

return getActor()->isDistributedActor();
}

bool ActorIsolation::isEqual(const ActorIsolation &lhs,
const ActorIsolation &rhs) {
if (lhs.getKind() != rhs.getKind())
return false;

switch (lhs.getKind()) {
case Nonisolated:
case NonisolatedUnsafe:
case Unspecified:
return true;

case Erased:
// Different functions with erased isolation have the same *kind* of
// isolation, but we must generally assume that they're not isolated
// the *same way*, which is what this function is apparently supposed
// to answer.
return false;

case ActorInstance: {
auto *lhsActor = lhs.getActorInstance();
auto *rhsActor = rhs.getActorInstance();
if (lhsActor && rhsActor) {
// FIXME: This won't work for arbitrary isolated parameter captures.
if ((lhsActor->isSelfParameter() && rhsActor->isSelfParamCapture()) ||
(lhsActor->isSelfParamCapture() && rhsActor->isSelfParameter())) {
return true;
}
}

// The parameter index doesn't matter; only the actor instance
// values must be equal.
return (lhs.getActor() == rhs.getActor() &&
lhs.actorInstance == rhs.actorInstance);
}

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

BuiltinTupleDecl::BuiltinTupleDecl(Identifier Name, DeclContext *Parent)
: NominalTypeDecl(DeclKind::BuiltinTuple, Parent, Name, SourceLoc(),
ArrayRef<InheritedEntry>(), nullptr) {}
Expand Down