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
1 change: 1 addition & 0 deletions include/swift/AST/ASTTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
//
//===----------------------------------------------------------------------===//

SWIFT_TYPEID(ActorIsolation)
SWIFT_TYPEID(AncestryFlags)
SWIFT_TYPEID(CtorInitializerKind)
SWIFT_TYPEID(FunctionBuilderBodyPreCheck)
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/ASTTypeIDs.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
namespace swift {

class AbstractFunctionDecl;
class ActorIsolation;
class BraceStmt;
class ClosureExpr;
class CodeCompletionCallbacksFactory;
Expand Down
111 changes: 111 additions & 0 deletions include/swift/AST/ActorIsolation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//===--- 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 "llvm/ADT/Hashing.h"

namespace llvm {
class raw_ostream;
}

namespace swift {
class ClassDecl;

/// 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 class.
/// 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,
};

private:
Kind kind;
ClassDecl *actor;

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

public:
static ActorIsolation forUnspecified() {
return ActorIsolation(Unspecified, nullptr);
}

static ActorIsolation forIndependent() {
return ActorIsolation(Independent, nullptr);
}

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

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

Kind getKind() const { return kind; }

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

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

friend bool operator==(const ActorIsolation &lhs,
const ActorIsolation &rhs) {
if (lhs.kind != rhs.kind)
return false;

switch (lhs.kind) {
case Independent:
case Unspecified:
return true;

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

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.actor);
}
};

void simple_display(llvm::raw_ostream &out, const ActorIsolation &state);

} // end namespace swift

#endif /* SWIFT_AST_ACTORISOLATIONSTATE_H */
8 changes: 7 additions & 1 deletion include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ SIMPLE_DECL_ATTR(noDerivative, NoDerivative,
100)

SIMPLE_DECL_ATTR(asyncHandler, AsyncHandler,
OnFunc | UserInaccessible |
OnFunc | ConcurrencyOnly |
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
101)

Expand All @@ -572,6 +572,12 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(actor, Actor,
APIBreakingToAdd | APIBreakingToRemove,
102)

SIMPLE_DECL_ATTR(actorIndependent, ActorIndependent,
OnFunc | OnVar | OnSubscript | ConcurrencyOnly |
ABIStableToAdd | ABIStableToRemove |
APIStableToAdd | APIBreakingToRemove,
103)

