diff --git a/include/swift/AST/ASTTypeIDZone.def b/include/swift/AST/ASTTypeIDZone.def index fa9dd1d3a8d3c..0bffc3a56697b 100644 --- a/include/swift/AST/ASTTypeIDZone.def +++ b/include/swift/AST/ASTTypeIDZone.def @@ -15,6 +15,7 @@ // //===----------------------------------------------------------------------===// +SWIFT_TYPEID(ActorIsolation) SWIFT_TYPEID(AncestryFlags) SWIFT_TYPEID(CtorInitializerKind) SWIFT_TYPEID(FunctionBuilderBodyPreCheck) diff --git a/include/swift/AST/ASTTypeIDs.h b/include/swift/AST/ASTTypeIDs.h index 6fc964d6fa305..e59255ec7ec28 100644 --- a/include/swift/AST/ASTTypeIDs.h +++ b/include/swift/AST/ASTTypeIDs.h @@ -23,6 +23,7 @@ namespace swift { class AbstractFunctionDecl; +class ActorIsolation; class BraceStmt; class ClosureExpr; class CodeCompletionCallbacksFactory; diff --git a/include/swift/AST/ActorIsolation.h b/include/swift/AST/ActorIsolation.h new file mode 100644 index 0000000000000..2de16ff3fe547 --- /dev/null +++ b/include/swift/AST/ActorIsolation.h @@ -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 */ diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index e737241386a0e..93d8308bb34cc 100644 --- a/include/swift/AST/Attr.def +++ b/include/swift/AST/Attr.def @@ -562,7 +562,7 @@ SIMPLE_DECL_ATTR(noDerivative, NoDerivative, 100) SIMPLE_DECL_ATTR(asyncHandler, AsyncHandler, - OnFunc | UserInaccessible | + OnFunc | ConcurrencyOnly | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove, 101) @@ -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 diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index eaae1b7f858be..a9da96cd96304 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -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 //------------------------------------------------------------------------------ diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index d9a3489de1ab9..424db029bff4f 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -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", ()) @@ -4142,8 +4139,6 @@ 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)) @@ -4151,6 +4146,10 @@ 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", @@ -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 //------------------------------------------------------------------------------ diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 543f2d938be99..b30ac57f01ed6 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -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" @@ -817,6 +818,24 @@ class IsActorRequest : bool isCached() const { return true; } }; +/// Determine the actor isolation for the given declaration. +class ActorIsolationRequest : + public SimpleRequest { +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(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; + } +} diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 032cf266c0eb7..50830e98a7f5f 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -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, diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 11d2dc9d05ddd..370c416416005 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -259,11 +259,6 @@ class AttributeChecker : public AttributeVisitor { void visitTransposeAttr(TransposeAttr *attr); void visitAsyncHandlerAttr(AsyncHandlerAttr *attr) { - if (!Ctx.LangOpts.EnableExperimentalConcurrency) { - diagnoseAndRemoveAttr(attr, diag::asynchandler_attr_requires_concurrency); - return; - } - auto func = dyn_cast(D); if (!func) { diagnoseAndRemoveAttr(attr, diag::asynchandler_non_func); @@ -281,6 +276,53 @@ class AttributeChecker : public AttributeVisitor { (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(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(D)->isInstanceMember()) { + diagnoseAndRemoveAttr( + attr, diag::actorisolated_not_actor_instance_member); + return; + } + } }; } // end anonymous namespace diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index f4e23ad1a98e3..e1979a407e706 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -161,14 +161,6 @@ bool IsActorRequest::evaluate( Evaluator &evaluator, ClassDecl *classDecl) const { // If concurrency is not enabled, we don't have actors. auto actorAttr = classDecl->getAttrs().getAttribute(); - if (!classDecl->getASTContext().LangOpts.EnableExperimentalConcurrency) { - if (actorAttr) { - classDecl->diagnose(diag::actor_without_concurrency) - .highlight(actorAttr->getRange()); - } - - return false; - } // If there is a superclass, we can infer actor-ness from it. if (auto superclassDecl = classDecl->getSuperclassDecl()) { @@ -323,12 +315,21 @@ class IsolationRestriction { if (cast(decl)->isLocalCapture()) return forLocalCapture(decl->getDeclContext()); - // Protected actor instance members can only be accessed on 'self'. - if (auto actorClass = getActorIsolatingMember(cast(decl))) - return forActorSelf(actorClass); + // Determine the actor isolation of the given declaration. + switch (auto isolation = getActorIsolation(cast(decl))) { + case ActorIsolation::ActorInstance: + // Protected actor instance members can only be accessed on 'self'. + return forActorSelf(isolation.getActor()); - // All other accesses are unsafe. - return forUnsafe(); + case ActorIsolation::Independent: + case ActorIsolation::ActorPrivileged: + // Actor-independent and actor-privileged declarations have no + // restrictions on their access. + return forUnrestricted(); + + case ActorIsolation::Unspecified: + return forUnsafe(); + } } } @@ -577,6 +578,26 @@ void swift::checkActorIsolation(const Expr *expr, const DeclContext *dc) { return true; } + // Check whether the context of 'self' is actor-isolated. + switch (getActorIsolation( + cast(selfVar->getDeclContext()->getAsDecl()))) { + case ActorIsolation::ActorInstance: + case ActorIsolation::ActorPrivileged: + case ActorIsolation::Unspecified: + // Okay + break; + + case ActorIsolation::Independent: + // The 'self' is for an actor-independent member, which means + // we cannot refer to actor-isolated state. + ctx.Diags.diagnose( + memberLoc, diag::actor_isolated_self_independent_context, + member->getDescriptiveKind(), + member->getName()); + noteIsolatedActorMember(member); + break; + } + // Check whether we are in a context that will not execute concurrently // with the context of 'self'. if (mayExecuteConcurrentlyWith( @@ -605,22 +626,42 @@ void swift::checkActorIsolation(const Expr *expr, const DeclContext *dc) { const_cast(expr)->walk(walker); } -ClassDecl *swift::getActorIsolatingMember(ValueDecl *value) { - // Only instance members are isolated. - if (!value->isInstanceMember()) - return nullptr; +ActorIsolation ActorIsolationRequest::evaluate( + Evaluator &evaluator, ValueDecl *value) const { + // If the attribute is explicitly marked @actorIndependent, report it as + // independent. + if (value->getAttrs().hasAttribute()) { + return ActorIsolation::forIndependent(); + } + + // If the declaration overrides another declaration, it must have the same + // actor isolation. + if (auto overriddenValue = value->getOverriddenDecl()) { + if (auto isolation = getActorIsolation(overriddenValue)) + return isolation; + } - // Are we within an actor class? + // Check for instance members of actor classes, which are part of + // actor-isolated state. auto classDecl = value->getDeclContext()->getSelfClassDecl(); - if (!classDecl || !classDecl->isActor()) - return nullptr; + if (classDecl && classDecl->isActor() && value->isInstanceMember()) { + // A function that is an asynchronous context is actor-privileged. + if (auto func = dyn_cast(value)) { + if (func->isAsyncContext()) + return ActorIsolation::forActorPrivileged(classDecl); + } - // Functions that are an asynchronous context can be accessed from anywhere. - if (auto func = dyn_cast(value)) { - if (func->isAsyncContext()) - return nullptr; + // Everything else is part of the actor's isolated state. + return ActorIsolation::forActorInstance(classDecl); } - // This member is part of the isolated state. - return classDecl; + // Everything else is unspecified. + return ActorIsolation::forUnspecified(); +} + +ActorIsolation swift::getActorIsolation(ValueDecl *value) { + auto &ctx = value->getASTContext(); + return evaluateOrDefault( + ctx.evaluator, ActorIsolationRequest{value}, + ActorIsolation::forUnspecified()); } diff --git a/lib/Sema/TypeCheckConcurrency.h b/lib/Sema/TypeCheckConcurrency.h index 9bcdad2db287e..030b466537a8c 100644 --- a/lib/Sema/TypeCheckConcurrency.h +++ b/lib/Sema/TypeCheckConcurrency.h @@ -19,6 +19,7 @@ namespace swift { +class ActorIsolation; class ClassDecl; class DeclContext; class Expr; @@ -41,11 +42,8 @@ void addAsyncNotes(FuncDecl *func); /// Check actor isolation rules. void checkActorIsolation(const Expr *expr, const DeclContext *dc); -/// Determine whether the given value is an instance member of an actor -/// class that is isolated to the current actor instance. -/// -/// \returns the type of the actor. -ClassDecl *getActorIsolatingMember(ValueDecl *value); +/// Determine how the given value declaration is isolated. +ActorIsolation getActorIsolation(ValueDecl *value); } // end namespace swift diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index 29670ce622340..1c865bd8dd01b 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1513,6 +1513,7 @@ namespace { UNINTERESTING_ATTR(ProjectedValueProperty) UNINTERESTING_ATTR(OriginallyDefinedIn) UNINTERESTING_ATTR(Actor) + UNINTERESTING_ATTR(ActorIndependent) #undef UNINTERESTING_ATTR void visitAvailableAttr(AvailableAttr *attr) { diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index bf1bc6a6f5c56..d5821a90f5844 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -727,10 +727,18 @@ swift::matchWitness( } } - // Actor-isolated witnesses cannot conform to protocol requirements. - if (getActorIsolatingMember(witness)) + // Check for actor-isolation consistency. + switch (getActorIsolation(witness)) { + case ActorIsolation::ActorInstance: + // Actor-isolated witnesses cannot conform to protocol requirements. return RequirementMatch(witness, MatchKind::ActorIsolatedWitness); + case ActorIsolation::ActorPrivileged: + case ActorIsolation::Independent: + case ActorIsolation::Unspecified: + break; + } + // Now finalize the match. auto result = finalize(anyRenaming, optionalAdjustments); // Check if the requirement's `@differentiable` attributes are satisfied by diff --git a/test/Concurrency/actor_isolation.swift b/test/Concurrency/actor_isolation.swift index 838c35eb73b9e..a1dc9fcc950ef 100644 --- a/test/Concurrency/actor_isolation.swift +++ b/test/Concurrency/actor_isolation.swift @@ -1,7 +1,7 @@ // RUN: %target-typecheck-verify-swift -enable-experimental-concurrency let immutableGlobal: String = "hello" -var mutableGlobal: String = "can't touch this" // expected-note{{var declared here}} +var mutableGlobal: String = "can't touch this" // expected-note 2{{var declared here}} func globalFunc() { } func acceptClosure(_: () -> T) { } @@ -23,16 +23,46 @@ actor class MySuperActor { actor class MyActor: MySuperActor { let immutable: Int = 17 - var text: [String] = [] // expected-note 5{{mutable state is only available within the actor instance}} + var text: [String] = [] // expected-note 6{{mutable state is only available within the actor instance}} class func synchronousClass() { } static func synchronousStatic() { } - func synchronous() -> String { text.first ?? "nothing" } // expected-note 5{{only asynchronous methods can be used outside the actor instance; do you want to add 'async'?}} + func synchronous() -> String { text.first ?? "nothing" } // expected-note 6{{only asynchronous methods can be used outside the actor instance; do you want to add 'async'?}} func asynchronous() async -> String { synchronous() } } extension MyActor { + @actorIndependent var actorIndependentVar: Int { + get { 5 } + set { } + } + + @actorIndependent func actorIndependentFunc(otherActor: MyActor) -> Int { + _ = immutable + _ = text[0] // expected-error{{actor-isolated property 'text' can not be referenced from an '@actorIndependent' context}} + _ = synchronous() // expected-error{{actor-isolated instance method 'synchronous()' can not be referenced from an '@actorIndependent' context}} + + // @actorIndependent + _ = actorIndependentFunc(otherActor: self) + _ = actorIndependentVar + actorIndependentVar = 17 + _ = self.actorIndependentFunc(otherActor: self) + _ = self.actorIndependentVar + self.actorIndependentVar = 17 + + // @actorIndependent on another actor + _ = otherActor.actorIndependentFunc(otherActor: self) + _ = otherActor.actorIndependentVar + otherActor.actorIndependentVar = 17 + + // Global data is okay if it is immutable. + _ = immutableGlobal + _ = mutableGlobal // expected-warning{{reference to var 'mutableGlobal' is not concurrency-safe because it involves shared mutable state}} + + return 5 + } + func testAsynchronous(otherActor: MyActor) async { _ = immutable _ = synchronous() @@ -125,6 +155,11 @@ func testGlobalRestrictions(actor: MyActor) async { _ = actor.text[0] // expected-error{{actor-isolated property 'text' can only be referenced inside the actor}} _ = actor[0] // expected-error{{actor-isolated subscript 'subscript(_:)' can only be referenced inside the actor}} + // @actorIndependent declarations are permitted. + _ = actor.actorIndependentFunc(otherActor: actor) + _ = actor.actorIndependentVar + actor.actorIndependentVar = 5 + // Operations on non-instances are permitted. MyActor.synchronousStatic() MyActor.synchronousClass() diff --git a/test/attr/actorindependent.swift b/test/attr/actorindependent.swift new file mode 100644 index 0000000000000..4cc8d3ef45acb --- /dev/null +++ b/test/attr/actorindependent.swift @@ -0,0 +1,77 @@ +// RUN: %target-swift-frontend -typecheck -verify %s -enable-experimental-concurrency + +// expected-error@+1{{'@actorIsolated' can only be applied to actor members and global/static variables}} +@actorIndependent func globalFunction() { } + +@actorIndependent var globalComputedProperty1: Int { 17 } + +@actorIndependent var globalComputedProperty2: Int { + get { 17 } + set { } +} + +// expected-error@+1{{'@actorIsolated' can not be applied to stored properties}} +@actorIndependent var globalStoredProperty: Int = 17 + +struct X { + @actorIndependent + static var staticProperty1: Int { + return 5 + } + + @actorIndependent + static var staticProperty2: Int { + get { 5 } + set { } + } + + // expected-error@+1{{'@actorIsolated' can not be applied to stored properties}} + @actorIndependent + static var storedStaticProperty: Int = 17 +} + +class C { + // expected-error@+1{{'@actorIsolated' can only be applied to actor members and global/static variables}} + @actorIndependent + var property3: Int { 5 } +} + +actor class A { + var property: Int = 5 + + // expected-error@+1{{'@actorIsolated' can not be applied to stored properties}} + @actorIndependent + var property2: Int = 5 + + @actorIndependent + var property3: Int { 5 } + + @actorIndependent + var property4: Int { + get { 5 } + set { } + } + + @actorIndependent + static var staticProperty1: Int { + return 5 + } + + @actorIndependent + static var staticProperty2: Int { + get { 5 } + set { } + } + + @actorIndependent + func synchronousFunc() { } + + @actorIndependent + func asynchronousFunc() async { } + + @actorIndependent + subscript(index: Int) -> String { "\(index)" } + + // expected-error@+1{{'@actorIsolated' can only be applied to instance members of actors}} + @actorIndependent static func staticFunc() { } +} diff --git a/test/attr/asynchandler_noconcurrency.swift b/test/attr/asynchandler_noconcurrency.swift index 97545fd0bc555..94a6fab001d88 100644 --- a/test/attr/asynchandler_noconcurrency.swift +++ b/test/attr/asynchandler_noconcurrency.swift @@ -1,4 +1,4 @@ // RUN: %target-swift-frontend -typecheck -verify %s @asyncHandler func asyncHandler1() { } -// expected-error@-1{{'@asyncHandler' is only valid when experimental concurrency is enabled}} +// expected-error@-1{{'asyncHandler' attribute is only valid when experimental concurrency is enabled}} diff --git a/test/decl/class/actor/conformance.swift b/test/decl/class/actor/conformance.swift index 5cd3542d25ca0..70f10d4afab2f 100644 --- a/test/decl/class/actor/conformance.swift +++ b/test/decl/class/actor/conformance.swift @@ -24,6 +24,8 @@ protocol SyncProtocol { func syncMethodB() + func syncMethodC() -> Int + subscript (index: Int) -> String { get } // expected-note@-1{{do you want to add a stub}} @@ -46,6 +48,10 @@ actor class OtherActor: SyncProtocol { // expected-error{{type 'OtherActor' does @asyncHandler func syncMethodB() { } + // @actorIndependent methods are okay. + // FIXME: Consider suggesting @actorIndependent if this didn't match. + @actorIndependent func syncMethodC() -> Int { 5 } + subscript (index: Int) -> String { "\(index)" } // expected-note@-1{{actor-isolated subscript 'subscript(_:)' cannot be used to satisfy a protocol requirement}} diff --git a/test/decl/class/actor/noconcurrency.swift b/test/decl/class/actor/noconcurrency.swift index b01725cd2c26d..48e4c7d018bc5 100644 --- a/test/decl/class/actor/noconcurrency.swift +++ b/test/decl/class/actor/noconcurrency.swift @@ -1,4 +1,4 @@ // RUN: %target-typecheck-verify-swift -actor class C { } // expected-error{{'actor' classes require experimental concurrency support}} +actor class C { } // expected-error{{'actor' attribute is only valid when experimental concurrency is enabled}}