From 0590163496516b3695af7d6a609fbe9cd730c5c6 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 30 Mar 2022 11:16:59 +0900 Subject: [PATCH 1/2] [Distributed] More tests for implicit Codable --- ...or_implicit_codable_system_typealias.swift | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 test/Distributed/distributed_actor_implicit_codable_system_typealias.swift diff --git a/test/Distributed/distributed_actor_implicit_codable_system_typealias.swift b/test/Distributed/distributed_actor_implicit_codable_system_typealias.swift new file mode 100644 index 0000000000000..59c10e25f3294 --- /dev/null +++ b/test/Distributed/distributed_actor_implicit_codable_system_typealias.swift @@ -0,0 +1,26 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/Inputs/FakeDistributedActorSystems.swift +// RUN: %target-swift-frontend -typecheck -verify -enable-experimental-distributed -disable-availability-checking -I %t 2>&1 %s +// REQUIRES: concurrency +// REQUIRES: distributed + +import Distributed +import FakeDistributedActorSystems + +distributed actor DA { + typealias ActorSystem = FakeActorSystem + + init(actorSystem: ActorSystem) { + self.actorSystem = actorSystem + } +} + +func take(actor: A) {} +func takeE(actor: A) {} +func takeD(actor: A) {} + +func test(actorSystem: FakeActorSystem) { + take(actor: DA(actorSystem: actorSystem)) // ok + takeE(actor: DA(actorSystem: actorSystem)) // ok + takeD(actor: DA(actorSystem: actorSystem)) // ok +} From 9003609f7a2450e8064e14d374f79f1661ad4809 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 30 Mar 2022 19:10:19 +0900 Subject: [PATCH 2/2] [Distributed] implemented _local more properly --- include/swift/AST/Decl.h | 26 ++++++- include/swift/AST/DiagnosticsSema.def | 6 +- include/swift/AST/Expr.h | 2 + include/swift/AST/TypeRepr.h | 27 +++++-- include/swift/AST/TypeReprNodes.def | 1 + include/swift/AST/Types.h | 33 ++++++--- include/swift/Demangling/TypeDecoder.h | 2 + include/swift/Parse/Parser.h | 10 ++- lib/AST/ASTDumper.cpp | 6 ++ lib/AST/ASTPrinter.cpp | 3 + lib/AST/ASTWalker.cpp | 4 ++ lib/AST/Decl.cpp | 8 ++- lib/AST/NameLookup.cpp | 1 + lib/AST/Type.cpp | 6 +- lib/Parse/ParseDecl.cpp | 7 ++ lib/Parse/ParsePattern.cpp | 47 +++++++++++- lib/Parse/ParseType.cpp | 20 ++++-- lib/SIL/Parser/ParseSIL.cpp | 7 +- .../Mandatory/LowerHopToActor.cpp | 2 +- lib/Sema/DerivedConformances.cpp | 6 +- lib/Sema/TypeCheckAttr.cpp | 5 +- lib/Sema/TypeCheckConcurrency.cpp | 45 ++++++++---- lib/Sema/TypeCheckDecl.cpp | 2 + lib/Sema/TypeCheckPattern.cpp | 8 +++ lib/Sema/TypeCheckType.cpp | 42 ++++++++++- lib/Serialization/Deserialization.cpp | 18 +++-- lib/Serialization/ModuleFormat.h | 4 +- lib/Serialization/Serialization.cpp | 4 +- stdlib/public/Concurrency/Actor.swift | 2 +- .../public/Distributed/DistributedActor.swift | 2 +- .../Distributed/DistributedActorSystem.swift | 2 +- .../distributed_actor_whenLocal_better.swift | 71 +++++++++++++++++++ 32 files changed, 365 insertions(+), 64 deletions(-) create mode 100644 test/Distributed/distributed_actor_whenLocal_better.swift diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 02f0969f1b8f7..3df48dfa87d85 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -4745,6 +4745,10 @@ class AbstractStorageDecl : public ValueDecl { } bool isCompileTimeConst() const; + /// Is this type a '_local' distributed actor type? + /// I.e. it is known to be local and distributed checks need not apply. + bool isKnownToBeLocal() const; + /// \returns the way 'static'/'class' should be spelled for this declaration. StaticSpellingKind getCorrectStaticSpelling() const; @@ -5537,9 +5541,12 @@ class ParamDecl : public VarDecl { /// Whether or not this parameter is '_const'. IsCompileTimeConst = 1 << 1, + + /// Whether or not this parameter is '_local'. + IsKnownToBeLocal = 1 << 2, }; - llvm::PointerIntPair> + llvm::PointerIntPair> ArgumentNameAndFlags; SourceLoc ParameterNameLoc; SourceLoc ArgumentNameLoc; @@ -5574,9 +5581,13 @@ class ParamDecl : public VarDecl { /// Whether or not this parameter is 'isolated'. IsIsolated = 1 << 2, + +// /// Whether or not this parameter is '_local'. +// IsKnownToBeLocal = 1 << 3, // FIXME: can't because "PointerIntPair with integer size too large for pointer" }; /// The default value, if any, along with flags. +// llvm::PointerIntPair> llvm::PointerIntPair> DefaultValueAndFlags; @@ -5776,6 +5787,19 @@ class ParamDecl : public VarDecl { : flags - Flags::IsIsolated); } + /// Whether or not this parameter is marked with 'isolated'. + bool isKnownToBeLocal() const { + return ArgumentNameAndFlags.getInt().contains( + ArgumentNameFlags::IsKnownToBeLocal); + } + + void setKnownToBeLocal(bool value = true) { + auto flags = ArgumentNameAndFlags.getInt(); + flags = value ? flags | ArgumentNameFlags::IsKnownToBeLocal + : flags - ArgumentNameFlags::IsKnownToBeLocal; + ArgumentNameAndFlags.setInt(flags); + } + /// Whether or not this parameter is marked with '_const'. bool isCompileTimeConst() const { return ArgumentNameAndFlags.getInt().contains( diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 21c7d117be0a2..4cdbbac960023 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4611,7 +4611,7 @@ ERROR(distributed_actor_isolated_method,none, "only 'distributed' instance methods can be called on a potentially remote distributed actor", ()) ERROR(distributed_local_cannot_be_used,none, - "'local' cannot be used in user-defined code currently", + "'_local' cannot be used in user-defined code currently", ()) ERROR(distributed_actor_func_param_not_codable,none, "parameter '%0' of type %1 in %2 does not conform to serialization requirement '%3'", @@ -4677,6 +4677,10 @@ NOTE(protocol_isolated_to_global_actor_here,none, ERROR(isolated_parameter_not_actor,none, "'isolated' parameter has non-actor type %0", (Type)) +ERROR(local_parameter_not_distributed_actor,none, + "'_local' parameter has non-distributed-actor type %0", (Type)) +ERROR(local_not_supported_in_pattern,none, + "'_local' is not support in patterns", ()) WARNING(non_sendable_param_type,none, "non-sendable type %0 %select{passed in call to %4 %2 %3|" diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 7769550838682..2810e00af77a9 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -499,6 +499,8 @@ class alignas(8) Expr : public ASTAllocated { bool printConstExprValue(llvm::raw_ostream *OS, llvm::function_ref additionalCheck) const; bool isSemanticallyConstExpr(llvm::function_ref additionalCheck = nullptr) const; + bool isKnownToBeLocal() const; + /// Returns false if this expression needs to be wrapped in parens when /// used inside of a any postfix expression, true otherwise. /// diff --git a/include/swift/AST/TypeRepr.h b/include/swift/AST/TypeRepr.h index 9f863fb317df0..3c3bf8259c9ba 100644 --- a/include/swift/AST/TypeRepr.h +++ b/include/swift/AST/TypeRepr.h @@ -962,7 +962,8 @@ class SpecifierTypeRepr : public TypeRepr { return T->getKind() == TypeReprKind::InOut || T->getKind() == TypeReprKind::Shared || T->getKind() == TypeReprKind::Owned || - T->getKind() == TypeReprKind::Isolated; + T->getKind() == TypeReprKind::Isolated || + T->getKind() == TypeReprKind::KnownToBeLocal; } static bool classof(const SpecifierTypeRepr *T) { return true; } @@ -1024,8 +1025,8 @@ class OwnedTypeRepr : public SpecifierTypeRepr { /// \endcode class IsolatedTypeRepr : public SpecifierTypeRepr { public: - IsolatedTypeRepr(TypeRepr *Base, SourceLoc InOutLoc) - : SpecifierTypeRepr(TypeReprKind::Isolated, Base, InOutLoc) {} + IsolatedTypeRepr(TypeRepr *Base, SourceLoc Loc) + : SpecifierTypeRepr(TypeReprKind::Isolated, Base, Loc) {} static bool classof(const TypeRepr *T) { return T->getKind() == TypeReprKind::Isolated; @@ -1039,8 +1040,8 @@ class IsolatedTypeRepr : public SpecifierTypeRepr { /// \endcode class CompileTimeConstTypeRepr : public SpecifierTypeRepr { public: - CompileTimeConstTypeRepr(TypeRepr *Base, SourceLoc InOutLoc) - : SpecifierTypeRepr(TypeReprKind::CompileTimeConst, Base, InOutLoc) {} + CompileTimeConstTypeRepr(TypeRepr *Base, SourceLoc Loc) + : SpecifierTypeRepr(TypeReprKind::CompileTimeConst, Base, Loc) {} static bool classof(const TypeRepr *T) { return T->getKind() == TypeReprKind::CompileTimeConst; @@ -1048,6 +1049,21 @@ class CompileTimeConstTypeRepr : public SpecifierTypeRepr { static bool classof(const CompileTimeConstTypeRepr *T) { return true; } }; +/// A '_local' type. +/// \code +/// x : _local SomeDistributedActor +/// \endcode +class KnownToBeLocalTypeRepr : public SpecifierTypeRepr { +public: + KnownToBeLocalTypeRepr(TypeRepr *Base, SourceLoc Loc) + : SpecifierTypeRepr(TypeReprKind::KnownToBeLocal, Base, Loc) {} + + static bool classof(const TypeRepr *T) { + return T->getKind() == TypeReprKind::KnownToBeLocal; + } + static bool classof(const KnownToBeLocalTypeRepr *T) { return true; } +}; + /// A TypeRepr for a known, fixed type. /// /// Fixed type representations should be used sparingly, in places @@ -1348,6 +1364,7 @@ inline bool TypeRepr::isSimple() const { case TypeReprKind::Isolated: case TypeReprKind::Placeholder: case TypeReprKind::CompileTimeConst: + case TypeReprKind::KnownToBeLocal: return true; } llvm_unreachable("bad TypeRepr kind"); diff --git a/include/swift/AST/TypeReprNodes.def b/include/swift/AST/TypeReprNodes.def index 3bb74cf05f77a..9082bb05ce9f4 100644 --- a/include/swift/AST/TypeReprNodes.def +++ b/include/swift/AST/TypeReprNodes.def @@ -63,6 +63,7 @@ ABSTRACT_TYPEREPR(Specifier, TypeRepr) TYPEREPR(Owned, SpecifierTypeRepr) TYPEREPR(Isolated, SpecifierTypeRepr) TYPEREPR(CompileTimeConst, SpecifierTypeRepr) + TYPEREPR(KnownToBeLocal, SpecifierTypeRepr) TYPEREPR(Fixed, TypeRepr) TYPEREPR(SILBox, TypeRepr) LAST_TYPEREPR(SILBox) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index d99855556fd45..9d30f7ade420e 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -775,7 +775,7 @@ class alignas(1 << TypeAlignInBits) TypeBase /// Determines whether this type conforms or inherits (if it's a protocol /// type) from `DistributedActor`. - bool isDistributedActor(); + bool isDistributedActorType(); /// Determines the element type of a known /// [Autoreleasing]Unsafe[Mutable][Raw]Pointer variant, or returns null if the @@ -1981,7 +1981,8 @@ class ParameterTypeFlags { NoDerivative = 1 << 6, Isolated = 1 << 7, CompileTimeConst = 1 << 8, - NumBits = 9 + KnownToBeLocal = 1 << 9, + NumBits = 10 }; OptionSet value; static_assert(NumBits <= 8*sizeof(OptionSet), "overflowed"); @@ -1995,21 +1996,23 @@ class ParameterTypeFlags { } ParameterTypeFlags(bool variadic, bool autoclosure, bool nonEphemeral, - ValueOwnership ownership, bool isolated, bool noDerivative, + ValueOwnership ownership, bool isolated, + bool knownToBeLocal, bool noDerivative, bool compileTimeConst) : value((variadic ? Variadic : 0) | (autoclosure ? AutoClosure : 0) | (nonEphemeral ? NonEphemeral : 0) | uint8_t(ownership) << OwnershipShift | (isolated ? Isolated : 0) | (noDerivative ? NoDerivative : 0) | - (compileTimeConst ? CompileTimeConst : 0)){} + (compileTimeConst ? CompileTimeConst : 0) | + (knownToBeLocal ? KnownToBeLocal : 0)){} /// Create one from what's present in the parameter type inline static ParameterTypeFlags fromParameterType(Type paramTy, bool isVariadic, bool isAutoClosure, bool isNonEphemeral, ValueOwnership ownership, - bool isolated, bool isNoDerivative, - bool compileTimeConst); + bool isolated, bool knownToBeLocal, + bool isNoDerivative, bool compileTimeConst); bool isNone() const { return !value; } bool isVariadic() const { return value.contains(Variadic); } @@ -2020,6 +2023,7 @@ class ParameterTypeFlags { bool isOwned() const { return getValueOwnership() == ValueOwnership::Owned; } bool isIsolated() const { return value.contains(Isolated); } bool isCompileTimeConst() const { return value.contains(CompileTimeConst); } + bool isKnownToBeLocal() const { return value.contains(KnownToBeLocal); } bool isNoDerivative() const { return value.contains(NoDerivative); } ValueOwnership getValueOwnership() const { @@ -2074,6 +2078,12 @@ class ParameterTypeFlags { : value - ParameterTypeFlags::Isolated); } + ParameterTypeFlags withKnownToBeLocal(bool local) const { + return ParameterTypeFlags(local + ? value | ParameterTypeFlags::KnownToBeLocal + : value - ParameterTypeFlags::KnownToBeLocal); + } + ParameterTypeFlags withNoDerivative(bool noDerivative) const { return ParameterTypeFlags(noDerivative ? value | ParameterTypeFlags::NoDerivative @@ -2147,7 +2157,8 @@ class YieldTypeFlags { return ParameterTypeFlags(/*variadic*/ false, /*autoclosure*/ false, /*nonEphemeral*/ false, getValueOwnership(), - /*isolated*/ false, /*noDerivative*/ false, + /*isolated*/ false, /*knownToBeLocal*/false, + /*noDerivative*/ false, /*compileTimeConst*/false); } @@ -6625,8 +6636,8 @@ inline TupleTypeElt TupleTypeElt::getWithType(Type T) const { /// Create one from what's present in the parameter decl and type inline ParameterTypeFlags ParameterTypeFlags::fromParameterType( Type paramTy, bool isVariadic, bool isAutoClosure, bool isNonEphemeral, - ValueOwnership ownership, bool isolated, bool isNoDerivative, - bool compileTimeConst) { + ValueOwnership ownership, bool isolated, bool knownToBeLocal, + bool isNoDerivative, bool compileTimeConst) { // FIXME(Remove InOut): The last caller that needs this is argument // decomposition. Start by enabling the assertion there and fixing up those // callers, then remove this, then remove @@ -6636,8 +6647,8 @@ inline ParameterTypeFlags ParameterTypeFlags::fromParameterType( ownership == ValueOwnership::InOut); ownership = ValueOwnership::InOut; } - return {isVariadic, isAutoClosure, isNonEphemeral, ownership, isolated, - isNoDerivative, compileTimeConst}; + return {isVariadic, isAutoClosure, isNonEphemeral, ownership, + isolated, knownToBeLocal, isNoDerivative, compileTimeConst}; } inline const Type *BoundGenericType::getTrailingObjectsPointer() const { diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h index 7361e0147b5b3..e0ed6dd7661fa 100644 --- a/include/swift/Demangling/TypeDecoder.h +++ b/include/swift/Demangling/TypeDecoder.h @@ -1512,6 +1512,8 @@ return {}; // Not Implemented! hasParamFlags = true; break; + // TODO: demangle _local as well? + case NodeKind::AutoClosureType: case NodeKind::EscapingAutoClosureType: param.setAutoClosure(); diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 78357e240be38..5890ce0fff7f2 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1121,6 +1121,7 @@ class Parser { ParserStatus parseTypeAttributeList(ParamDecl::Specifier &Specifier, SourceLoc &SpecifierLoc, SourceLoc &IsolatedLoc, + SourceLoc &KnownToBeLocalLoc, SourceLoc &ConstLoc, TypeAttributes &Attributes) { if (Tok.isAny(tok::at_sign, tok::kw_inout) || @@ -1128,15 +1129,18 @@ class Parser { (Tok.getRawText().equals("__shared") || Tok.getRawText().equals("__owned") || Tok.isContextualKeyword("isolated") || + Tok.isContextualKeyword("_local") || Tok.isContextualKeyword("_const")))) return parseTypeAttributeListPresent( - Specifier, SpecifierLoc, IsolatedLoc, ConstLoc, Attributes); + Specifier, SpecifierLoc, IsolatedLoc, KnownToBeLocalLoc, ConstLoc, + Attributes); return makeParserSuccess(); } ParserStatus parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier, SourceLoc &SpecifierLoc, SourceLoc &IsolatedLoc, + SourceLoc &KnownToBeLocalLoc, SourceLoc &ConstLoc, TypeAttributes &Attributes); @@ -1322,6 +1326,7 @@ class Parser { ParamDecl::Specifier Specifier, SourceLoc SpecifierLoc, SourceLoc IsolatedLoc, + SourceLoc KnownToBeLocalLoc, SourceLoc ConstLoc); //===--------------------------------------------------------------------===// @@ -1387,6 +1392,9 @@ class Parser { /// The location of the '_const' keyword, if present. SourceLoc CompileConstLoc; + /// The location of the '_local' keyword, if present. + SourceLoc KnownToBeLocalLoc; + /// The type following the ':'. TypeRepr *Type = nullptr; diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 0b61e905fc9dd..95d425d06c18b 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -3096,6 +3096,12 @@ class PrintTypeRepr : public TypeReprVisitor { PrintWithColorRAII(OS, ParenthesisColor) << ')'; } + void visitKnownToBeLocalTypeRepr(KnownToBeLocalTypeRepr *T) { + printCommon("_local") << '\n'; + printRec(T->getBase()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + void visitCompileTimeConstTypeRepr(CompileTimeConstTypeRepr *T) { printCommon("_const") << '\n'; printRec(T->getBase()); diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 000af787b4872..8196b6322c465 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3654,6 +3654,9 @@ static void printParameterFlags(ASTPrinter &printer, if (flags.isIsolated()) printer.printKeyword("isolated", options, " "); + if (flags.isKnownToBeLocal()) + printer.printKeyword("_local", options, " "); + if (!options.excludeAttrKind(TAK_escaping) && escaping) printer.printKeyword("@escaping", options, " "); diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 926d6b8b414a1..84cba8e4ab71d 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -1882,6 +1882,10 @@ bool Traversal::visitCompileTimeConstTypeRepr(CompileTimeConstTypeRepr *T) { return doIt(T->getBase()); } +bool Traversal::visitKnownToBeLocalTypeRepr(KnownToBeLocalTypeRepr *T) { + return doIt(T->getBase()); +} + bool Traversal::visitOpaqueReturnTypeRepr(OpaqueReturnTypeRepr *T) { return doIt(T->getConstraint()); } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index ba4733cb4aecf..ac2b14b963039 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -811,6 +811,10 @@ bool AbstractStorageDecl::isCompileTimeConst() const { return getAttrs().hasAttribute(); } +bool AbstractStorageDecl::isKnownToBeLocal() const { + return getAttrs().hasAttribute(); +} + bool AbstractStorageDecl::isTransparent() const { return getAttrs().hasAttribute(); } @@ -6984,8 +6988,8 @@ AnyFunctionType::Param ParamDecl::toFunctionParam(Type type) const { auto internalLabel = getParameterName(); auto flags = ParameterTypeFlags::fromParameterType( type, isVariadic(), isAutoClosure(), isNonEphemeral(), - getValueOwnership(), isIsolated(), /*isNoDerivative*/ false, - isCompileTimeConst()); + getValueOwnership(), isIsolated(), isKnownToBeLocal(), + /*isNoDerivative*/ false, isCompileTimeConst()); return AnyFunctionType::Param(type, label, flags, internalLabel); } diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 2060cb9e254f5..8262b2f898f11 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -2260,6 +2260,7 @@ directReferencesForTypeRepr(Evaluator &evaluator, case TypeReprKind::InOut: case TypeReprKind::Isolated: case TypeReprKind::CompileTimeConst: + case TypeReprKind::KnownToBeLocal: case TypeReprKind::Metatype: case TypeReprKind::Owned: case TypeReprKind::Protocol: diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index ac1e29a9c30e5..e87b2eb839e8c 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -429,7 +429,7 @@ bool TypeBase::isActorType() { return false; } -bool TypeBase::isDistributedActor() { +bool TypeBase::isDistributedActorType() { // Nominal types: check whether the declaration is an actor. if (auto *nominal = getAnyNominal()) { if (auto *classDecl = dyn_cast(nominal)) @@ -450,13 +450,11 @@ bool TypeBase::isDistributedActor() { if (!actorProto) return false; - // TODO(distributed): Inheritance is not yet supported. - auto layout = getExistentialLayout(); return llvm::any_of(layout.getProtocols(), [&actorProto](ProtocolType *protocol) { return protocol->getDecl() == actorProto || - protocol->isDistributedActor(); + protocol->isDistributedActorType(); }); } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 2bf7d0b1a1c99..f2a9d47e08928 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -4000,6 +4000,7 @@ ParserStatus Parser::parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier, SourceLoc &SpecifierLoc, SourceLoc &IsolatedLoc, + SourceLoc &KnownToBeLocalLoc, SourceLoc &ConstLoc, TypeAttributes &Attributes) { PatternBindingInitializer *initContext = nullptr; @@ -4008,6 +4009,7 @@ Parser::parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier, Tok.isContextualKeyword("__shared") || Tok.isContextualKeyword("__owned") || Tok.isContextualKeyword("isolated") || + Tok.isContextualKeyword("_local") || Tok.isContextualKeyword("_const")) { if (Tok.isContextualKeyword("isolated")) { @@ -4019,6 +4021,11 @@ Parser::parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier, continue; } + if (Tok.isContextualKeyword("_local")) { + KnownToBeLocalLoc = consumeToken(); + continue; + } + if (Tok.isContextualKeyword("_const")) { ConstLoc = consumeToken(); continue; diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index 774071d10a588..aaa718936ed6b 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -165,6 +165,7 @@ bool Parser::startsParameterName(bool isClosure) { if (nextTok.canBeArgumentLabel()) { // If the first name wasn't "isolated", we're done. if (!Tok.isContextualKeyword("isolated") && + !Tok.isContextualKeyword("_local") && !Tok.isContextualKeyword("some") && !Tok.isContextualKeyword("any")) return true; @@ -261,6 +262,7 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc, Tok.isContextualKeyword("__shared") || Tok.isContextualKeyword("__owned") || Tok.isContextualKeyword("isolated") || + Tok.isContextualKeyword("_local") || Tok.isContextualKeyword("_const")) { if (Tok.isContextualKeyword("isolated")) { @@ -289,6 +291,32 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc, continue; } + if (Tok.isContextualKeyword("_local")) { + // did we already find an '_local' type modifier? + if (param.KnownToBeLocalLoc.isValid()) { + diagnose(Tok, diag::parameter_specifier_repeated) + .fixItRemove(Tok.getLoc()); + consumeToken(); + continue; + } + + // is this '_local' token the identifier of an argument label? + bool partOfArgumentLabel = lookahead(1, [&](CancellableBacktrackingScope &) { + if (Tok.is(tok::colon)) + return true; // _local : + + // _local x : + return Tok.canBeArgumentLabel() && peekToken().is(tok::colon); + }); + + if (partOfArgumentLabel) + break; + + // consume '_local' as type modifier + param.KnownToBeLocalLoc = consumeToken(); + continue; + } + if (Tok.isContextualKeyword("_const")) { param.CompileConstLoc = consumeToken(); continue; @@ -596,6 +624,12 @@ mapParsedParameters(Parser &parser, param->setIsolated(); } + if (paramInfo.KnownToBeLocalLoc.isValid()) { + type = new (parser.Context) KnownToBeLocalTypeRepr( + type, paramInfo.KnownToBeLocalLoc); + param->setKnownToBeLocal(); + } + if (paramInfo.CompileConstLoc.isValid()) { type = new (parser.Context) CompileTimeConstTypeRepr( type, paramInfo.CompileConstLoc); @@ -623,10 +657,19 @@ mapParsedParameters(Parser &parser, } if (auto *STR = dyn_cast(unwrappedType)) { - if (isa(STR)) + if (isa(STR)) { param->setIsolated(true); + } + + if (isa(STR)) { + param->setKnownToBeLocal(true); + auto localAttr = new (parser.Context) + KnownToBeLocalAttr(paramInfo.KnownToBeLocalLoc); + param->getAttrs().add(localAttr); + } + unwrappedType = STR->getBase(); - continue;; + continue; } if (auto *CTR = dyn_cast(unwrappedType)) { diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 16feac79393db..e1ab8cc8f2413 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -38,6 +38,7 @@ TypeRepr *Parser::applyAttributeToType(TypeRepr *ty, ParamDecl::Specifier specifier, SourceLoc specifierLoc, SourceLoc isolatedLoc, + SourceLoc knownToBeLocalLoc, SourceLoc constLoc) { // Apply those attributes that do apply. if (!attrs.empty()) { @@ -66,6 +67,12 @@ TypeRepr *Parser::applyAttributeToType(TypeRepr *ty, ty = new (Context) IsolatedTypeRepr(ty, isolatedLoc); } + // Apply '_local'. + if (knownToBeLocalLoc.isValid()) { + ty = new (Context) KnownToBeLocalTypeRepr(ty, knownToBeLocalLoc); + } + + // Apply '_const'. if (constLoc.isValid()) { ty = new (Context) CompileTimeConstTypeRepr(ty, constLoc); } @@ -328,7 +335,7 @@ ParserResult Parser::parseSILBoxType(GenericParamList *generics, return makeParserResult(applyAttributeToType(repr, attrs, ParamDecl::Specifier::Owned, SourceLoc(), SourceLoc(), - SourceLoc())); + SourceLoc(), SourceLoc())); } @@ -352,10 +359,11 @@ ParserResult Parser::parseType( ParamDecl::Specifier specifier; SourceLoc specifierLoc; SourceLoc isolatedLoc; + SourceLoc knownToBeLocalLoc; SourceLoc constLoc; TypeAttributes attrs; - status |= parseTypeAttributeList(specifier, specifierLoc, isolatedLoc, constLoc, - attrs); + status |= parseTypeAttributeList(specifier, specifierLoc, isolatedLoc, + knownToBeLocalLoc, constLoc, attrs); // Parse generic parameters in SIL mode. GenericParamList *generics = nullptr; @@ -552,14 +560,14 @@ ParserResult Parser::parseType( if (tyR) tyR->walk(walker); } - if (specifierLoc.isValid() || isolatedLoc.isValid() || !attrs.empty() || - constLoc.isValid()) + if (specifierLoc.isValid() || isolatedLoc.isValid() || + knownToBeLocalLoc.isValid() || !attrs.empty() || constLoc.isValid()) SyntaxContext->setCreateSyntax(SyntaxKind::AttributedType); return makeParserResult( status, applyAttributeToType(tyR, attrs, specifier, specifierLoc, isolatedLoc, - constLoc)); + knownToBeLocalLoc, constLoc)); } ParserResult Parser::parseTypeWithOpaqueParams(Diag<> MessageID) { diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index 35e4aae6f65c6..f9857d7ee727a 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -1370,9 +1370,11 @@ bool SILParser::parseSILType(SILType &Result, ParamDecl::Specifier specifier; SourceLoc specifierLoc; SourceLoc isolatedLoc; + SourceLoc knownToBeLocalLoc; SourceLoc constLoc; TypeAttributes attrs; - P.parseTypeAttributeList(specifier, specifierLoc, isolatedLoc, constLoc, attrs); + P.parseTypeAttributeList(specifier, specifierLoc, isolatedLoc, + knownToBeLocalLoc, constLoc, attrs); // Global functions are implicitly @convention(thin) if not specified otherwise. if (IsFuncDecl && !attrs.has(TAK_convention)) { @@ -1392,7 +1394,8 @@ bool SILParser::parseSILType(SILType &Result, // Apply attributes to the type. auto *attrRepr = P.applyAttributeToType( - TyR.get(), attrs, specifier, specifierLoc, isolatedLoc, constLoc); + TyR.get(), attrs, specifier, specifierLoc, isolatedLoc, + knownToBeLocalLoc, constLoc); auto Ty = performTypeResolution(attrRepr, /*IsSILType=*/true, OuterGenericEnv, OuterGenericParams); if (OuterGenericEnv) { diff --git a/lib/SILOptimizer/Mandatory/LowerHopToActor.cpp b/lib/SILOptimizer/Mandatory/LowerHopToActor.cpp index f5f3c674cccbd..262a42d92e615 100644 --- a/lib/SILOptimizer/Mandatory/LowerHopToActor.cpp +++ b/lib/SILOptimizer/Mandatory/LowerHopToActor.cpp @@ -179,7 +179,7 @@ SILValue LowerHopToActor::emitGetExecutor(SILLocation loc, SILValue actor, auto module = F->getModule().getSwiftModule(); SILValue unmarkedExecutor; if (isDefaultActorType(actorType, module, F->getResilienceExpansion()) || - actorType->isDistributedActor()) { + actorType->isDistributedActorType()) { auto builtinName = ctx.getIdentifier( getBuiltinName(BuiltinValueKind::BuildDefaultActorExecutorRef)); auto builtinDecl = cast(getBuiltinValueDecl(ctx, builtinName)); diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp index b9a87cd225cab..ea73f7cfc443d 100644 --- a/lib/Sema/DerivedConformances.cpp +++ b/lib/Sema/DerivedConformances.cpp @@ -380,10 +380,12 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal, } } - // DistributedActor.actorSystem + // DistributedActorSystem + // .invokeHandlerOnReturn(handler:resultBuffer:metatype) if (name.isCompoundName() && - name.getBaseName() == ctx.Id_invokeHandlerOnReturn) + name.getBaseName() == ctx.Id_invokeHandlerOnReturn) { return getRequirement(KnownProtocolKind::DistributedActorSystem); + } return nullptr; } diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 0617961ce5f41..e6cafc1a761fb 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -309,6 +309,7 @@ class AttributeChecker : public AttributeVisitor { void visitReasyncAttr(ReasyncAttr *attr); void visitNonisolatedAttr(NonisolatedAttr *attr); + void visitKnownToBeLocalAttr(KnownToBeLocalAttr *attr); void visitNoImplicitCopyAttr(NoImplicitCopyAttr *attr); @@ -319,8 +320,6 @@ class AttributeChecker : public AttributeVisitor { void visitCompilerInitializedAttr(CompilerInitializedAttr *attr); void checkBackDeployAttrs(ArrayRef Attrs); - - void visitKnownToBeLocalAttr(KnownToBeLocalAttr *attr); }; } // end anonymous namespace @@ -5722,7 +5721,7 @@ void AttributeChecker::visitDistributedActorAttr(DistributedActorAttr *attr) { // distributed func must be declared inside an distributed actor auto selfTy = dc->getSelfTypeInContext(); - if (!selfTy->isDistributedActor()) { + if (!selfTy->isDistributedActorType()) { auto diagnostic = diagnoseAndRemoveAttr( attr, diag::distributed_actor_func_not_in_distributed_actor); diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index c951ed6f8ecda..8c3224f06e0a1 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -1877,7 +1877,7 @@ namespace { return nullptr; } - VarDecl *findReferencedBaseSelf(Expr *expr) { + VarDecl *findReferencedCallBase(Expr *expr) { if (auto selfVar = getReferencedParamOrCapture(expr)) if (selfVar->isSelfParameter() || selfVar->isSelfParamCapture()) return selfVar; @@ -1893,18 +1893,26 @@ namespace { expr = conversion->getSubExpr(); } while (prior != expr); + // it could be a function call if (auto call = dyn_cast(expr)) { for (auto arg : *call->getArgs()) { if (auto declRef = dyn_cast(arg.getExpr())) { if (auto var = dyn_cast(declRef->getDecl())) { - if (var->isSelfParameter()) { - return var; - } + return var; } } } } + // maybe it's a property access? + if (auto memberRef = dyn_cast(expr)) { + if (auto baseDeclRef = dyn_cast(memberRef->getBase())) { + if (auto var = dyn_cast(baseDeclRef->getDecl())) { + return var; + } + } + } + // Not a self reference. return nullptr; @@ -1970,6 +1978,8 @@ namespace { nominal->getName()); } else { // it's a function or subscript + fprintf(stderr, "[%s:%d] (%s) HERE\n", __FILE__, __LINE__, __FUNCTION__); + decl->dump(); decl->diagnose(diag::note_distributed_actor_isolated_method, decl->getDescriptiveKind(), decl->getName()); @@ -2147,6 +2157,23 @@ namespace { Optional> checkDistributedAccess(SourceLoc declLoc, ValueDecl *decl, Expr *context) { + fprintf(stderr, "[%s:%d] (%s) CON\n", __FILE__, __LINE__, __FUNCTION__); + context->dump(); + + // Check if the base of the call is known to be local; this can be true + // either when: + // - the base is `self`, which we're only allowed to call when "inside" + // the distributed actor + // - the parameter is explicitly known to be '_local' + if (auto base = findReferencedCallBase(context)) { + if (base->isSelfParameter() || + base->getAttrs().getAttribute()) { + return std::make_pair( + /*setThrows=*/false, + /*isDistributedThunk=*/false); + } + } + // Cannot reference properties or subscripts of distributed actors. if (isPropOrSubscript(decl)) { ctx.Diags.diagnose( @@ -2156,14 +2183,6 @@ namespace { return None; } - if (auto baseSelf = findReferencedBaseSelf(context)) { - if (baseSelf->getAttrs().hasAttribute()) { - return std::make_pair( - /*setThrows=*/false, - /*isDistributedThunk=*/false); - } - } - // Check that we have a distributed function. auto func = dyn_cast(decl); if (!func || !func->isDistributed()) { @@ -3074,6 +3093,8 @@ namespace { if (nominal && nominal->isDistributedActor()) { auto funcDecl = dyn_cast(member); if (funcDecl && !funcDecl->isStatic()) { + fprintf(stderr, "[%s:%d] (%s) HERE\n", __FILE__, __LINE__, __FUNCTION__); + funcDecl->dump(); member->diagnose(diag::distributed_actor_isolated_method); return true; } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 1b55bc7febfc1..23e005ece5ab2 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2067,6 +2067,8 @@ ParamSpecifierRequest::evaluate(Evaluator &evaluator, if (auto isolated = dyn_cast(nestedRepr)) nestedRepr = isolated->getBase(); + if (auto knownLocal = dyn_cast(nestedRepr)) + nestedRepr = knownLocal->getBase(); if (isa(nestedRepr) && param->isDefaultArgument()) { diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 65e35293f703a..8c5832fccaaee 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -750,6 +750,14 @@ validateTypedPattern(TypedPattern *TP, DeclContext *dc, return named->getDecl()->getDeclContext()->mapTypeIntoContext(opaqueTy); } + // TODO(distributed): `_local` is not completely implemented, and for now not + // supported in patterns + if (auto local = dyn_cast_or_null(Repr)) { + Context.Diags.diagnose(TP->getLoc(), + diag::local_not_supported_in_pattern); + return ErrorType::get(Context); + } + const auto ty = TypeResolution::resolveContextualType( Repr, dc, options, unboundTyOpener, placeholderHandler); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index b2e99abc52987..5cb5804ea784d 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1919,6 +1919,8 @@ namespace { TypeResolutionOptions options); NeverNullType resolveIsolatedTypeRepr(IsolatedTypeRepr *repr, TypeResolutionOptions options); + NeverNullType resolveKnownToBeLocalTypeRepr(KnownToBeLocalTypeRepr *repr, + TypeResolutionOptions options); NeverNullType resolveCompileTimeConstTypeRepr(CompileTimeConstTypeRepr *repr, TypeResolutionOptions options); NeverNullType resolveArrayType(ArrayTypeRepr *repr, @@ -2058,6 +2060,9 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr, case TypeReprKind::Isolated: return resolveIsolatedTypeRepr(cast(repr), options); + case TypeReprKind::KnownToBeLocal: + return resolveKnownToBeLocalTypeRepr(cast(repr), + options); case TypeReprKind::CompileTimeConst: return resolveCompileTimeConstTypeRepr(cast(repr), options); @@ -2858,6 +2863,7 @@ TypeResolver::resolveASTFunctionTypeParams(TupleTypeRepr *inputRepr, auto *nestedRepr = eltTypeRepr->getWithoutParens(); bool isolated = false; + bool knownToBeLocal = false; bool compileTimeConst = false; while (true) { if (auto *specifierRepr = dyn_cast(nestedRepr)) { @@ -2878,6 +2884,10 @@ TypeResolver::resolveASTFunctionTypeParams(TupleTypeRepr *inputRepr, isolated = true; nestedRepr = specifierRepr->getBase(); continue; + case TypeReprKind::KnownToBeLocal: + knownToBeLocal = true; + nestedRepr = specifierRepr->getBase(); + continue; case TypeReprKind::CompileTimeConst: compileTimeConst = true; nestedRepr = specifierRepr->getBase(); @@ -2906,7 +2916,7 @@ TypeResolver::resolveASTFunctionTypeParams(TupleTypeRepr *inputRepr, auto paramFlags = ParameterTypeFlags::fromParameterType( ty, variadic, autoclosure, /*isNonEphemeral*/ false, ownership, - isolated, noDerivative, compileTimeConst); + isolated, knownToBeLocal, noDerivative, compileTimeConst); elements.emplace_back(ty, Identifier(), paramFlags, inputRepr->getElementName(i)); } @@ -3565,6 +3575,9 @@ TypeResolver::resolveSpecifierTypeRepr(SpecifierTypeRepr *repr, case TypeReprKind::Owned: name = "__owned"; break; + case TypeReprKind::KnownToBeLocal: + name = "_local"; + break; default: llvm_unreachable("unknown SpecifierTypeRepr kind"); } @@ -3605,6 +3618,32 @@ TypeResolver::resolveIsolatedTypeRepr(IsolatedTypeRepr *repr, return type; } +NeverNullType +TypeResolver::resolveKnownToBeLocalTypeRepr(KnownToBeLocalTypeRepr *repr, + TypeResolutionOptions options) { +// // '_local' is only value for non-EnumCaseDecl parameters. +// if (!options.is(TypeResolverContext::FunctionInput) || +// options.hasBase(TypeResolverContext::EnumElementDecl)) { +// diagnoseInvalid( +// repr, repr->getSpecifierLoc(), diag::attr_only_on_parameters, +// "_local"); +// return ErrorType::get(getASTContext()); +// } + Type type = resolveType(repr->getBase(), options); + + // isolated parameters must be of 'distributed actor' type + if (!type->hasTypeParameter() && + !type->isDistributedActorType() && + !type->hasError()) { + diagnoseInvalid( + repr, repr->getSpecifierLoc(), + diag::local_parameter_not_distributed_actor, type); + return ErrorType::get(type); + } + + return type; +} + NeverNullType TypeResolver::resolveCompileTimeConstTypeRepr(CompileTimeConstTypeRepr *repr, TypeResolutionOptions options) { @@ -4208,6 +4247,7 @@ class ExistentialTypeVisitor case TypeReprKind::Shared: case TypeReprKind::Owned: case TypeReprKind::Isolated: + case TypeReprKind::KnownToBeLocal: case TypeReprKind::Placeholder: case TypeReprKind::CompileTimeConst: return false; diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 7aae3ac33f3dd..bebb44d625b00 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -3220,6 +3220,7 @@ class DeclDeserializer { bool isVariadic; bool isAutoClosure; bool isIsolated; + bool isKnownToBeLocal; bool isCompileTimeConst; uint8_t rawDefaultArg; TypeID defaultExprType; @@ -3228,6 +3229,7 @@ class DeclDeserializer { contextID, rawSpecifier, interfaceTypeID, isIUO, isVariadic, isAutoClosure, isIsolated, + isKnownToBeLocal, isCompileTimeConst, rawDefaultArg, defaultExprType); @@ -3265,6 +3267,11 @@ class DeclDeserializer { param->setVariadic(isVariadic); param->setAutoClosure(isAutoClosure); param->setIsolated(isIsolated); + param->setKnownToBeLocal(isKnownToBeLocal); + if (isKnownToBeLocal) { + fprintf(stderr, "[%s:%d] (%s) KNOWN LOCAL:\n", __FILE__, __LINE__, __FUNCTION__); + param->dump(); + } param->setCompileTimeConst(isCompileTimeConst); // Decode the default argument kind. @@ -5478,13 +5485,14 @@ class TypeDeserializer { IdentifierID labelID; IdentifierID internalLabelID; TypeID typeID; - bool isVariadic, isAutoClosure, isNonEphemeral, isIsolated, isCompileTimeConst; + bool isVariadic, isAutoClosure, isNonEphemeral, isIsolated, + isKnownToBeLocal, isCompileTimeConst; bool isNoDerivative; unsigned rawOwnership; decls_block::FunctionParamLayout::readRecord( scratch, labelID, internalLabelID, typeID, isVariadic, isAutoClosure, - isNonEphemeral, rawOwnership, isIsolated, isNoDerivative, - isCompileTimeConst); + isNonEphemeral, rawOwnership, isIsolated, isKnownToBeLocal, + isNoDerivative, isCompileTimeConst); auto ownership = getActualValueOwnership((serialization::ValueOwnership)rawOwnership); @@ -5498,8 +5506,8 @@ class TypeDeserializer { params.emplace_back(paramTy.get(), MF.getIdentifier(labelID), ParameterTypeFlags(isVariadic, isAutoClosure, isNonEphemeral, *ownership, - isIsolated, isNoDerivative, - isCompileTimeConst), + isIsolated, isKnownToBeLocal, + isNoDerivative, isCompileTimeConst), MF.getIdentifier(internalLabelID)); } diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 6d8c45c536db9..9b86a64d6ce8b 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -56,7 +56,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 682; // Remove unused instructions +const uint16_t SWIFTMODULE_VERSION_MINOR = 683; // Add _local parameter attribute /// A standard hash seed used for all string hashes in a serialized module. /// @@ -1053,6 +1053,7 @@ namespace decls_block { BCFixed<1>, // non-ephemeral? ValueOwnershipField, // inout, shared or owned? BCFixed<1>, // isolated + BCFixed<1>, // knownToBeLocal? BCFixed<1>, // noDerivative? BCFixed<1> // compileTimeConst >; @@ -1376,6 +1377,7 @@ namespace decls_block { BCFixed<1>, // isVariadic? BCFixed<1>, // isAutoClosure? BCFixed<1>, // isIsolated? + BCFixed<1>, // isKnownToBeLocal? BCFixed<1>, // isCompileTimeConst? DefaultArgumentField, // default argument kind TypeIDField, // default argument type diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 58ffb29850e7e..cc8c4bc4da910 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3814,6 +3814,7 @@ class Serializer::DeclSerializer : public DeclVisitor { param->isVariadic(), param->isAutoClosure(), param->isIsolated(), + param->isKnownToBeLocal(), param->isCompileTimeConst(), getRawStableDefaultArgumentKind(argKind), S.addTypeRef(defaultExprType), @@ -4620,7 +4621,8 @@ class Serializer::TypeSerializer : public TypeVisitor { S.addDeclBaseNameRef(param.getInternalLabel()), S.addTypeRef(param.getPlainType()), paramFlags.isVariadic(), paramFlags.isAutoClosure(), paramFlags.isNonEphemeral(), rawOwnership, - paramFlags.isIsolated(), paramFlags.isNoDerivative(), + paramFlags.isIsolated(), paramFlags.isKnownToBeLocal(), + paramFlags.isNoDerivative(), paramFlags.isCompileTimeConst()); } } diff --git a/stdlib/public/Concurrency/Actor.swift b/stdlib/public/Concurrency/Actor.swift index c8abc4ef078eb..0b38837e155cd 100644 --- a/stdlib/public/Concurrency/Actor.swift +++ b/stdlib/public/Concurrency/Actor.swift @@ -35,7 +35,7 @@ public protocol AnyActor: AnyObject, Sendable {} /// The `Actor` protocol generalizes over all `actor` types. Actor types /// implicitly conform to this protocol. @available(SwiftStdlib 5.1, *) -public protocol Actor: AnyActor, Sendable { +public protocol Actor: AnyActor { /// Retrieve the executor for this actor as an optimized, unowned /// reference. diff --git a/stdlib/public/Distributed/DistributedActor.swift b/stdlib/public/Distributed/DistributedActor.swift index 24f7d22a1d6ef..288ef6c13dc02 100644 --- a/stdlib/public/Distributed/DistributedActor.swift +++ b/stdlib/public/Distributed/DistributedActor.swift @@ -140,7 +140,7 @@ extension DistributedActor { /// /// When the actor is remote, the closure won't be executed and this function will return nil. public nonisolated func whenLocal( - _ body: @Sendable (isolated Self) async throws -> T + _ body: @Sendable (_local Self) async throws -> T ) async rethrows -> T? { if __isLocalActor(self) { return try await body(self) diff --git a/stdlib/public/Distributed/DistributedActorSystem.swift b/stdlib/public/Distributed/DistributedActorSystem.swift index 65fcf9c302a77..7cff785709eab 100644 --- a/stdlib/public/Distributed/DistributedActorSystem.swift +++ b/stdlib/public/Distributed/DistributedActorSystem.swift @@ -333,7 +333,7 @@ extension DistributedActorSystem { do { let returnType = try invocationDecoder.decodeReturnType() ?? returnTypeFromTypeInfo - // let errorType = try invocationDecoder.decodeErrorType() // TODO(distributed): decide how to use? + _ = try invocationDecoder.decodeErrorType() // TODO(distributed): decide how to use? // Execute the target! try await _executeDistributedTarget( diff --git a/test/Distributed/distributed_actor_whenLocal_better.swift b/test/Distributed/distributed_actor_whenLocal_better.swift new file mode 100644 index 0000000000000..ddb6357c52c38 --- /dev/null +++ b/test/Distributed/distributed_actor_whenLocal_better.swift @@ -0,0 +1,71 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/Inputs/FakeDistributedActorSystems.swift +// RUN: %target-swift-frontend -typecheck -verify -enable-experimental-distributed -disable-availability-checking -I %t 2>&1 %s +// REQUIRES: concurrency +// REQUIRES: distributed + +import Distributed +import FakeDistributedActorSystems + +typealias DefaultDistributedActorSystem = FakeActorSystem + +func nope(test: _local String) { + // expected-error@-1{{'_local' cannot be used in user-defined code currently}} + // expected-error@-2{{'_local' parameter has non-distributed-actor type 'String'}} +} + +func nopeDA(test: _local DA) { + // expected-error@-1{{'_local' cannot be used in user-defined code currently}} +} + +func nopeDAG(test: _local D) where D: DistributedActor { + // expected-error@-1{{'_local' cannot be used in user-defined code currently}} +} + +struct NotCodable {} + +distributed actor DA { + // normally not accessible because distributed actor protection + let constant: NotCodable = .init() + + // normally not accessible because distributed actor protection + func hi() -> String { "yay" } + + func justChecking() { } + // expected-note@-1{{distributed actor-isolated instance method 'justChecking()' declared here}} +} + +func test(actorSystem: FakeActorSystem) async { + let da = DA(actorSystem: actorSystem) + + let x: _local DA = da // expected-error{{'_local' is not support in patterns}} + + // Double check normal distributed isolation still works: + await da.justChecking() + // expected-error@-1{{only 'distributed' instance methods can be called on a potentially remote distributed actor}} + + // === WhenLocal + // --- functions + _ = await da.whenLocal { (myself: _local DA) in // can spell this + await myself.hi() // ok! Safely by-passed distributed actor isolation + } + // FIXME(distributed): _local must be spelled out in the closure nowadays, remove this limitation +// _ = await da.whenLocal { myself in +// await myself.hi() +// } + + // --- properties + _ = await da.whenLocal { (myself: _local DA) in + myself.constant // ok! Safely by-passed distributed actor isolation + } + + // === Passing Around a known to be local distributed actor + let closure: (_local DA) async -> String = { (da: _local DA) in + await da.hi() + } + _ = await closure(da) + // FIXME(distributed): _local must be spelled out in the closure nowadays, remove this limitation +// let closure: (_local DA) async -> String = { da in +// await da.hi() +// } +}