#undef TYPE_ATTR
#undef DECL_ATTR_ALIAS
#undef CONTEXTUAL_DECL_ATTR_ALIAS
Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -1748,6 +1748,11 @@ ERROR(pound_available_package_description_not_allowed, none,
ERROR(availability_query_repeated_platform, none,
"version for '%0' already specified", (StringRef))

ERROR(attr_requires_concurrency,none,
"'%0' %select{attribute|modifier}1 is only valid when experimental "
"concurrency is enabled",
(StringRef, bool))

//------------------------------------------------------------------------------
// MARK: syntax parsing diagnostics
//------------------------------------------------------------------------------
Expand Down
27 changes: 22 additions & 5 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -4107,9 +4107,6 @@ NOTE(protocol_witness_async_conflict,none,
ERROR(async_autoclosure_nonasync_function,none,
"'async' autoclosure parameter in a non-'async' function", ())

ERROR(asynchandler_attr_requires_concurrency,none,
"'@asyncHandler' is only valid when experimental concurrency is enabled",
())
ERROR(asynchandler_non_func,none,
"'@asyncHandler' can only be applied to functions",
())
Expand Down Expand Up @@ -4142,15 +4139,17 @@ ERROR(satisfy_async_objc,none,
ERROR(async_objc_dynamic_self,none,
"asynchronous method returning 'Self' cannot be '@objc'", ())

ERROR(actor_without_concurrency,none,
"'actor' classes require experimental concurrency support", ())
ERROR(actor_with_nonactor_superclass,none,
"actor class cannot inherit from non-actor class %0", (DeclName))

ERROR(actor_isolated_non_self_reference,none,
"actor-isolated %0 %1 can only be referenced "
"%select{inside the actor|on 'self'}2",
(DescriptiveDeclKind, DeclName, bool))
ERROR(actor_isolated_self_independent_context,none,
"actor-isolated %0 %1 can not be referenced from an "
"'@actorIndependent' context",
(DescriptiveDeclKind, DeclName))
WARNING(concurrent_access_local,none,
"local %0 %1 is unsafe to reference in code that may execute "
"concurrently",
Expand All @@ -4175,6 +4174,24 @@ NOTE(actor_isolated_witness_could_be_async_handler,none,
"did you mean to make it an asychronous handler?",
(DescriptiveDeclKind, DeclName))

ERROR(actorisolated_let,none,
"'@actorIsolated' is meaningless on 'let' declarations because "
"they are immutable",
())
ERROR(actorisolated_mutable_storage,none,
"'@actorIsolated' can not be applied to stored properties",
())
ERROR(actorisolated_local_var,none,
"'@actorIsolated' can not be applied to local variables",
())
ERROR(actorisolated_not_actor_member,none,
"'@actorIsolated' can only be applied to actor members and "
"global/static variables",
())
ERROR(actorisolated_not_actor_instance_member,none,
"'@actorIsolated' can only be applied to instance members of actors",
())

//------------------------------------------------------------------------------
// MARK: Type Check Types
//------------------------------------------------------------------------------
Expand Down
19 changes: 19 additions & 0 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#ifndef SWIFT_TYPE_CHECK_REQUESTS_H
#define SWIFT_TYPE_CHECK_REQUESTS_H

#include "swift/AST/ActorIsolation.h"
#include "swift/AST/AnyFunctionRef.h"
#include "swift/AST/ASTTypeIDs.h"
#include "swift/AST/GenericSignature.h"
Expand Down Expand Up @@ -817,6 +818,24 @@ class IsActorRequest :
bool isCached() const { return true; }
};

/// Determine the actor isolation for the given declaration.
class ActorIsolationRequest :
public SimpleRequest<ActorIsolationRequest,
ActorIsolation(ValueDecl *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

ActorIsolation evaluate(Evaluator &evaluator, ValueDecl *value) const;

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

/// Request whether the storage has a mutating getter.
class IsGetterMutatingRequest :
public SimpleRequest<IsGetterMutatingRequest,
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ SWIFT_REQUEST(TypeChecker, IsAsyncHandlerRequest, bool(FuncDecl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, IsActorRequest, bool(ClassDecl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, ActorIsolationRequest,
ActorIsolationState(ValueDecl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, FunctionOperatorRequest, OperatorDecl *(FuncDecl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(NameLookup, GenericSignatureRequest,
Expand Down
22 changes: 22 additions & 0 deletions lib/AST/TypeCheckRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1496,3 +1496,25 @@ void CustomAttrTypeRequest::cacheResult(Type value) const {
auto *attr = std::get<0>(getStorage());
attr->setType(value);
}


void swift::simple_display(
llvm::raw_ostream &out, const ActorIsolation &state) {
switch (state) {
case ActorIsolation::ActorInstance:
out << "actor-isolated to instance of " << state.getActor()->getName();
break;

case ActorIsolation::ActorPrivileged:
out << "actor-privileged to instance of " << state.getActor()->getName();
break;

case ActorIsolation::Independent:
out << "actor-independent";
break;

case ActorIsolation::Unspecified:
out << "unspecified actor isolation";
break;
}
}
9 changes: 9 additions & 0 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,15 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
DiscardAttribute = true;
}

// If this attribute is only permitted when concurrency is enabled, reject it.
if (DeclAttribute::isConcurrencyOnly(DK) &&
!shouldParseExperimentalConcurrency()) {
diagnose(
Loc, diag::attr_requires_concurrency, AttrName,
DeclAttribute::isDeclModifier(DK));
DiscardAttribute = true;
}

if (Context.LangOpts.Target.isOSBinFormatCOFF()) {
if (DK == DAK_WeakLinked) {
diagnose(Loc, diag::attr_unsupported_on_target, AttrName,
Expand Down
52 changes: 47 additions & 5 deletions lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,11 +259,6 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
void visitTransposeAttr(TransposeAttr *attr);

void visitAsyncHandlerAttr(AsyncHandlerAttr *attr) {
if (!Ctx.LangOpts.EnableExperimentalConcurrency) {
diagnoseAndRemoveAttr(attr, diag::asynchandler_attr_requires_concurrency);
return;
}

auto func = dyn_cast<FuncDecl>(D);
if (!func) {
diagnoseAndRemoveAttr(attr, diag::asynchandler_non_func);
Expand All @@ -281,6 +276,53 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {

(void)classDecl->isActor();
}

void visitActorIndependentAttr(ActorIndependentAttr *attr) {
// @actorIndependent can be applied to global and static/class variables
// that do not have storage.
auto dc = D->getDeclContext();
if (auto var = dyn_cast<VarDecl>(D)) {
// @actorIndependent is meaningless on a `let`.
if (var->isLet()) {
diagnoseAndRemoveAttr(attr, diag::actorisolated_let);
return;
}

// @actorIndependent can not be applied to stored properties.
if (var->hasStorage()) {
diagnoseAndRemoveAttr(attr, diag::actorisolated_mutable_storage);
return;
}

// @actorIndependent can not be applied to local properties.
if (dc->isLocalContext()) {
diagnoseAndRemoveAttr(attr, diag::actorisolated_local_var);
return;
}

// If this is a static or global variable, we're all set.
if (dc->isModuleScopeContext() ||
(dc->isTypeContext() && var->isStatic())) {
return;
}

// Otherwise, fall through to make sure we're in an appropriate
// context.
}

// @actorIndependent only makes sense on an actor instance member.
if (!dc->getSelfClassDecl() ||
!dc->getSelfClassDecl()->isActor()) {
diagnoseAndRemoveAttr(attr, diag::actorisolated_not_actor_member);
return;
}

if (!cast<ValueDecl>(D)->isInstanceMember()) {
diagnoseAndRemoveAttr(
attr, diag::actorisolated_not_actor_instance_member);
return;
}
}
};
} // end anonymous namespace

Expand Down
Loading