diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h index 54232972ca9fd..e45629dce240a 100644 --- a/include/swift/ABI/MetadataValues.h +++ b/include/swift/ABI/MetadataValues.h @@ -1177,6 +1177,9 @@ namespace SpecialPointerAuthDiscriminators { /// Resilient class stub initializer callback const uint16_t ResilientClassStubInitCallback = 0xC671; + + /// Actor enqueue(partialTask:). + const uint16_t ActorEnqueuePartialTask = 0x8f3d; } /// The number of arguments that will be passed directly to a generic diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index 93d8308bb34cc..bd0af44538512 100644 --- a/include/swift/AST/Attr.def +++ b/include/swift/AST/Attr.def @@ -567,7 +567,7 @@ SIMPLE_DECL_ATTR(asyncHandler, AsyncHandler, 101) CONTEXTUAL_SIMPLE_DECL_ATTR(actor, Actor, - OnClass | ConcurrencyOnly | + DeclModifier | OnClass | ConcurrencyOnly | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove, 102) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 87568606192d5..3c279e4a2e640 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -70,6 +70,7 @@ namespace swift { class BraceStmt; class DeclAttributes; class GenericContext; + class GenericParamList; class GenericSignature; class GenericTypeParamDecl; class GenericTypeParamType; @@ -88,6 +89,7 @@ namespace swift { class ProtocolType; struct RawComment; enum class ResilienceExpansion : unsigned; + class TrailingWhereClause; class TypeAliasDecl; class Stmt; class SubscriptDecl; @@ -1011,364 +1013,6 @@ void *allocateMemoryForDecl(AllocatorTy &allocator, size_t baseSize, return mem; } -enum class RequirementReprKind : unsigned { - /// A type bound T : P, where T is a type that depends on a generic - /// parameter and P is some type that should bound T, either as a concrete - /// supertype or a protocol to which T must conform. - TypeConstraint, - - /// A same-type requirement T == U, where T and U are types that shall be - /// equivalent. - SameType, - - /// A layout bound T : L, where T is a type that depends on a generic - /// parameter and L is some layout specification that should bound T. - LayoutConstraint, - - // Note: there is code that packs this enum in a 2-bit bitfield. Audit users - // when adding enumerators. -}; - -/// A single requirement in a 'where' clause, which places additional -/// restrictions on the generic parameters or associated types of a generic -/// function, type, or protocol. -/// -/// This always represents a requirement spelled in the source code. It is -/// never generated implicitly. -/// -/// \c GenericParamList assumes these are POD-like. -class RequirementRepr { - SourceLoc SeparatorLoc; - RequirementReprKind Kind : 2; - bool Invalid : 1; - TypeRepr *FirstType; - - /// The second element represents the right-hand side of the constraint. - /// It can be e.g. a type or a layout constraint. - union { - TypeRepr *SecondType; - LayoutConstraintLoc SecondLayout; - }; - - /// Set during deserialization; used to print out the requirements accurately - /// for the generated interface. - StringRef AsWrittenString; - - RequirementRepr(SourceLoc SeparatorLoc, RequirementReprKind Kind, - TypeRepr *FirstType, TypeRepr *SecondType) - : SeparatorLoc(SeparatorLoc), Kind(Kind), Invalid(false), - FirstType(FirstType), SecondType(SecondType) { } - - RequirementRepr(SourceLoc SeparatorLoc, RequirementReprKind Kind, - TypeRepr *FirstType, LayoutConstraintLoc SecondLayout) - : SeparatorLoc(SeparatorLoc), Kind(Kind), Invalid(false), - FirstType(FirstType), SecondLayout(SecondLayout) { } - - void printImpl(ASTPrinter &OS) const; - -public: - /// Construct a new type-constraint requirement. - /// - /// \param Subject The type that must conform to the given protocol or - /// composition, or be a subclass of the given class type. - /// \param ColonLoc The location of the ':', or an invalid location if - /// this requirement was implied. - /// \param Constraint The protocol or protocol composition to which the - /// subject must conform, or superclass from which the subject must inherit. - static RequirementRepr getTypeConstraint(TypeRepr *Subject, - SourceLoc ColonLoc, - TypeRepr *Constraint) { - return { ColonLoc, RequirementReprKind::TypeConstraint, Subject, Constraint }; - } - - /// Construct a new same-type requirement. - /// - /// \param FirstType The first type. - /// \param EqualLoc The location of the '==' in the same-type constraint, or - /// an invalid location if this requirement was implied. - /// \param SecondType The second type. - static RequirementRepr getSameType(TypeRepr *FirstType, - SourceLoc EqualLoc, - TypeRepr *SecondType) { - return { EqualLoc, RequirementReprKind::SameType, FirstType, SecondType }; - } - - /// Construct a new layout-constraint requirement. - /// - /// \param Subject The type that must conform to the given layout - /// requirement. - /// \param ColonLoc The location of the ':', or an invalid location if - /// this requirement was implied. - /// \param Layout The layout requirement to which the - /// subject must conform. - static RequirementRepr getLayoutConstraint(TypeRepr *Subject, - SourceLoc ColonLoc, - LayoutConstraintLoc Layout) { - return {ColonLoc, RequirementReprKind::LayoutConstraint, Subject, - Layout}; - } - - /// Determine the kind of requirement - RequirementReprKind getKind() const { return Kind; } - - /// Determine whether this requirement is invalid. - bool isInvalid() const { return Invalid; } - - /// Mark this requirement invalid. - void setInvalid() { Invalid = true; } - - /// For a type-bound requirement, return the subject of the - /// conformance relationship. - TypeRepr *getSubjectRepr() const { - assert(getKind() == RequirementReprKind::TypeConstraint || - getKind() == RequirementReprKind::LayoutConstraint); - return FirstType; - } - - /// For a type-bound requirement, return the protocol or to which - /// the subject conforms or superclass it inherits. - TypeRepr *getConstraintRepr() const { - assert(getKind() == RequirementReprKind::TypeConstraint); - return SecondType; - } - - LayoutConstraint getLayoutConstraint() const { - assert(getKind() == RequirementReprKind::LayoutConstraint); - return SecondLayout.getLayoutConstraint(); - } - - LayoutConstraintLoc &getLayoutConstraintLoc() { - assert(getKind() == RequirementReprKind::LayoutConstraint); - return SecondLayout; - } - - const LayoutConstraintLoc &getLayoutConstraintLoc() const { - assert(getKind() == RequirementReprKind::LayoutConstraint); - return SecondLayout; - } - - /// Retrieve the first type of a same-type requirement. - TypeRepr *getFirstTypeRepr() const { - assert(getKind() == RequirementReprKind::SameType); - return FirstType; - } - - /// Retrieve the second type of a same-type requirement. - TypeRepr *getSecondTypeRepr() const { - assert(getKind() == RequirementReprKind::SameType); - return SecondType; - } - - /// Retrieve the location of the ':' or '==' in an explicitly-written - /// conformance or same-type requirement respectively. - SourceLoc getSeparatorLoc() const { - return SeparatorLoc; - } - - SourceRange getSourceRange() const; - - /// Retrieve the first or subject type representation from the \c repr, - /// or \c nullptr if \c repr is null. - static TypeRepr *getFirstTypeRepr(const RequirementRepr *repr) { - if (!repr) return nullptr; - return repr->FirstType; - } - - /// Retrieve the second or constraint type representation from the \c repr, - /// or \c nullptr if \c repr is null. - static TypeRepr *getSecondTypeRepr(const RequirementRepr *repr) { - if (!repr) return nullptr; - assert(repr->getKind() == RequirementReprKind::TypeConstraint || - repr->getKind() == RequirementReprKind::SameType); - return repr->SecondType; - } - - SWIFT_DEBUG_DUMP; - void print(raw_ostream &OS) const; - void print(ASTPrinter &Printer) const; -}; - -using GenericParamSource = PointerUnion; - -/// GenericParamList - A list of generic parameters that is part of a generic -/// function or type, along with extra requirements placed on those generic -/// parameters and types derived from them. -class GenericParamList final : - private llvm::TrailingObjects { - friend TrailingObjects; - - SourceRange Brackets; - unsigned NumParams; - SourceLoc WhereLoc; - MutableArrayRef Requirements; - - GenericParamList *OuterParameters; - - GenericParamList(SourceLoc LAngleLoc, - ArrayRef Params, - SourceLoc WhereLoc, - MutableArrayRef Requirements, - SourceLoc RAngleLoc); - - // Don't copy. - GenericParamList(const GenericParamList &) = delete; - GenericParamList &operator=(const GenericParamList &) = delete; - -public: - /// create - Create a new generic parameter list within the given AST context. - /// - /// \param Context The ASTContext in which the generic parameter list will - /// be allocated. - /// \param LAngleLoc The location of the opening angle bracket ('<') - /// \param Params The list of generic parameters, which will be copied into - /// ASTContext-allocated memory. - /// \param RAngleLoc The location of the closing angle bracket ('>') - static GenericParamList *create(ASTContext &Context, - SourceLoc LAngleLoc, - ArrayRef Params, - SourceLoc RAngleLoc); - - /// create - Create a new generic parameter list and "where" clause within - /// the given AST context. - /// - /// \param Context The ASTContext in which the generic parameter list will - /// be allocated. - /// \param LAngleLoc The location of the opening angle bracket ('<') - /// \param Params The list of generic parameters, which will be copied into - /// ASTContext-allocated memory. - /// \param WhereLoc The location of the 'where' keyword, if any. - /// \param Requirements The list of requirements, which will be copied into - /// ASTContext-allocated memory. - /// \param RAngleLoc The location of the closing angle bracket ('>') - static GenericParamList *create(const ASTContext &Context, - SourceLoc LAngleLoc, - ArrayRef Params, - SourceLoc WhereLoc, - ArrayRef Requirements, - SourceLoc RAngleLoc); - - MutableArrayRef getParams() { - return {getTrailingObjects(), NumParams}; - } - - ArrayRef getParams() const { - return {getTrailingObjects(), NumParams}; - } - - using iterator = GenericTypeParamDecl **; - using const_iterator = const GenericTypeParamDecl * const *; - - unsigned size() const { return NumParams; } - iterator begin() { return getParams().begin(); } - iterator end() { return getParams().end(); } - const_iterator begin() const { return getParams().begin(); } - const_iterator end() const { return getParams().end(); } - - /// Retrieve the location of the 'where' keyword, or an invalid - /// location if 'where' was not present. - SourceLoc getWhereLoc() const { return WhereLoc; } - - /// Retrieve the set of additional requirements placed on these - /// generic parameters and types derived from them. - /// - /// This list may contain both explicitly-written requirements as well as - /// implicitly-generated requirements, and may be non-empty even if no - /// 'where' keyword is present. - MutableArrayRef getRequirements() { return Requirements; } - - /// Retrieve the set of additional requirements placed on these - /// generic parameters and types derived from them. - /// - /// This list may contain both explicitly-written requirements as well as - /// implicitly-generated requirements, and may be non-empty even if no - /// 'where' keyword is present. - ArrayRef getRequirements() const { return Requirements; } - - /// Retrieve the outer generic parameter list. - /// - /// This is used for extensions of nested types, and in SIL mode, where a - /// single lexical context can have multiple logical generic parameter - /// lists. - GenericParamList *getOuterParameters() const { return OuterParameters; } - - /// Set the outer generic parameter list. See \c getOuterParameters - /// for more information. - void setOuterParameters(GenericParamList *Outer) { OuterParameters = Outer; } - - void setDeclContext(DeclContext *dc); - - SourceLoc getLAngleLoc() const { return Brackets.Start; } - SourceLoc getRAngleLoc() const { return Brackets.End; } - - SourceRange getSourceRange() const { return Brackets; } - - /// Retrieve the source range covering the where clause. - SourceRange getWhereClauseSourceRange() const { - if (WhereLoc.isInvalid()) - return SourceRange(); - - auto endLoc = Requirements.back().getSourceRange().End; - return SourceRange(WhereLoc, endLoc); - } - - /// Configure the depth of the generic parameters in this list. - void setDepth(unsigned depth); - - /// Create a copy of the generic parameter list and all of its generic - /// parameter declarations. The copied generic parameters are re-parented - /// to the given DeclContext. - GenericParamList *clone(DeclContext *dc) const; - - void print(raw_ostream &OS) const; - SWIFT_DEBUG_DUMP; - - bool walk(ASTWalker &walker); - - /// Finds a generic parameter declaration by name. This should only - /// be used from the SIL parser. - GenericTypeParamDecl *lookUpGenericParam(Identifier name) const; -}; - -/// A trailing where clause. -class alignas(RequirementRepr) TrailingWhereClause final : - private llvm::TrailingObjects { - friend TrailingObjects; - - SourceLoc WhereLoc; - - /// The number of requirements. The actual requirements are tail-allocated. - unsigned NumRequirements; - - TrailingWhereClause(SourceLoc whereLoc, - ArrayRef requirements); - -public: - /// Create a new trailing where clause with the given set of requirements. - static TrailingWhereClause *create(ASTContext &ctx, SourceLoc whereLoc, - ArrayRef requirements); - - /// Retrieve the location of the 'where' keyword. - SourceLoc getWhereLoc() const { return WhereLoc; } - - /// Retrieve the set of requirements. - MutableArrayRef getRequirements() { - return {getTrailingObjects(), NumRequirements}; - } - - /// Retrieve the set of requirements. - ArrayRef getRequirements() const { - return {getTrailingObjects(), NumRequirements}; - } - - /// Compute the source range containing this trailing where clause. - SourceRange getSourceRange() const { - return SourceRange(WhereLoc, - getRequirements().back().getSourceRange().End); - } - - void print(llvm::raw_ostream &OS, bool printWhereKeyword) const; -}; - // A private class for forcing exact field layout. class alignas(8) _GenericContext { // Not really public. See GenericContext. @@ -4172,6 +3816,7 @@ enum class KnownDerivableProtocolKind : uint8_t { Decodable, AdditiveArithmetic, Differentiable, + Actor, }; /// ProtocolDecl - A declaration of a protocol, for example: @@ -6325,6 +5970,14 @@ class FuncDecl : public AbstractFunctionDecl { bool isMainTypeMainMethod() const; + /// Whether the given name is enqueue(partialTask:), which is used for + /// actors. + static bool isEnqueuePartialTaskName(ASTContext &ctx, DeclName name); + + /// Determine whether this function is the witness to the Actor protocol's + /// enqueue(partialTask:) operation within an actor. + bool isActorEnqueuePartialTaskWitness() const; + SelfAccessKind getSelfAccessKind() const; void setSelfAccessKind(SelfAccessKind mod) { diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index e27bdb0847cd8..6bd1a32a6eb76 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4101,6 +4101,9 @@ ERROR(not_objc_function_async,none, "'async' function cannot be represented in Objective-C", ()) NOTE(not_objc_function_type_async,none, "'async' function types cannot be represented in Objective-C", ()) +ERROR(actor_isolated_objc,none, + "actor-isolated %0 %1 cannot be @objc", + (DescriptiveDeclKind, DeclName)) NOTE(protocol_witness_async_conflict,none, "candidate is %select{not |}0'async', but protocol requirement is%select{| not}0", (bool)) @@ -4195,6 +4198,13 @@ ERROR(actorisolated_not_actor_instance_member,none, "'@actorIsolated' can only be applied to instance members of actors", ()) +ERROR(concurrency_lib_missing,none, + "missing '%0' declaration, probably because the '_Concurrency' " + "module was not imported", (StringRef)) +ERROR(enqueue_partial_task_not_in_context,none, + "'enqueue(partialTask:)' can only be implemented in the definition of " + "actor class %0", (Type)) + //------------------------------------------------------------------------------ // MARK: Type Check Types //------------------------------------------------------------------------------ diff --git a/include/swift/AST/GenericEnvironment.h b/include/swift/AST/GenericEnvironment.h index a47067b940fa7..3c269644ea980 100644 --- a/include/swift/AST/GenericEnvironment.h +++ b/include/swift/AST/GenericEnvironment.h @@ -18,8 +18,9 @@ #define SWIFT_AST_GENERIC_ENVIRONMENT_H #include "swift/AST/SubstitutionMap.h" -#include "swift/AST/GenericSignature.h" #include "swift/AST/GenericParamKey.h" +#include "swift/AST/GenericParamList.h" +#include "swift/AST/GenericSignature.h" #include "swift/Basic/Compiler.h" #include "swift/Basic/Debug.h" #include "llvm/ADT/ArrayRef.h" diff --git a/include/swift/AST/GenericParamList.h b/include/swift/AST/GenericParamList.h new file mode 100644 index 0000000000000..2d3b8c34475c3 --- /dev/null +++ b/include/swift/AST/GenericParamList.h @@ -0,0 +1,392 @@ +//===--- GenericParamList.h - Generic parameter list AST --------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 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 defines the GenericParamList class, and related classes. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_GENERIC_PARAM_LIST_H +#define SWIFT_GENERIC_PARAM_LIST_H + +#include "swift/AST/Decl.h" +#include "swift/AST/LayoutConstraint.h" +#include "swift/Basic/SourceLoc.h" +#include "llvm/ADT/StringRef.h" + +namespace swift { + +class ASTPrinter; +class TypeRepr; + +enum class RequirementReprKind : unsigned { + /// A type bound T : P, where T is a type that depends on a generic + /// parameter and P is some type that should bound T, either as a concrete + /// supertype or a protocol to which T must conform. + TypeConstraint, + + /// A same-type requirement T == U, where T and U are types that shall be + /// equivalent. + SameType, + + /// A layout bound T : L, where T is a type that depends on a generic + /// parameter and L is some layout specification that should bound T. + LayoutConstraint, + + // Note: there is code that packs this enum in a 2-bit bitfield. Audit users + // when adding enumerators. +}; + +/// A single requirement in a 'where' clause, which places additional +/// restrictions on the generic parameters or associated types of a generic +/// function, type, or protocol. +/// +/// This always represents a requirement spelled in the source code. It is +/// never generated implicitly. +/// +/// \c GenericParamList assumes these are POD-like. + +class RequirementRepr { + SourceLoc SeparatorLoc; + RequirementReprKind Kind : 2; + bool Invalid : 1; + TypeRepr *FirstType; + + /// The second element represents the right-hand side of the constraint. + /// It can be e.g. a type or a layout constraint. + union { + TypeRepr *SecondType; + LayoutConstraintLoc SecondLayout; + }; + + /// Set during deserialization; used to print out the requirements accurately + /// for the generated interface. + StringRef AsWrittenString; + + RequirementRepr(SourceLoc SeparatorLoc, RequirementReprKind Kind, + TypeRepr *FirstType, TypeRepr *SecondType) + : SeparatorLoc(SeparatorLoc), Kind(Kind), Invalid(false), + FirstType(FirstType), SecondType(SecondType) { } + + RequirementRepr(SourceLoc SeparatorLoc, RequirementReprKind Kind, + TypeRepr *FirstType, LayoutConstraintLoc SecondLayout) + : SeparatorLoc(SeparatorLoc), Kind(Kind), Invalid(false), + FirstType(FirstType), SecondLayout(SecondLayout) { } + + void printImpl(ASTPrinter &OS) const; + +public: + /// Construct a new type-constraint requirement. + /// + /// \param Subject The type that must conform to the given protocol or + /// composition, or be a subclass of the given class type. + /// \param ColonLoc The location of the ':', or an invalid location if + /// this requirement was implied. + /// \param Constraint The protocol or protocol composition to which the + /// subject must conform, or superclass from which the subject must inherit. + static RequirementRepr getTypeConstraint(TypeRepr *Subject, + SourceLoc ColonLoc, + TypeRepr *Constraint) { + return { ColonLoc, RequirementReprKind::TypeConstraint, Subject, Constraint }; + } + + /// Construct a new same-type requirement. + /// + /// \param FirstType The first type. + /// \param EqualLoc The location of the '==' in the same-type constraint, or + /// an invalid location if this requirement was implied. + /// \param SecondType The second type. + static RequirementRepr getSameType(TypeRepr *FirstType, + SourceLoc EqualLoc, + TypeRepr *SecondType) { + return { EqualLoc, RequirementReprKind::SameType, FirstType, SecondType }; + } + + /// Construct a new layout-constraint requirement. + /// + /// \param Subject The type that must conform to the given layout + /// requirement. + /// \param ColonLoc The location of the ':', or an invalid location if + /// this requirement was implied. + /// \param Layout The layout requirement to which the + /// subject must conform. + static RequirementRepr getLayoutConstraint(TypeRepr *Subject, + SourceLoc ColonLoc, + LayoutConstraintLoc Layout) { + return {ColonLoc, RequirementReprKind::LayoutConstraint, Subject, + Layout}; + } + + /// Determine the kind of requirement + RequirementReprKind getKind() const { return Kind; } + + /// Determine whether this requirement is invalid. + bool isInvalid() const { return Invalid; } + + /// Mark this requirement invalid. + void setInvalid() { Invalid = true; } + + /// For a type-bound requirement, return the subject of the + /// conformance relationship. + TypeRepr *getSubjectRepr() const { + assert(getKind() == RequirementReprKind::TypeConstraint || + getKind() == RequirementReprKind::LayoutConstraint); + return FirstType; + } + + /// For a type-bound requirement, return the protocol or to which + /// the subject conforms or superclass it inherits. + TypeRepr *getConstraintRepr() const { + assert(getKind() == RequirementReprKind::TypeConstraint); + return SecondType; + } + + LayoutConstraint getLayoutConstraint() const { + assert(getKind() == RequirementReprKind::LayoutConstraint); + return SecondLayout.getLayoutConstraint(); + } + + LayoutConstraintLoc &getLayoutConstraintLoc() { + assert(getKind() == RequirementReprKind::LayoutConstraint); + return SecondLayout; + } + + const LayoutConstraintLoc &getLayoutConstraintLoc() const { + assert(getKind() == RequirementReprKind::LayoutConstraint); + return SecondLayout; + } + + /// Retrieve the first type of a same-type requirement. + TypeRepr *getFirstTypeRepr() const { + assert(getKind() == RequirementReprKind::SameType); + return FirstType; + } + + /// Retrieve the second type of a same-type requirement. + TypeRepr *getSecondTypeRepr() const { + assert(getKind() == RequirementReprKind::SameType); + return SecondType; + } + + /// Retrieve the location of the ':' or '==' in an explicitly-written + /// conformance or same-type requirement respectively. + SourceLoc getSeparatorLoc() const { + return SeparatorLoc; + } + + SourceRange getSourceRange() const; + + /// Retrieve the first or subject type representation from the \c repr, + /// or \c nullptr if \c repr is null. + static TypeRepr *getFirstTypeRepr(const RequirementRepr *repr) { + if (!repr) return nullptr; + return repr->FirstType; + } + + /// Retrieve the second or constraint type representation from the \c repr, + /// or \c nullptr if \c repr is null. + static TypeRepr *getSecondTypeRepr(const RequirementRepr *repr) { + if (!repr) return nullptr; + assert(repr->getKind() == RequirementReprKind::TypeConstraint || + repr->getKind() == RequirementReprKind::SameType); + return repr->SecondType; + } + + SWIFT_DEBUG_DUMP; + void print(raw_ostream &OS) const; + void print(ASTPrinter &Printer) const; +}; + +using GenericParamSource = PointerUnion; + +/// GenericParamList - A list of generic parameters that is part of a generic +/// function or type, along with extra requirements placed on those generic +/// parameters and types derived from them. +class GenericParamList final : + private llvm::TrailingObjects { + friend TrailingObjects; + + SourceRange Brackets; + unsigned NumParams; + SourceLoc WhereLoc; + MutableArrayRef Requirements; + + GenericParamList *OuterParameters; + + GenericParamList(SourceLoc LAngleLoc, + ArrayRef Params, + SourceLoc WhereLoc, + MutableArrayRef Requirements, + SourceLoc RAngleLoc); + + // Don't copy. + GenericParamList(const GenericParamList &) = delete; + GenericParamList &operator=(const GenericParamList &) = delete; + +public: + /// create - Create a new generic parameter list within the given AST context. + /// + /// \param Context The ASTContext in which the generic parameter list will + /// be allocated. + /// \param LAngleLoc The location of the opening angle bracket ('<') + /// \param Params The list of generic parameters, which will be copied into + /// ASTContext-allocated memory. + /// \param RAngleLoc The location of the closing angle bracket ('>') + static GenericParamList *create(ASTContext &Context, + SourceLoc LAngleLoc, + ArrayRef Params, + SourceLoc RAngleLoc); + + /// create - Create a new generic parameter list and "where" clause within + /// the given AST context. + /// + /// \param Context The ASTContext in which the generic parameter list will + /// be allocated. + /// \param LAngleLoc The location of the opening angle bracket ('<') + /// \param Params The list of generic parameters, which will be copied into + /// ASTContext-allocated memory. + /// \param WhereLoc The location of the 'where' keyword, if any. + /// \param Requirements The list of requirements, which will be copied into + /// ASTContext-allocated memory. + /// \param RAngleLoc The location of the closing angle bracket ('>') + static GenericParamList *create(const ASTContext &Context, + SourceLoc LAngleLoc, + ArrayRef Params, + SourceLoc WhereLoc, + ArrayRef Requirements, + SourceLoc RAngleLoc); + + MutableArrayRef getParams() { + return {getTrailingObjects(), NumParams}; + } + + ArrayRef getParams() const { + return {getTrailingObjects(), NumParams}; + } + + using iterator = GenericTypeParamDecl **; + using const_iterator = const GenericTypeParamDecl * const *; + + unsigned size() const { return NumParams; } + iterator begin() { return getParams().begin(); } + iterator end() { return getParams().end(); } + const_iterator begin() const { return getParams().begin(); } + const_iterator end() const { return getParams().end(); } + + /// Retrieve the location of the 'where' keyword, or an invalid + /// location if 'where' was not present. + SourceLoc getWhereLoc() const { return WhereLoc; } + + /// Retrieve the set of additional requirements placed on these + /// generic parameters and types derived from them. + /// + /// This list may contain both explicitly-written requirements as well as + /// implicitly-generated requirements, and may be non-empty even if no + /// 'where' keyword is present. + MutableArrayRef getRequirements() { return Requirements; } + + /// Retrieve the set of additional requirements placed on these + /// generic parameters and types derived from them. + /// + /// This list may contain both explicitly-written requirements as well as + /// implicitly-generated requirements, and may be non-empty even if no + /// 'where' keyword is present. + ArrayRef getRequirements() const { return Requirements; } + + /// Retrieve the outer generic parameter list. + /// + /// This is used for extensions of nested types, and in SIL mode, where a + /// single lexical context can have multiple logical generic parameter + /// lists. + GenericParamList *getOuterParameters() const { return OuterParameters; } + + /// Set the outer generic parameter list. See \c getOuterParameters + /// for more information. + void setOuterParameters(GenericParamList *Outer) { OuterParameters = Outer; } + + void setDeclContext(DeclContext *dc); + + SourceLoc getLAngleLoc() const { return Brackets.Start; } + SourceLoc getRAngleLoc() const { return Brackets.End; } + + SourceRange getSourceRange() const { return Brackets; } + + /// Retrieve the source range covering the where clause. + SourceRange getWhereClauseSourceRange() const { + if (WhereLoc.isInvalid()) + return SourceRange(); + + auto endLoc = Requirements.back().getSourceRange().End; + return SourceRange(WhereLoc, endLoc); + } + + /// Configure the depth of the generic parameters in this list. + void setDepth(unsigned depth); + + /// Create a copy of the generic parameter list and all of its generic + /// parameter declarations. The copied generic parameters are re-parented + /// to the given DeclContext. + GenericParamList *clone(DeclContext *dc) const; + + void print(raw_ostream &OS) const; + SWIFT_DEBUG_DUMP; + + bool walk(ASTWalker &walker); + + /// Finds a generic parameter declaration by name. This should only + /// be used from the SIL parser. + GenericTypeParamDecl *lookUpGenericParam(Identifier name) const; +}; + +/// A trailing where clause. +class alignas(RequirementRepr) TrailingWhereClause final : + private llvm::TrailingObjects { + friend TrailingObjects; + + SourceLoc WhereLoc; + + /// The number of requirements. The actual requirements are tail-allocated. + unsigned NumRequirements; + + TrailingWhereClause(SourceLoc whereLoc, + ArrayRef requirements); + +public: + /// Create a new trailing where clause with the given set of requirements. + static TrailingWhereClause *create(ASTContext &ctx, SourceLoc whereLoc, + ArrayRef requirements); + + /// Retrieve the location of the 'where' keyword. + SourceLoc getWhereLoc() const { return WhereLoc; } + + /// Retrieve the set of requirements. + MutableArrayRef getRequirements() { + return {getTrailingObjects(), NumRequirements}; + } + + /// Retrieve the set of requirements. + ArrayRef getRequirements() const { + return {getTrailingObjects(), NumRequirements}; + } + + /// Compute the source range containing this trailing where clause. + SourceRange getSourceRange() const { + return SourceRange(WhereLoc, + getRequirements().back().getSourceRange().End); + } + + void print(llvm::raw_ostream &OS, bool printWhereKeyword) const; + +}; + +} // namespace swift + +#endif // SWIFT_GENERIC_PARAM_LIST_H \ No newline at end of file diff --git a/include/swift/AST/GenericSignature.h b/include/swift/AST/GenericSignature.h index 3a29d21fbd890..fccbe06bde122 100644 --- a/include/swift/AST/GenericSignature.h +++ b/include/swift/AST/GenericSignature.h @@ -20,6 +20,7 @@ #include "swift/AST/PrintOptions.h" #include "swift/AST/Requirement.h" #include "swift/AST/Type.h" +#include "swift/AST/TypeAlignments.h" #include "swift/Basic/AnyValue.h" #include "swift/Basic/Debug.h" #include "llvm/ADT/ArrayRef.h" diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h index e91543b476539..6b8c507569a69 100644 --- a/include/swift/AST/GenericSignatureBuilder.h +++ b/include/swift/AST/GenericSignatureBuilder.h @@ -22,6 +22,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/Identifier.h" #include "swift/AST/ProtocolConformanceRef.h" diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index 37898169a6707..a9c4d53248615 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -44,6 +44,7 @@ IDENTIFIER(Change) IDENTIFIER_WITH_NAME(code_, "_code") IDENTIFIER(CodingKeys) IDENTIFIER(combine) +IDENTIFIER_(Concurrency) IDENTIFIER(container) IDENTIFIER(CoreGraphics) IDENTIFIER(CoreMedia) @@ -67,6 +68,7 @@ IDENTIFIER(encode) IDENTIFIER(encodeIfPresent) IDENTIFIER(Encoder) IDENTIFIER(encoder) +IDENTIFIER(enqueue) IDENTIFIER(erasing) IDENTIFIER(error) IDENTIFIER(errorDomain) @@ -105,6 +107,8 @@ IDENTIFIER(oldValue) IDENTIFIER(Optional) IDENTIFIER_(OptionalNilComparisonType) IDENTIFIER(parameter) +IDENTIFIER(partialTask) +IDENTIFIER(PartialAsyncTask) IDENTIFIER(projected) IDENTIFIER(projectedValue) IDENTIFIER(Protocol) @@ -137,6 +141,7 @@ IDENTIFIER(withKeywordArguments) IDENTIFIER(wrapped) IDENTIFIER(wrappedValue) IDENTIFIER(wrapperValue) +IDENTIFIER_WITH_NAME(actorStorage, "$__actor_storage") // Kinds of layout constraints IDENTIFIER_WITH_NAME(UnknownLayout, "_UnknownLayout") diff --git a/include/swift/AST/KnownProtocols.def b/include/swift/AST/KnownProtocols.def index e530e38c8bee6..1d4a8484b726c 100644 --- a/include/swift/AST/KnownProtocols.def +++ b/include/swift/AST/KnownProtocols.def @@ -58,6 +58,7 @@ #define BUILTIN_EXPRESSIBLE_BY_LITERAL_PROTOCOL_(name) \ BUILTIN_EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME(name, "_" #name) +PROTOCOL(Actor) PROTOCOL(Sequence) PROTOCOL(IteratorProtocol) PROTOCOL(RawRepresentable) diff --git a/include/swift/AST/TypeAlignments.h b/include/swift/AST/TypeAlignments.h index f0081a80dacf4..6097cf9a29fc5 100644 --- a/include/swift/AST/TypeAlignments.h +++ b/include/swift/AST/TypeAlignments.h @@ -35,9 +35,11 @@ namespace swift { class CaptureListExpr; class Decl; class DeclContext; + class DifferentiableAttr; class Expr; class ExtensionDecl; class GenericEnvironment; + class GenericParamList; class GenericTypeParamDecl; class NominalTypeDecl; class NormalProtocolConformance; @@ -46,9 +48,12 @@ namespace swift { class Pattern; class ProtocolDecl; class ProtocolConformance; + class RequirementRepr; class SILFunction; class SILFunctionType; + class SpecializeAttr; class Stmt; + class TrailingWhereClause; class TypeVariableType; class TypeBase; class TypeDecl; @@ -63,9 +68,15 @@ namespace swift { constexpr size_t StmtAlignInBits = 3; constexpr size_t TypeAlignInBits = 3; constexpr size_t PatternAlignInBits = 3; + constexpr size_t TypeReprAlignInBits = 3; + constexpr size_t SILFunctionAlignInBits = 2; + constexpr size_t ASTContextAlignInBits = 2; constexpr size_t TypeVariableAlignInBits = 4; - constexpr size_t TypeReprAlignInBits = 3; + + // Well, this is the *minimum* pointer alignment; it's going to be 3 on + // 64-bit targets, but that doesn't matter. + constexpr size_t PointerAlignInBits = 2; } namespace llvm { @@ -110,8 +121,9 @@ LLVM_DECLARE_TYPE_ALIGNMENT(swift::SILFunctionType, LLVM_DECLARE_TYPE_ALIGNMENT(swift::Stmt, swift::StmtAlignInBits) LLVM_DECLARE_TYPE_ALIGNMENT(swift::BraceStmt, swift::StmtAlignInBits) -LLVM_DECLARE_TYPE_ALIGNMENT(swift::ASTContext, 2); +LLVM_DECLARE_TYPE_ALIGNMENT(swift::ASTContext, swift::ASTContextAlignInBits); LLVM_DECLARE_TYPE_ALIGNMENT(swift::DeclContext, swift::DeclContextAlignInBits) +LLVM_DECLARE_TYPE_ALIGNMENT(swift::DifferentiableAttr, swift::PointerAlignInBits) LLVM_DECLARE_TYPE_ALIGNMENT(swift::Expr, swift::ExprAlignInBits) LLVM_DECLARE_TYPE_ALIGNMENT(swift::CaptureListExpr, swift::ExprAlignInBits) LLVM_DECLARE_TYPE_ALIGNMENT(swift::AbstractClosureExpr, swift::ExprAlignInBits) @@ -121,10 +133,17 @@ LLVM_DECLARE_TYPE_ALIGNMENT(swift::NormalProtocolConformance, swift::DeclAlignInBits) LLVM_DECLARE_TYPE_ALIGNMENT(swift::GenericEnvironment, swift::DeclAlignInBits) +LLVM_DECLARE_TYPE_ALIGNMENT(swift::GenericParamList, + swift::PointerAlignInBits) LLVM_DECLARE_TYPE_ALIGNMENT(swift::Pattern, swift::PatternAlignInBits) +LLVM_DECLARE_TYPE_ALIGNMENT(swift::RequirementRepr, + swift::PointerAlignInBits) LLVM_DECLARE_TYPE_ALIGNMENT(swift::SILFunction, swift::SILFunctionAlignInBits) +LLVM_DECLARE_TYPE_ALIGNMENT(swift::SpecializeAttr, swift::PointerAlignInBits) +LLVM_DECLARE_TYPE_ALIGNMENT(swift::TrailingWhereClause, + swift::PointerAlignInBits) LLVM_DECLARE_TYPE_ALIGNMENT(swift::AttributeBase, swift::AttrAlignInBits) diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 5c7b15f5a9158..9546b7dfab229 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -19,6 +19,7 @@ #include "swift/AST/ActorIsolation.h" #include "swift/AST/AnyFunctionRef.h" #include "swift/AST/ASTTypeIDs.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/Type.h" #include "swift/AST/Evaluator.h" diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 57c18ef074c6b..3cae352ef73dd 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -50,6 +50,7 @@ namespace swift { class Lexer; class ParsedTypeSyntax; class PersistentParserState; + class RequirementRepr; class SILParserStateBase; class ScopeInfo; class SourceManager; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 4b8be5ff67243..f09ac7b231b5c 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -947,6 +947,9 @@ ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const { case KnownProtocolKind::Differentiable: M = getLoadedModule(Id_Differentiation); break; + case KnownProtocolKind::Actor: + M = getLoadedModule(Id_Concurrency); + break; default: M = getStdlibModule(); break; diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 91b809e881ed5..dd12a1570f09b 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -21,6 +21,7 @@ #include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/Initializer.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ProtocolConformance.h" diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 3a76406d8ea4e..0c6d22b4bca5c 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -20,6 +20,7 @@ #include "swift/AST/Attr.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index e848e6c12c52c..20eea9d67101c 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -19,6 +19,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" diff --git a/lib/AST/ASTScopePrinting.cpp b/lib/AST/ASTScopePrinting.cpp index f68e4f582628e..2dafad62d3946 100644 --- a/lib/AST/ASTScopePrinting.cpp +++ b/lib/AST/ASTScopePrinting.cpp @@ -19,6 +19,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" diff --git a/lib/AST/ASTScopeSourceRange.cpp b/lib/AST/ASTScopeSourceRange.cpp index fc86ba1c2f84b..48a59b2f3ac59 100644 --- a/lib/AST/ASTScopeSourceRange.cpp +++ b/lib/AST/ASTScopeSourceRange.cpp @@ -19,6 +19,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index bc5998914d1b3..900afa1baf7aa 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -55,6 +55,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/ASTVisitor.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/ParameterList.h" #include "swift/AST/PrettyStackTrace.h" using namespace swift; diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 62993edae03ea..6762297a9f098 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -49,6 +49,7 @@ add_swift_host_library(swiftAST STATIC FineGrainedDependencyFormat.cpp FrontendSourceFileDepGraphFactory.cpp GenericEnvironment.cpp + GenericParamList.cpp GenericSignature.cpp GenericSignatureBuilder.cpp Identifier.cpp diff --git a/lib/AST/ConformanceLookupTable.cpp b/lib/AST/ConformanceLookupTable.cpp index 45a249601a7ac..547fa1bd4b4d0 100644 --- a/lib/AST/ConformanceLookupTable.cpp +++ b/lib/AST/ConformanceLookupTable.cpp @@ -18,6 +18,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 2f1fb7ba627b1..75b354c0d29d9 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -891,115 +891,6 @@ bool Decl::isWeakImported(ModuleDecl *fromModule) const { return !fromContext.isContainedIn(containingContext); } - -SourceRange RequirementRepr::getSourceRange() const { - if (getKind() == RequirementReprKind::LayoutConstraint) - return SourceRange(FirstType->getSourceRange().Start, - SecondLayout.getSourceRange().End); - return SourceRange(FirstType->getSourceRange().Start, - SecondType->getSourceRange().End); -} - -GenericParamList::GenericParamList(SourceLoc LAngleLoc, - ArrayRef Params, - SourceLoc WhereLoc, - MutableArrayRef Requirements, - SourceLoc RAngleLoc) - : Brackets(LAngleLoc, RAngleLoc), NumParams(Params.size()), - WhereLoc(WhereLoc), Requirements(Requirements), - OuterParameters(nullptr) -{ - std::uninitialized_copy(Params.begin(), Params.end(), - getTrailingObjects()); -} - -GenericParamList * -GenericParamList::create(ASTContext &Context, - SourceLoc LAngleLoc, - ArrayRef Params, - SourceLoc RAngleLoc) { - unsigned Size = totalSizeToAlloc(Params.size()); - void *Mem = Context.Allocate(Size, alignof(GenericParamList)); - return new (Mem) GenericParamList(LAngleLoc, Params, SourceLoc(), - MutableArrayRef(), - RAngleLoc); -} - -GenericParamList * -GenericParamList::create(const ASTContext &Context, - SourceLoc LAngleLoc, - ArrayRef Params, - SourceLoc WhereLoc, - ArrayRef Requirements, - SourceLoc RAngleLoc) { - unsigned Size = totalSizeToAlloc(Params.size()); - void *Mem = Context.Allocate(Size, alignof(GenericParamList)); - return new (Mem) GenericParamList(LAngleLoc, Params, - WhereLoc, - Context.AllocateCopy(Requirements), - RAngleLoc); -} - -GenericParamList * -GenericParamList::clone(DeclContext *dc) const { - auto &ctx = dc->getASTContext(); - SmallVector params; - for (auto param : getParams()) { - auto *newParam = new (ctx) GenericTypeParamDecl( - dc, param->getName(), SourceLoc(), - GenericTypeParamDecl::InvalidDepth, - param->getIndex()); - newParam->setImplicit(true); - params.push_back(newParam); - } - - return GenericParamList::create(ctx, SourceLoc(), params, SourceLoc()); -} - -void GenericParamList::setDepth(unsigned depth) { - for (auto param : *this) - param->setDepth(depth); -} - -void GenericParamList::setDeclContext(DeclContext *dc) { - for (auto param : *this) - param->setDeclContext(dc); -} - -GenericTypeParamDecl *GenericParamList::lookUpGenericParam( - Identifier name) const { - for (const auto *innerParams = this; - innerParams != nullptr; - innerParams = innerParams->getOuterParameters()) { - for (auto *paramDecl : *innerParams) { - if (name == paramDecl->getName()) { - return const_cast(paramDecl); - } - } - } - - return nullptr; -} - -TrailingWhereClause::TrailingWhereClause( - SourceLoc whereLoc, - ArrayRef requirements) - : WhereLoc(whereLoc), - NumRequirements(requirements.size()) -{ - std::uninitialized_copy(requirements.begin(), requirements.end(), - getTrailingObjects()); -} - -TrailingWhereClause *TrailingWhereClause::create( - ASTContext &ctx, - SourceLoc whereLoc, - ArrayRef requirements) { - unsigned size = totalSizeToAlloc(requirements.size()); - void *mem = ctx.Allocate(size, alignof(TrailingWhereClause)); - return new (mem) TrailingWhereClause(whereLoc, requirements); -} - GenericContext::GenericContext(DeclContextKind Kind, DeclContext *Parent, GenericParamList *Params) : _GenericContext(), DeclContext(Kind, Parent) { @@ -5031,7 +4922,8 @@ void ProtocolDecl::computeKnownProtocolKind() const { auto module = getModuleContext(); if (module != module->getASTContext().getStdlibModule() && !module->getName().is("Foundation") && - !module->getName().is("_Differentiation")) { + !module->getName().is("_Differentiation") && + !module->getName().is("_Concurrency")) { const_cast(this)->Bits.ProtocolDecl.KnownProtocol = 1; return; } @@ -5077,6 +4969,8 @@ Optional return KnownDerivableProtocolKind::AdditiveArithmetic; case KnownProtocolKind::Differentiable: return KnownDerivableProtocolKind::Differentiable; + case KnownProtocolKind::Actor: + return KnownDerivableProtocolKind::Actor; default: return None; } } @@ -7489,6 +7383,56 @@ bool FuncDecl::isMainTypeMainMethod() const { getParameters()->size() == 0; } +bool FuncDecl::isEnqueuePartialTaskName(ASTContext &ctx, DeclName name) { + if (name.isCompoundName() && name.getBaseName() == ctx.Id_enqueue) { + auto argumentNames = name.getArgumentNames(); + return argumentNames.size() == 1 && argumentNames[0] == ctx.Id_partialTask; + } + + return false; +} + +bool FuncDecl::isActorEnqueuePartialTaskWitness() const { + if (!isEnqueuePartialTaskName(getASTContext(), getName())) + return false; + + auto classDecl = getDeclContext()->getSelfClassDecl(); + if (!classDecl) + return false; + + if (!classDecl->isActor()) + return false; + + ASTContext &ctx = getASTContext(); + auto actorProto = ctx.getProtocol(KnownProtocolKind::Actor); + if (!actorProto) + return false; + + FuncDecl *requirement = nullptr; + for (auto protoMember : actorProto->getParsedMembers()) { + if (auto protoFunc = dyn_cast(protoMember)) { + if (isEnqueuePartialTaskName(ctx, protoFunc->getName())) { + requirement = protoFunc; + break; + } + } + } + + if (!requirement) + return false; + + SmallVector conformances; + classDecl->lookupConformance( + classDecl->getModuleContext(), actorProto, conformances); + for (auto conformance : conformances) { + auto witness = conformance->getWitnessDecl(requirement); + if (witness == this) + return true; + } + + return false; +} + ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc, bool Failable, SourceLoc FailabilityLoc, bool Throws, diff --git a/lib/AST/GenericParamList.cpp b/lib/AST/GenericParamList.cpp new file mode 100644 index 0000000000000..426833e151997 --- /dev/null +++ b/lib/AST/GenericParamList.cpp @@ -0,0 +1,129 @@ +//===--- GenericParamList.cpp - Swift Language Decl ASTs ------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 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 implements the GenericParamList class and related classes. +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/GenericParamList.h" + +#include "swift/AST/ASTContext.h" +#include "swift/AST/TypeRepr.h" + +using namespace swift; +SourceRange RequirementRepr::getSourceRange() const { + if (getKind() == RequirementReprKind::LayoutConstraint) + return SourceRange(FirstType->getSourceRange().Start, + SecondLayout.getSourceRange().End); + return SourceRange(FirstType->getSourceRange().Start, + SecondType->getSourceRange().End); +} + +GenericParamList::GenericParamList(SourceLoc LAngleLoc, + ArrayRef Params, + SourceLoc WhereLoc, + MutableArrayRef Requirements, + SourceLoc RAngleLoc) + : Brackets(LAngleLoc, RAngleLoc), NumParams(Params.size()), + WhereLoc(WhereLoc), Requirements(Requirements), + OuterParameters(nullptr) +{ + std::uninitialized_copy(Params.begin(), Params.end(), + getTrailingObjects()); +} + +GenericParamList * +GenericParamList::create(ASTContext &Context, + SourceLoc LAngleLoc, + ArrayRef Params, + SourceLoc RAngleLoc) { + unsigned Size = totalSizeToAlloc(Params.size()); + void *Mem = Context.Allocate(Size, alignof(GenericParamList)); + return new (Mem) GenericParamList(LAngleLoc, Params, SourceLoc(), + MutableArrayRef(), + RAngleLoc); +} + +GenericParamList * +GenericParamList::create(const ASTContext &Context, + SourceLoc LAngleLoc, + ArrayRef Params, + SourceLoc WhereLoc, + ArrayRef Requirements, + SourceLoc RAngleLoc) { + unsigned Size = totalSizeToAlloc(Params.size()); + void *Mem = Context.Allocate(Size, alignof(GenericParamList)); + return new (Mem) GenericParamList(LAngleLoc, Params, + WhereLoc, + Context.AllocateCopy(Requirements), + RAngleLoc); +} + +GenericParamList * +GenericParamList::clone(DeclContext *dc) const { + auto &ctx = dc->getASTContext(); + SmallVector params; + for (auto param : getParams()) { + auto *newParam = new (ctx) GenericTypeParamDecl( + dc, param->getName(), SourceLoc(), + GenericTypeParamDecl::InvalidDepth, + param->getIndex()); + newParam->setImplicit(true); + params.push_back(newParam); + } + + return GenericParamList::create(ctx, SourceLoc(), params, SourceLoc()); +} + +void GenericParamList::setDepth(unsigned depth) { + for (auto param : *this) + param->setDepth(depth); +} + +void GenericParamList::setDeclContext(DeclContext *dc) { + for (auto param : *this) + param->setDeclContext(dc); +} + +GenericTypeParamDecl *GenericParamList::lookUpGenericParam( + Identifier name) const { + for (const auto *innerParams = this; + innerParams != nullptr; + innerParams = innerParams->getOuterParameters()) { + for (auto *paramDecl : *innerParams) { + if (name == paramDecl->getName()) { + return const_cast(paramDecl); + } + } + } + + return nullptr; +} + +TrailingWhereClause::TrailingWhereClause( + SourceLoc whereLoc, + ArrayRef requirements) + : WhereLoc(whereLoc), + NumRequirements(requirements.size()) +{ + std::uninitialized_copy(requirements.begin(), requirements.end(), + getTrailingObjects()); +} + +TrailingWhereClause *TrailingWhereClause::create( + ASTContext &ctx, + SourceLoc whereLoc, + ArrayRef requirements) { + unsigned size = totalSizeToAlloc(requirements.size()); + void *mem = ctx.Allocate(size, alignof(TrailingWhereClause)); + return new (mem) TrailingWhereClause(whereLoc, requirements); +} diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index bff5a8688291d..09b02ec88d227 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -24,6 +24,7 @@ #include "swift/AST/ExistentialLayout.h" #include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 7ba550c9f8cfd..bd2620d838768 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -20,6 +20,7 @@ #include "swift/AST/ClangModuleLoader.h" #include "swift/AST/DebuggerClient.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/ImportCache.h" #include "swift/AST/Initializer.h" diff --git a/lib/AST/NameLookupRequests.cpp b/lib/AST/NameLookupRequests.cpp index 7914ee8094bd3..924d93e02049f 100644 --- a/lib/AST/NameLookupRequests.cpp +++ b/lib/AST/NameLookupRequests.cpp @@ -14,6 +14,7 @@ #include "swift/AST/NameLookupRequests.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/Evaluator.h" #include "swift/AST/Module.h" diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp index 5b2ff91752ca6..62b4791e29c88 100644 --- a/lib/AST/ProtocolConformance.cpp +++ b/lib/AST/ProtocolConformance.cpp @@ -1256,6 +1256,12 @@ void NominalTypeDecl::prepareConformanceTable() const { addSynthesized(KnownProtocolKind::RawRepresentable); } } + + // Actor classes conform to the actor protocol. + if (auto classDecl = dyn_cast(mutableThis)) { + if (classDecl->isActor()) + addSynthesized(KnownProtocolKind::Actor); + } } bool NominalTypeDecl::lookupConformance( diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp index 6490258e3b922..24253def0d94f 100644 --- a/lib/AST/TypeRepr.cpp +++ b/lib/AST/TypeRepr.cpp @@ -19,6 +19,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/Expr.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/Module.h" #include "swift/AST/Types.h" #include "swift/Basic/Defer.h" diff --git a/lib/AST/USRGeneration.cpp b/lib/AST/USRGeneration.cpp index 30716b9f498c8..c3fe2322c21c9 100644 --- a/lib/AST/USRGeneration.cpp +++ b/lib/AST/USRGeneration.cpp @@ -12,6 +12,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ClangModuleLoader.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/Module.h" #include "swift/AST/USRGeneration.h" #include "swift/AST/ASTMangler.h" diff --git a/lib/ClangImporter/ClangSourceBufferImporter.cpp b/lib/ClangImporter/ClangSourceBufferImporter.cpp index fa4df253d7a0f..097fb96c50cff 100644 --- a/lib/ClangImporter/ClangSourceBufferImporter.cpp +++ b/lib/ClangImporter/ClangSourceBufferImporter.cpp @@ -67,11 +67,17 @@ SourceLoc ClangSourceBufferImporter::resolveSourceLocation( StringRef presumedFile = presumedLoc.getFilename(); SourceLoc startOfLine = loc.getAdvancedLoc(-presumedLoc.getColumn() + 1); - bool isNewVirtualFile = swiftSourceManager.openVirtualFile( - startOfLine, presumedFile, presumedLoc.getLine() - bufferLineNumber); - if (isNewVirtualFile) { - SourceLoc endOfLine = findEndOfLine(swiftSourceManager, loc, mirrorID); - swiftSourceManager.closeVirtualFile(endOfLine); + + // FIXME: Virtual files can't actually model the EOF position correctly, so + // if this virtual file would start at EOF, just hope the physical location + // will do. + if (startOfLine != swiftSourceManager.getRangeForBuffer(mirrorID).getEnd()) { + bool isNewVirtualFile = swiftSourceManager.openVirtualFile( + startOfLine, presumedFile, presumedLoc.getLine() - bufferLineNumber); + if (isNewVirtualFile) { + SourceLoc endOfLine = findEndOfLine(swiftSourceManager, loc, mirrorID); + swiftSourceManager.closeVirtualFile(endOfLine); + } } using SourceManagerRef = llvm::IntrusiveRefCntPtr; diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index 3a7fc824699b2..5287239caffc5 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -18,6 +18,7 @@ #include "swift/Demangling/Demangle.h" #include "swift/AST/Ownership.h" #include "swift/Strings.h" +#include #include #include @@ -753,6 +754,35 @@ class NodePrinter { setInvalid(); return; } + + switch (node->getKind()) { + case Node::Kind::FunctionType: + case Node::Kind::UncurriedFunctionType: + case Node::Kind::NoEscapeFunctionType: + break; + case Node::Kind::AutoClosureType: + case Node::Kind::EscapingAutoClosureType: + Printer << "@autoclosure "; break; + case Node::Kind::ThinFunctionType: + Printer << "@convention(thin) "; break; + case Node::Kind::CFunctionPointer: + Printer << "@convention(c) "; break; + case Node::Kind::ObjCBlock: + Printer << "@convention(block) "; break; + case Node::Kind::EscapingObjCBlock: + Printer << "@escaping @convention(block) "; break; + case Node::Kind::DifferentiableFunctionType: + Printer << "@differentiable "; break; + case Node::Kind::EscapingDifferentiableFunctionType: + Printer << "@escaping @differentiable "; break; + case Node::Kind::LinearFunctionType: + Printer << "@differentiable(linear) "; break; + case Node::Kind::EscapingLinearFunctionType: + Printer << "@escaping @differentiable(linear) "; break; + default: + assert(false && "Unhandled function type in printFunctionType!"); + } + unsigned startIndex = 0; bool isAsync = false, isThrows = false; if (node->getChild(startIndex)->getKind() == Node::Kind::ThrowsAnnotation) { @@ -1256,39 +1286,19 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) { case Node::Kind::UnknownIndex: Printer << "unknown index"; return nullptr; + case Node::Kind::FunctionType: + case Node::Kind::UncurriedFunctionType: case Node::Kind::NoEscapeFunctionType: - printFunctionType(nullptr, Node); - return nullptr; - case Node::Kind::EscapingAutoClosureType: - Printer << "@autoclosure "; - printFunctionType(nullptr, Node); - return nullptr; case Node::Kind::AutoClosureType: - Printer << "@autoclosure "; - printFunctionType(nullptr, Node); - return nullptr; + case Node::Kind::EscapingAutoClosureType: case Node::Kind::ThinFunctionType: - Printer << "@convention(thin) "; - printFunctionType(nullptr, Node); - return nullptr; + case Node::Kind::CFunctionPointer: + case Node::Kind::ObjCBlock: + case Node::Kind::EscapingObjCBlock: case Node::Kind::DifferentiableFunctionType: - Printer << "@differentiable "; - printFunctionType(nullptr, Node); - return nullptr; case Node::Kind::EscapingDifferentiableFunctionType: - Printer << "@escaping @differentiable "; - printFunctionType(nullptr, Node); - return nullptr; case Node::Kind::LinearFunctionType: - Printer << "@differentiable(linear) "; - printFunctionType(nullptr, Node); - return nullptr; case Node::Kind::EscapingLinearFunctionType: - Printer << "@escaping @differentiable(linear) "; - printFunctionType(nullptr, Node); - return nullptr; - case Node::Kind::FunctionType: - case Node::Kind::UncurriedFunctionType: printFunctionType(nullptr, Node); return nullptr; case Node::Kind::ArgumentTuple: @@ -1881,21 +1891,6 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) { case Node::Kind::DynamicSelf: Printer << "Self"; return nullptr; - case Node::Kind::CFunctionPointer: { - Printer << "@convention(c) "; - printFunctionType(nullptr, Node); - return nullptr; - } - case Node::Kind::ObjCBlock: { - Printer << "@convention(block) "; - printFunctionType(nullptr, Node); - return nullptr; - } - case Node::Kind::EscapingObjCBlock: { - Printer << "@escaping @convention(block) "; - printFunctionType(nullptr, Node); - return nullptr; - } case Node::Kind::SILBoxType: { Printer << "@box "; NodePointer type = Node->getChild(0); @@ -2648,14 +2643,6 @@ void NodePrinter::printEntityType(NodePointer Entity, NodePointer type, Printer << ' '; type = dependentType->getFirstChild(); } - if (type->getKind() == Node::Kind::DifferentiableFunctionType) - Printer << "@differentiable "; - else if (type->getKind() == Node::Kind::EscapingDifferentiableFunctionType) - Printer << "@escaping @differentiable "; - else if (type->getKind() == Node::Kind::LinearFunctionType) - Printer << "@differentiable(linear) "; - else if (type->getKind() == Node::Kind::EscapingLinearFunctionType) - Printer << "@escaping @differentiable(linear) "; printFunctionType(labelList, type); } else { print(type); diff --git a/lib/IDE/Formatting.cpp b/lib/IDE/Formatting.cpp index 6100a21d41669..a35bb306e10cf 100644 --- a/lib/IDE/Formatting.cpp +++ b/lib/IDE/Formatting.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "swift/AST/ASTWalker.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/TypeRepr.h" #include "swift/IDE/SourceEntityWalker.h" #include "swift/Parse/Parser.h" diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index d18859efc34f0..7dfa9a3bd3094 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -5045,6 +5045,7 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) { case KnownProtocolKind::AdditiveArithmetic: case KnownProtocolKind::Differentiable: case KnownProtocolKind::FloatingPoint: + case KnownProtocolKind::Actor: return SpecialProtocol::None; } diff --git a/lib/IRGen/GenPointerAuth.cpp b/lib/IRGen/GenPointerAuth.cpp index fa6821b267900..6f2a7d2c17fc7 100644 --- a/lib/IRGen/GenPointerAuth.cpp +++ b/lib/IRGen/GenPointerAuth.cpp @@ -400,6 +400,17 @@ PointerAuthEntity::getDeclDiscriminator(IRGenModule &IGM) const { assert(!constant.isForeign && "discriminator for foreign declaration not supported yet!"); + // Special case: methods that are witnesses to Actor.enqueue(partialTask:) + // have their own descriminator, which is shared across all actor classes. + if (constant.hasFuncDecl()) { + auto func = dyn_cast(constant.getFuncDecl()); + if (func->isActorEnqueuePartialTaskWitness()) { + cache = IGM.getSize( + Size(SpecialPointerAuthDiscriminators::ActorEnqueuePartialTask)); + return cache; + } + } + auto mangling = constant.mangle(); cache = getDiscriminatorForString(IGM, mangling); return cache; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index fa9ace4441e27..da749109d0fd9 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -23,6 +23,7 @@ #include "swift/Subsystems.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/Attr.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/DebuggerClient.h" #include "swift/AST/DiagnosticsParse.h" diff --git a/lib/Parse/ParseGeneric.cpp b/lib/Parse/ParseGeneric.cpp index f980de64d56c8..969635bdd3cb6 100644 --- a/lib/Parse/ParseGeneric.cpp +++ b/lib/Parse/ParseGeneric.cpp @@ -16,6 +16,7 @@ #include "swift/Parse/Parser.h" #include "swift/AST/DiagnosticsParse.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/TypeRepr.h" #include "swift/Parse/CodeCompletionCallbacks.h" #include "swift/Parse/SyntaxParsingContext.h" diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 016281ab3d6b0..a1ceca394ac08 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -17,6 +17,7 @@ #include "swift/Parse/Parser.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/Attr.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/TypeRepr.h" #include "swift/Parse/Lexer.h" #include "swift/Parse/CodeCompletionCallbacks.h" diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index f93042ad18bcb..2c81d1bbcb646 100644 --- a/lib/SILOptimizer/PassManager/PassPipeline.cpp +++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp @@ -283,10 +283,6 @@ void addFunctionPasses(SILPassPipelinePlan &P, // splits up copy_addr. P.addCopyForwarding(); - // We earlier eliminated ownership if we are not compiling the stdlib. Now - // handle the stdlib functions. - P.addNonTransparentFunctionOwnershipModelEliminator(); - // Optimize copies from a temporary (an "l-value") to a destination. P.addTempLValueOpt(); @@ -300,6 +296,10 @@ void addFunctionPasses(SILPassPipelinePlan &P, P.addSROA(); } + // We earlier eliminated ownership if we are not compiling the stdlib. Now + // handle the stdlib functions. + P.addNonTransparentFunctionOwnershipModelEliminator(); + // Promote stack allocations to values. P.addMem2Reg(); diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp index d47dca47efee1..144c1d30a04e7 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp @@ -453,6 +453,10 @@ bool SILCombiner::optimizeStackAllocatedEnum(AllocStackInst *AS) { return false; EnumElementDecl *element = nullptr; + unsigned numInits =0; + unsigned numTakes = 0; + SILBasicBlock *initBlock = nullptr; + SILBasicBlock *takeBlock = nullptr; SILType payloadType; // First step: check if the stack location is only used to hold one specific @@ -463,6 +467,8 @@ bool SILCombiner::optimizeStackAllocatedEnum(AllocStackInst *AS) { case SILInstructionKind::DebugValueAddrInst: case SILInstructionKind::DestroyAddrInst: case SILInstructionKind::DeallocStackInst: + case SILInstructionKind::InjectEnumAddrInst: + // We'll check init_enum_addr below. break; case SILInstructionKind::InitEnumDataAddrInst: { auto *ieda = cast(user); @@ -472,13 +478,8 @@ bool SILCombiner::optimizeStackAllocatedEnum(AllocStackInst *AS) { element = el; assert(!payloadType || payloadType == ieda->getType()); payloadType = ieda->getType(); - break; - } - case SILInstructionKind::InjectEnumAddrInst: { - auto *el = cast(user)->getElement(); - if (element && el != element) - return false; - element = el; + numInits++; + initBlock = user->getParent(); break; } case SILInstructionKind::UncheckedTakeEnumDataAddrInst: { @@ -486,6 +487,8 @@ bool SILCombiner::optimizeStackAllocatedEnum(AllocStackInst *AS) { if (element && el != element) return false; element = el; + numTakes++; + takeBlock = user->getParent(); break; } default: @@ -495,6 +498,24 @@ bool SILCombiner::optimizeStackAllocatedEnum(AllocStackInst *AS) { if (!element || !payloadType) return false; + // If the enum has a single init-take pair in a single block, we know that + // the enum cannot contain any valid payload outside that init-take pair. + // + // This also means that we can ignore any inject_enum_addr of another enum + // case, because this can only inject a case without a payload. + bool singleInitTakePair = + (numInits == 1 && numTakes == 1 && initBlock == takeBlock); + if (!singleInitTakePair) { + // No single init-take pair: We cannot ignore inject_enum_addrs with a + // mismatching case. + for (auto *use : AS->getUses()) { + if (auto *inject = dyn_cast(use->getUser())) { + if (inject->getElement() != element) + return false; + } + } + } + // Second step: replace the enum alloc_stack with a payload alloc_stack. auto *newAlloc = Builder.createAllocStack( AS->getLoc(), payloadType, AS->getVarInfo(), AS->hasDynamicLifetime()); @@ -508,6 +529,22 @@ bool SILCombiner::optimizeStackAllocatedEnum(AllocStackInst *AS) { eraseInstFromFunction(*user); break; case SILInstructionKind::DestroyAddrInst: + if (singleInitTakePair) { + // It's not possible that the enum has a payload at the destroy_addr, + // because it must have already been taken by the take of the + // single init-take pair. + // We _have_ to remove the destroy_addr, because we also remove all + // inject_enum_addrs which might inject a payload-less case before + // the destroy_addr. + eraseInstFromFunction(*user); + } else { + // The enum payload can still be valid at the destroy_addr, so we have + // to keep the destroy_addr. Just replace the enum with the payload + // (and because it's not a singleInitTakePair, we can be sure that the + // enum cannot have any other case than the payload case). + use->set(newAlloc); + } + break; case SILInstructionKind::DeallocStackInst: use->set(newAlloc); break; diff --git a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp index 44ee8e01f3998..176588416d0dd 100644 --- a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp +++ b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp @@ -916,16 +916,57 @@ static bool couldRemoveRelease(SILBasicBlock *SrcBB, SILValue SrcV, return IsReleaseOfDest; } +/// Returns true if any instruction in \p block may write memory. +static bool blockMayWriteMemory(SILBasicBlock *block) { + for (auto instAndIdx : llvm::enumerate(*block)) { + if (instAndIdx.value().mayWriteToMemory()) + return true; + // Only look at the first 20 instructions to avoid compile time problems for + // corner cases of very large blocks without memory writes. + // 20 instructions is more than enough. + if (instAndIdx.index() > 50) + return true; + } + return false; +} + +// Returns true if \p block contains an injected an enum case into \p enumAddr +// which is valid at the end of the block. +static bool hasInjectedEnumAtEndOfBlock(SILBasicBlock *block, SILValue enumAddr) { + for (auto instAndIdx : llvm::enumerate(llvm::reverse(*block))) { + SILInstruction &inst = instAndIdx.value(); + if (auto *injectInst = dyn_cast(&inst)) { + return injectInst->getOperand() == enumAddr; + } + if (inst.mayWriteToMemory()) + return false; + // Only look at the first 20 instructions to avoid compile time problems for + // corner cases of very large blocks without memory writes. + // 20 instructions is more than enough. + if (instAndIdx.index() > 50) + return false; + } + return false; +} + /// tryJumpThreading - Check to see if it looks profitable to duplicate the /// destination of an unconditional jump into the bottom of this block. bool SimplifyCFG::tryJumpThreading(BranchInst *BI) { auto *DestBB = BI->getDestBB(); auto *SrcBB = BI->getParent(); + TermInst *destTerminator = DestBB->getTerminator(); // If the destination block ends with a return, we don't want to duplicate it. // We want to maintain the canonical form of a single return where possible. - if (DestBB->getTerminator()->isFunctionExiting()) + if (destTerminator->isFunctionExiting()) return false; + // Jump threading only makes sense if there is an argument on the branch + // (which is reacted on in the DestBB), or if this goes through a memory + // location (switch_enum_addr is the only adress-instruction which we + // currently handle). + if (BI->getArgs().empty() && !isa(destTerminator)) + return false; + // We don't have a great cost model at the SIL level, so we don't want to // blissly duplicate tons of code with a goal of improved performance (we'll // leave that to LLVM). However, doing limited code duplication can lead to @@ -956,11 +997,29 @@ bool SimplifyCFG::tryJumpThreading(BranchInst *BI) { } } - if (ThreadingBudget == 0 && isa(DestBB->getTerminator())) { - for (auto V : BI->getArgs()) { - if (isa(V) || isa(V)) { + if (ThreadingBudget == 0) { + if (isa(destTerminator)) { + for (auto V : BI->getArgs()) { + if (isa(V) || isa(V)) { + ThreadingBudget = 4; + break; + } + } + } else if (auto *SEA = dyn_cast(destTerminator)) { + // If the branch-block injects a certain enum case and the destination + // switches on that enum, it's worth jump threading. E.g. + // + // inject_enum_addr %enum : $*Optional, #Optional.some + // ... // no memory writes here + // br DestBB + // DestBB: + // ... // no memory writes here + // switch_enum_addr %enum : $*Optional, case #Optional.some ... + // + SILValue enumAddr = SEA->getOperand(); + if (!blockMayWriteMemory(DestBB) && + hasInjectedEnumAtEndOfBlock(SrcBB, enumAddr)) { ThreadingBudget = 4; - break; } } } @@ -976,7 +1035,7 @@ bool SimplifyCFG::tryJumpThreading(BranchInst *BI) { // control flow. Still, we make an exception for switch_enum. bool DestIsLoopHeader = (LoopHeaders.count(DestBB) != 0); if (DestIsLoopHeader) { - if (!isa(DestBB->getTerminator())) + if (!isa(destTerminator)) return false; } @@ -1286,8 +1345,7 @@ bool SimplifyCFG::simplifyBranchBlock(BranchInst *BI) { // If this unconditional branch has BBArgs, check to see if duplicating the // destination would allow it to be simplified. This is a simple form of jump // threading. - if (!isVeryLargeFunction && !BI->getArgs().empty() && - tryJumpThreading(BI)) + if (!isVeryLargeFunction && tryJumpThreading(BI)) return true; return Simplified; diff --git a/lib/SILOptimizer/Transforms/TempLValueOpt.cpp b/lib/SILOptimizer/Transforms/TempLValueOpt.cpp index 8511de4452e75..36303388a2a02 100644 --- a/lib/SILOptimizer/Transforms/TempLValueOpt.cpp +++ b/lib/SILOptimizer/Transforms/TempLValueOpt.cpp @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "cow-opts" + #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SIL/SILFunction.h" @@ -105,8 +106,8 @@ void TempLValueOptPass::run() { } // Do the optimizations. for (CopyAddrInst *copyInst : copyInsts) { - changed |=combineCopyAndDestroy(copyInst); - changed |=tempLValueOpt(copyInst); + changed |= combineCopyAndDestroy(copyInst); + changed |= tempLValueOpt(copyInst); } } diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index d35c849fb435f..6d83a9b33d58b 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -17,6 +17,7 @@ add_swift_host_library(swiftSema STATIC ConstraintLocator.cpp ConstraintSystem.cpp DebuggerTestingTransform.cpp + DerivedConformanceActor.cpp DerivedConformanceAdditiveArithmetic.cpp DerivedConformanceCaseIterable.cpp DerivedConformanceCodable.cpp diff --git a/lib/Sema/DerivedConformanceActor.cpp b/lib/Sema/DerivedConformanceActor.cpp new file mode 100644 index 0000000000000..27b26bfecc0d9 --- /dev/null +++ b/lib/Sema/DerivedConformanceActor.cpp @@ -0,0 +1,294 @@ +//===--- DerivedConformanceActor.cpp - Derived Actor Conformance ----------===// +// +// 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 implements implicit derivation of the Actor protocol. +// +//===----------------------------------------------------------------------===// +#include "DerivedConformances.h" +#include "TypeChecker.h" +#include "TypeCheckConcurrency.h" +#include "swift/AST/NameLookupRequests.h" +#include "swift/AST/ParameterList.h" + +using namespace swift; + +bool DerivedConformance::canDeriveActor( + NominalTypeDecl *nominal, DeclContext *dc) { + auto classDecl = dyn_cast(nominal); + return classDecl && classDecl->isActor() && dc == nominal; +} + +static DeclName getEnqueuePartialTaskName(ASTContext &ctx) { + return DeclName(ctx, ctx.Id_enqueue, { ctx.Id_partialTask }); +} + +static Type getPartialAsyncTaskType(ASTContext &ctx) { + auto concurrencyModule = ctx.getLoadedModule(ctx.Id_Concurrency); + if (!concurrencyModule) + return Type(); + + SmallVector decls; + concurrencyModule->lookupQualified( + concurrencyModule, DeclNameRef(ctx.Id_PartialAsyncTask), + NL_QualifiedDefault, decls); + for (auto decl : decls) { + if (auto typeDecl = dyn_cast(decl)) + return typeDecl->getDeclaredInterfaceType(); + } + + return Type(); +} + +/// Look for the default actor queue type. +static Type getDefaultActorQueueType(DeclContext *dc, SourceLoc loc) { + ASTContext &ctx = dc->getASTContext(); + UnqualifiedLookupOptions options; + options |= UnqualifiedLookupFlags::TypeLookup; + auto desc = UnqualifiedLookupDescriptor( + DeclNameRef(ctx.getIdentifier("_DefaultActorQueue")), dc, loc, options); + auto lookup = + evaluateOrDefault(ctx.evaluator, UnqualifiedLookupRequest{desc}, {}); + for (const auto &result : lookup) { + if (auto typeDecl = dyn_cast(result.getValueDecl())) + return typeDecl->getDeclaredInterfaceType(); + } + + return Type(); +} + +/// Look for the initialization function for the default actor storage. +static FuncDecl *getDefaultActorQueueCreate(DeclContext *dc, SourceLoc loc) { + ASTContext &ctx = dc->getASTContext(); + auto desc = UnqualifiedLookupDescriptor( + DeclNameRef(ctx.getIdentifier("_defaultActorQueueCreate")), dc, loc, + UnqualifiedLookupOptions()); + auto lookup = + evaluateOrDefault(ctx.evaluator, UnqualifiedLookupRequest{desc}, {}); + for (const auto &result : lookup) { + // FIXME: Validate this further, because we're assuming the exact type. + if (auto func = dyn_cast(result.getValueDecl())) + return func; + } + + return nullptr; +} + +/// Look for the default enqueue operation. +static FuncDecl *getDefaultActorQueueEnqueue(DeclContext *dc, SourceLoc loc) { + ASTContext &ctx = dc->getASTContext(); + auto desc = UnqualifiedLookupDescriptor( + DeclNameRef(ctx.getIdentifier("_defaultActorQueueEnqueuePartialTask")), + dc, loc, UnqualifiedLookupOptions()); + auto lookup = + evaluateOrDefault(ctx.evaluator, UnqualifiedLookupRequest{desc}, {}); + for (const auto &result : lookup) { + // FIXME: Validate this further, because we're assuming the exact type. + if (auto func = dyn_cast(result.getValueDecl())) + return func; + } + + return nullptr; +} + +static std::pair +deriveBodyActor_enqueuePartialTask( + AbstractFunctionDecl *enqueuePartialTask, void *) { + // func enqueue(partialTask: PartialAsyncTask) { + // _defaultActorQueueEnqueuePartialTask( + // actor: self, queue: &self.$__actor_storage, partialTask: partialTask) + // } + ASTContext &ctx = enqueuePartialTask->getASTContext(); + + // Dig out the $__actor_storage property. + auto classDecl = enqueuePartialTask->getDeclContext()->getSelfClassDecl(); + VarDecl *storageVar = nullptr; + for (auto decl : classDecl->lookupDirect(ctx.Id_actorStorage)) { + storageVar = dyn_cast(decl); + if (storageVar) + break; + } + + // Produce an empty brace statement on failure. + auto failure = [&]() -> std::pair { + auto body = BraceStmt::create( + ctx, SourceLoc(), { }, SourceLoc(), /*implicit=*/true); + return { body, /*isTypeChecked=*/true }; + }; + + if (!storageVar) { + classDecl->diagnose( + diag::concurrency_lib_missing, ctx.Id_actorStorage.str()); + return failure(); + } + + // Call into the runtime to enqueue the task. + auto fn = getDefaultActorQueueEnqueue(classDecl, classDecl->getLoc()); + if (!fn) { + classDecl->diagnose( + diag::concurrency_lib_missing, "_defaultActorQueueEnqueuePartialTask"); + return failure(); + } + + // Reference to _defaultActorQueueEnqueuePartialTask. + auto fnRef = new (ctx) DeclRefExpr(fn, DeclNameLoc(), /*Implicit=*/true); + fnRef->setType(fn->getInterfaceType()); + + // self argument to the function. + auto selfDecl = enqueuePartialTask->getImplicitSelfDecl(); + Type selfType = enqueuePartialTask->mapTypeIntoContext( + selfDecl->getValueInterfaceType()); + Expr *selfArg = new (ctx) DeclRefExpr( + selfDecl, DeclNameLoc(), /*Implicit=*/true, AccessSemantics::Ordinary, + selfType); + selfArg = ErasureExpr::create(ctx, selfArg, ctx.getAnyObjectType(), { }); + selfArg->setImplicit(); + + // Address of the actor storage. + auto module = classDecl->getModuleContext(); + Expr *selfBase = new (ctx) DeclRefExpr( + selfDecl, DeclNameLoc(), /*Implicit=*/true, AccessSemantics::Ordinary, + selfType); + SubstitutionMap storageVarSubs = classDecl->getDeclaredTypeInContext() + ->getMemberSubstitutionMap(module, storageVar); + ConcreteDeclRef storageVarDeclRef(storageVar, storageVarSubs); + Type storageVarType = classDecl->mapTypeIntoContext( + storageVar->getValueInterfaceType()); + Type storageVarRefType = LValueType::get(storageVarType); + Expr *storageVarRefExpr = new (ctx) MemberRefExpr( + selfBase, SourceLoc(), storageVarDeclRef, DeclNameLoc(), + /*Implicit=*/true); + storageVarRefExpr->setType(storageVarRefType); + storageVarRefExpr = new (ctx) InOutExpr( + SourceLoc(), storageVarRefExpr, storageVarType, /*isImplicit=*/true); + + // The partial asynchronous task. + auto partialTaskParam = enqueuePartialTask->getParameters()->get(0); + Expr *partialTask = new (ctx) DeclRefExpr( + partialTaskParam, DeclNameLoc(), /*Implicit=*/true, + AccessSemantics::Ordinary, + enqueuePartialTask->mapTypeIntoContext( + partialTaskParam->getValueInterfaceType())); + + // Form the call itself. + auto call = CallExpr::createImplicit( + ctx, fnRef, { selfArg, storageVarRefExpr, partialTask }, + { ctx.getIdentifier("actor"), ctx.getIdentifier("queue"), + ctx.Id_partialTask }); + call->setType(fn->getResultInterfaceType()); + call->setThrows(false); + + auto body = BraceStmt::create( + ctx, SourceLoc(), { call }, SourceLoc(), /*implicit=*/true); + return { body, /*isTypeChecked=*/true }; +} + +/// Derive the declaration of Actor's enqueue(partialTask:). +static ValueDecl *deriveActor_enqueuePartialTask(DerivedConformance &derived) { + ASTContext &ctx = derived.Context; + + // Retrieve the types and declarations we'll need to form this operation. + Type partialTaskType = getPartialAsyncTaskType(ctx); + if (!partialTaskType) { + derived.Nominal->diagnose( + diag::concurrency_lib_missing, ctx.Id_PartialAsyncTask.str()); + return nullptr; + } + + auto parentDC = derived.getConformanceContext(); + Type defaultActorQueueType = getDefaultActorQueueType( + parentDC, derived.ConformanceDecl->getLoc()); + if (!defaultActorQueueType) { + derived.Nominal->diagnose( + diag::concurrency_lib_missing, "_DefaultActorQueue"); + return nullptr; + } + + auto actorStorageCreateFn = getDefaultActorQueueCreate( + parentDC, derived.ConformanceDecl->getLoc()); + if (!actorStorageCreateFn) { + derived.Nominal->diagnose( + diag::concurrency_lib_missing, "_defaultActorQueueCreate"); + return nullptr; + } + + // Partial task parameter to enqueue(partialTask:). + auto partialTaskParamDecl = new (ctx) ParamDecl( + SourceLoc(), SourceLoc(), ctx.Id_partialTask, + SourceLoc(), ctx.Id_partialTask, parentDC); + partialTaskParamDecl->setInterfaceType(partialTaskType); + partialTaskParamDecl->setSpecifier(ParamSpecifier::Default); + + // enqueue(partialTask:) method. + ParameterList *params = ParameterList::createWithoutLoc(partialTaskParamDecl); + auto func = FuncDecl::createImplicit( + ctx, StaticSpellingKind::None, getEnqueuePartialTaskName(ctx), + SourceLoc(), /*Async=*/false, /*Throws=*/false, /*GenericParams=*/nullptr, + params, TupleType::getEmpty(ctx), parentDC); + func->copyFormalAccessFrom(derived.Nominal); + func->setBodySynthesizer(deriveBodyActor_enqueuePartialTask); + func->setSynthesized(); + + // FIXME: This function should be "actor-unsafe", not "actor-independent", but + // the latter is all we have at the moment. + func->getAttrs().add(new (ctx) ActorIndependentAttr(/*IsImplicit=*/true)); + + // Actor storage property and its initialization. + auto actorStorage = new (ctx) VarDecl( + /*isStatic=*/false, VarDecl::Introducer::Var, SourceLoc(), + ctx.Id_actorStorage, parentDC); + actorStorage->setInterfaceType(defaultActorQueueType); + actorStorage->setImplicit(); + actorStorage->setAccess(AccessLevel::Private); + actorStorage->getAttrs().add(new (ctx) FinalAttr(/*Implicit=*/true)); + + // Pattern binding to initialize the actor storage. + Pattern *actorStoragePattern = NamedPattern::createImplicit( + ctx, actorStorage); + actorStoragePattern = TypedPattern::createImplicit( + ctx, actorStoragePattern, defaultActorQueueType); + + // Initialization expression. + // FIXME: We want the equivalent of type(of: self) here, but we cannot refer + // to self, so for now we use the static type instead. + Type nominalType = derived.Nominal->getDeclaredTypeInContext(); + Expr *metatypeArg = TypeExpr::createImplicit(nominalType, ctx); + Type anyObjectMetatype = ExistentialMetatypeType::get(ctx.getAnyObjectType()); + metatypeArg = ErasureExpr::create(ctx, metatypeArg, anyObjectMetatype, { }); + Expr *actorStorageCreateFnRef = new (ctx) DeclRefExpr( + actorStorageCreateFn, DeclNameLoc(), /*Implicit=*/true); + actorStorageCreateFnRef->setType(actorStorageCreateFn->getInterfaceType()); + + auto actorStorageInit = CallExpr::createImplicit( + ctx, actorStorageCreateFnRef, { metatypeArg}, { Identifier() }); + actorStorageInit->setType(actorStorageCreateFn->getResultInterfaceType()); + actorStorageInit->setThrows(false); + + auto actorStoragePatternBinding = PatternBindingDecl::createImplicit( + ctx, StaticSpellingKind::None, actorStoragePattern, actorStorageInit, + parentDC); + actorStoragePatternBinding->setInitializerChecked(0); + + derived.addMembersToConformanceContext( + { func, actorStorage, actorStoragePatternBinding }); + return func; +} + +ValueDecl *DerivedConformance::deriveActor(ValueDecl *requirement) { + auto func = dyn_cast(requirement); + if (!func) + return nullptr; + + if (FuncDecl::isEnqueuePartialTaskName(Context, func->getName())) + return deriveActor_enqueuePartialTask(*this); + + return nullptr; +} diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp index b22a351eaf6be..c4dd45728b060 100644 --- a/lib/Sema/DerivedConformances.cpp +++ b/lib/Sema/DerivedConformances.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "TypeChecker.h" +#include "TypeCheckConcurrency.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/Decl.h" #include "swift/AST/Stmt.h" @@ -74,6 +75,10 @@ bool DerivedConformance::derivesProtocolConformance(DeclContext *DC, return canDeriveHashable(Nominal); } + if (*derivableKind == KnownDerivableProtocolKind::Actor) { + return canDeriveActor(Nominal, DC); + } + if (*derivableKind == KnownDerivableProtocolKind::AdditiveArithmetic) return canDeriveAdditiveArithmetic(Nominal, DC); @@ -359,6 +364,11 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal, return getRequirement(KnownProtocolKind::Hashable); } + // Actor.enqueue(partialTask: PartialTask) + if (FuncDecl::isEnqueuePartialTaskName(ctx, name)) { + return getRequirement(KnownProtocolKind::Actor); + } + return nullptr; } diff --git a/lib/Sema/DerivedConformances.h b/lib/Sema/DerivedConformances.h index c5dba4bb20172..7deee41999f2f 100644 --- a/lib/Sema/DerivedConformances.h +++ b/lib/Sema/DerivedConformances.h @@ -18,15 +18,31 @@ #ifndef SWIFT_SEMA_DERIVEDCONFORMANCES_H #define SWIFT_SEMA_DERIVEDCONFORMANCES_H +#include "swift/Basic/LLVM.h" #include namespace swift { +class AbstractFunctionDecl; +class AccessorDecl; +class AssociatedTypeDecl; +class ASTContext; +struct ASTNode; class Decl; +class DeclContext; class DeclRefExpr; -class AccessorDecl; +class EnumDecl; +class EnumElementDecl; +class Expr; +class GuardStmt; +class Identifier; class NominalTypeDecl; +class ParamDecl; +class Pattern; class PatternBindingDecl; +class ProtocolDecl; +class StructDecl; class Type; +class TypeDecl; class ValueDecl; class VarDecl; @@ -277,6 +293,14 @@ class DerivedConformance { /// \returns the derived member, which will also be added to the type. ValueDecl *deriveDecodable(ValueDecl *requirement); + /// Whether we can derive the given Actor requirement in the given context. + static bool canDeriveActor(NominalTypeDecl *nominal, DeclContext *dc); + + /// Derive an Actor requirement for an actor class. + /// + /// \returns the derived member, which will also be added to the type. + ValueDecl *deriveActor(ValueDecl *requirement); + /// Declare a read-only property. std::pair declareDerivedProperty(Identifier name, Type propertyInterfaceType, diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index b5c19ab93c570..a7543e8265f6e 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -180,6 +180,14 @@ bool IsActorRequest::evaluate( if (superclassDecl->isActor()) return true; + // The superclass is 'NSObject', which is known to have no state and no + // superclass. + if (superclassDecl->hasClangNode() && + superclassDecl->getName().is("NSObject") && + superclassDecl->getModuleContext()->getName().is("ObjectiveC") && + actorAttr != nullptr) + return true; + // This class cannot be an actor; complain if the 'actor' modifier was // provided. if (actorAttr) { diff --git a/lib/Sema/TypeCheckConcurrency.h b/lib/Sema/TypeCheckConcurrency.h index ea0f92a7ff3a6..b2ec4f05784ec 100644 --- a/lib/Sema/TypeCheckConcurrency.h +++ b/lib/Sema/TypeCheckConcurrency.h @@ -20,6 +20,7 @@ namespace swift { class ActorIsolation; +class ASTContext; class ClassDecl; class DeclContext; class Expr; diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index cb3d9cafd1683..4bec788c5daea 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2686,6 +2686,15 @@ SemanticMembersRequest::evaluate(Evaluator &evaluator, for (auto *member : idc->getMembers()) { if (auto *afd = dyn_cast(member)) { + // If this is a witness to Actor.enqueue(partialTask:), put it at the + // beginning of the vtable. + if (auto func = dyn_cast(afd)) { + if (func->isActorEnqueuePartialTaskWitness()) { + result.insert(result.begin(), func); + continue; + } + } + // Add synthesized members to a side table and sort them by their mangled // name, since they could have been added to the class in any order. if (afd->isSynthesized()) { diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp index 1d99cc1b9cc91..2659e564d6d92 100644 --- a/lib/Sema/TypeCheckDeclObjC.cpp +++ b/lib/Sema/TypeCheckDeclObjC.cpp @@ -16,6 +16,7 @@ //===----------------------------------------------------------------------===// #include "TypeCheckObjC.h" #include "TypeChecker.h" +#include "TypeCheckConcurrency.h" #include "TypeCheckProtocol.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" @@ -368,6 +369,32 @@ static bool checkObjCInForeignClassContext(const ValueDecl *VD, return true; } +/// Actor-isolated declarations cannot be @objc. +static bool checkObjCActorIsolation(const ValueDecl *VD, + ObjCReason Reason) { + // Check actor isolation. + bool Diagnose = shouldDiagnoseObjCReason(Reason, VD->getASTContext()); + + switch (getActorIsolation(const_cast(VD))) { + case ActorIsolation::ActorInstance: + // Actor-isolated functions cannot be @objc. + if (Diagnose) { + VD->diagnose( + diag::actor_isolated_objc, VD->getDescriptiveKind(), VD->getName()); + describeObjCReason(VD, Reason); + if (auto FD = dyn_cast(VD)) { + addAsyncNotes(const_cast(FD)); + } + } + return true; + + case ActorIsolation::ActorPrivileged: + case ActorIsolation::Independent: + case ActorIsolation::Unspecified: + return false; + } +} + static VersionRange getMinOSVersionForClassStubs(const llvm::Triple &target) { if (target.isMacOSX()) return VersionRange::allGTE(llvm::VersionTuple(10, 15, 0)); @@ -512,6 +539,8 @@ bool swift::isRepresentableInObjC( return false; if (checkObjCInExtensionContext(AFD, Diagnose)) return false; + if (checkObjCActorIsolation(AFD, Reason)) + return false; if (AFD->isOperator()) { AFD->diagnose((isa(AFD->getDeclContext()) @@ -686,10 +715,12 @@ bool swift::isRepresentableInObjC( Type resultType = FD->mapTypeIntoContext(FD->getResultInterfaceType()); if (auto tupleType = resultType->getAs()) { for (const auto &tupleElt : tupleType->getElements()) { - addCompletionHandlerParam(tupleElt.getType()); + if (addCompletionHandlerParam(tupleElt.getType())) + return false; } } else { - addCompletionHandlerParam(resultType); + if (addCompletionHandlerParam(resultType)) + return false; } // For a throwing asynchronous function, an Error? parameter is added @@ -939,6 +970,8 @@ bool swift::isRepresentableInObjC(const VarDecl *VD, ObjCReason Reason) { if (checkObjCInForeignClassContext(VD, Reason)) return false; + if (checkObjCActorIsolation(VD, Reason)) + return false; if (!Diagnose || Result) return Result; @@ -967,6 +1000,8 @@ bool swift::isRepresentableInObjC(const SubscriptDecl *SD, ObjCReason Reason) { return false; if (checkObjCWithGenericParams(SD, Reason)) return false; + if (checkObjCActorIsolation(SD, Reason)) + return false; // ObjC doesn't support class subscripts. if (!SD->isInstanceMember()) { diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 08df65e1a80f6..dc0c1c182f14a 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -4216,8 +4216,20 @@ void ConformanceChecker::resolveValueWitnesses() { auto witness = Conformance->getWitnessUncached(requirement).getDecl(); if (!witness) return; - // Objective-C checking for @objc requirements. auto &C = witness->getASTContext(); + + // Ensure that Actor.enqueue(partialTask:) is implemented within the + // actor class itself. + if (FuncDecl::isEnqueuePartialTaskName(C, requirement->getName()) && + Proto->isSpecificProtocol(KnownProtocolKind::Actor) && + DC != witness->getDeclContext() && + Adoptee->getClassOrBoundGenericClass() && + Adoptee->getClassOrBoundGenericClass()->isActor()) { + witness->diagnose(diag::enqueue_partial_task_not_in_context, Adoptee); + return; + } + + // Objective-C checking for @objc requirements. if (requirement->isObjC() && requirement->getName() == witness->getName() && !requirement->getAttrs().isUnavailable(getASTContext())) { @@ -5804,6 +5816,9 @@ ValueDecl *TypeChecker::deriveProtocolRequirement(DeclContext *DC, case KnownDerivableProtocolKind::Differentiable: return derived.deriveDifferentiable(Requirement); + case KnownDerivableProtocolKind::Actor: + return derived.deriveActor(Requirement); + case KnownDerivableProtocolKind::OptionSet: llvm_unreachable( "When possible, OptionSet is derived via memberwise init synthesis"); diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index 69525ed1881e7..1f550ab32c01d 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -30,6 +30,7 @@ #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" #include "swift/AST/PropertyWrappers.h" +#include "swift/AST/ProtocolConformance.h" #include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/Types.h" @@ -113,6 +114,21 @@ static void computeLoweredStoredProperties(NominalTypeDecl *decl) { if (var->hasAttachedPropertyWrapper()) (void) var->getPropertyWrapperBackingProperty(); } + + // If this is an actor class, check conformance to the Actor protocol to + // ensure that the actor storage will get created (if needed). + if (auto classDecl = dyn_cast(decl)) { + if (classDecl->isActor()) { + ASTContext &ctx = decl->getASTContext(); + if (auto actorProto = ctx.getProtocol(KnownProtocolKind::Actor)) { + SmallVector conformances; + classDecl->lookupConformance( + decl->getModuleContext(), actorProto, conformances); + for (auto conformance : conformances) + TypeChecker::checkConformance(conformance->getRootNormalConformance()); + } + } + } } ArrayRef @@ -128,10 +144,16 @@ StoredPropertiesRequest::evaluate(Evaluator &evaluator, if (isa(decl->getModuleScopeContext())) computeLoweredStoredProperties(decl); + ASTContext &ctx = decl->getASTContext(); for (auto *member : decl->getMembers()) { if (auto *var = dyn_cast(member)) - if (!var->isStatic() && var->hasStorage()) - results.push_back(var); + if (!var->isStatic() && var->hasStorage()) { + // Actor storage always goes at the beginning. + if (var->getName() == ctx.Id_actorStorage) + results.insert(results.begin(), var); + else + results.push_back(var); + } } return decl->getASTContext().AllocateCopy(results); diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index dbd5f63e86b05..fa8f01f211e7c 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -22,6 +22,7 @@ #include "swift/AST/AnyFunctionRef.h" #include "swift/AST/Availability.h" #include "swift/AST/DiagnosticsSema.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/KnownProtocols.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/NameLookup.h" diff --git a/stdlib/CMakeLists.txt b/stdlib/CMakeLists.txt index 6a39ac804c01a..5f8202b406ab2 100644 --- a/stdlib/CMakeLists.txt +++ b/stdlib/CMakeLists.txt @@ -66,6 +66,10 @@ option(SWIFT_ENABLE_MODULE_INTERFACES "Generate .swiftinterface files alongside .swiftmodule files" "${SWIFT_STDLIB_STABLE_ABI}") +option(SWIFT_COMPILE_DIFFERENTIATION_WITHOUT_TGMATH + "Build Differentation without tgmath (and dependency on platform runtime libraries)" + FALSE) + # # End of user-configurable options. # diff --git a/stdlib/public/CMakeLists.txt b/stdlib/public/CMakeLists.txt index 9141a0db2d466..978322b95a1b0 100644 --- a/stdlib/public/CMakeLists.txt +++ b/stdlib/public/CMakeLists.txt @@ -87,7 +87,15 @@ if(SWIFT_BUILD_STDLIB) add_subdirectory(SwiftOnoneSupport) if(SWIFT_ENABLE_EXPERIMENTAL_DIFFERENTIABLE_PROGRAMMING) - add_subdirectory(Differentiation) + if(SWIFT_COMPILE_DIFFERENTIATION_WITHOUT_TGMATH) + # Use a different CMakeLists.txt for this configuration + # while sharing the bulk of the code + # This way we will reduce any side effect on the main configuration + # and increase the readability of the CMake code + add_subdirectory(Differentiation_NoTgMath) + else() + add_subdirectory(Differentiation) + endif() endif() if(SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY) diff --git a/stdlib/public/Concurrency/Actor.swift b/stdlib/public/Concurrency/Actor.swift new file mode 100644 index 0000000000000..212651ecfb6b3 --- /dev/null +++ b/stdlib/public/Concurrency/Actor.swift @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 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 +// +//===----------------------------------------------------------------------===// + +import Swift +@_implementationOnly import _SwiftConcurrencyShims + +/// Common protocol to which all actor classes conform. +/// +/// The \c Actor protocol provides the core functionality of an actor class, +/// which involves enqueuing new partial tasks to be executed at some +/// point. Actor classes implicitly conform to this protocol as part of their +/// primary class definition. +public protocol Actor: AnyObject { + /// Enqueue a new partial task that will be executed in the actor's context. + func enqueue(partialTask: PartialAsyncTask) +} + +/// A native actor queue, which schedules partial tasks onto a serial queue. +public struct _NativeActorQueue { + // TODO: This is just a stub for now +} + +/// The default type to be used for an actor's queue when an actor does not +/// provide its own implementation of `enqueue(partialTask:)`. +public typealias _DefaultActorQueue = _NativeActorQueue + +/// Called to create a new default actor queue instance for a class of the given +/// type. The implementation will call this within the actor's initializer to +/// initialize the actor queue. +public func _defaultActorQueueCreate( + _ actorClass: AnyObject.Type +) -> _DefaultActorQueue { + _DefaultActorQueue() +} + +/// Called by the synthesized implementation of enqueue(partialTask:). +/// +/// The implementation is provided with the address of the synthesized instance +/// property for the actor queue, so that it need not be at a fixed offset. +public func _defaultActorQueueEnqueuePartialTask( + actor: AnyObject, + queue: inout _DefaultActorQueue, + partialTask: PartialAsyncTask +) { + // TODO: Implement queueing. +} diff --git a/stdlib/public/Concurrency/CMakeLists.txt b/stdlib/public/Concurrency/CMakeLists.txt index fa491ec431295..e63b3e475255b 100644 --- a/stdlib/public/Concurrency/CMakeLists.txt +++ b/stdlib/public/Concurrency/CMakeLists.txt @@ -11,6 +11,7 @@ #===----------------------------------------------------------------------===# add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB + Actor.swift PartialAsyncTask.swift SWIFT_MODULE_DEPENDS_OSX Darwin diff --git a/stdlib/public/Differentiation_NoTgMath/CMakeLists.txt b/stdlib/public/Differentiation_NoTgMath/CMakeLists.txt new file mode 100644 index 0000000000000..b27e8a207be96 --- /dev/null +++ b/stdlib/public/Differentiation_NoTgMath/CMakeLists.txt @@ -0,0 +1,20 @@ +set(SOURCES_FOLDER ../Differentiation) + +add_swift_target_library(swift_Differentiation ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB + ${SOURCES_FOLDER}/Differentiable.swift + ${SOURCES_FOLDER}/DifferentialOperators.swift + ${SOURCES_FOLDER}/DifferentiationUtilities.swift + ${SOURCES_FOLDER}/AnyDifferentiable.swift + ${SOURCES_FOLDER}/ArrayDifferentiation.swift + ${SOURCES_FOLDER}/OptionalDifferentiation.swift + + GYB_SOURCES + ${SOURCES_FOLDER}/FloatingPointDifferentiation.swift.gyb + ${SOURCES_FOLDER}/SIMDDifferentiation.swift.gyb + + SWIFT_COMPILE_FLAGS + ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} + -parse-stdlib + LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}" + DARWIN_INSTALL_NAME_DIR "@rpath" + INSTALL_IN_COMPONENT stdlib) diff --git a/test/ClangImporter/diags_from_module.swift b/test/ClangImporter/diags_from_module.swift index 8e74e7a8ca062..5cc81a87e1291 100644 --- a/test/ClangImporter/diags_from_module.swift +++ b/test/ClangImporter/diags_from_module.swift @@ -37,7 +37,7 @@ import Module // CHECK-PRIMARY: diags_from_module.swift:[[@LINE-4]]:8: error: could not build Objective-C module 'Module' // CHECK-WARN: Sub2.h:7:2: warning: here is some warning about something -// CHECK-WARN: :1:1: warning: umbrella header for module 'Module' does not include header 'NotInModule.h' +// CHECK-WARN: Module.h:20:1: warning: umbrella header for module 'Module' does not include header 'NotInModule.h' // FIXME: show [-Wincomplete-umbrella] // CHECK-NO-WARN-NOT: warning about something diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt index 7f410eec10faa..294e7a08a34c2 100644 --- a/test/Demangle/Inputs/manglings.txt +++ b/test/Demangle/Inputs/manglings.txt @@ -357,6 +357,8 @@ $s3red4testyAA3ResOyxSayq_GAEs5ErrorAAq_sAFHD1__HCg_GADyxq_GsAFR_r0_lF ---> red. $s3red4testyAA7OurTypeOy4them05TheirD0Vy5AssocQzGAjE0F8ProtocolAAxAA0c7DerivedH0HD1_AA0c4BaseH0HI1_AieKHA2__HCg_GxmAaLRzlF ---> red.test(A.Type) -> red.OurType> $s17property_wrappers10WithTuplesV9fractionsSd_S2dtvpfP ---> property wrapper backing initializer of property_wrappers.WithTuples.fractions : (Swift.Double, Swift.Double, Swift.Double) $sSo17OS_dispatch_queueC4sync7executeyyyXE_tFTOTA ---> {T:$sSo17OS_dispatch_queueC4sync7executeyyyXE_tFTO} partial apply forwarder for @nonobjc __C.OS_dispatch_queue.sync(execute: () -> ()) -> () +$s4main1gyySiXCvp ---> main.g : @convention(c) (Swift.Int) -> () +$s4main1gyySiXBvp ---> main.g : @convention(block) (Swift.Int) -> () $sxq_Idgnr_D ---> @differentiable @callee_guaranteed (@in_guaranteed A) -> (@out B) $sxq_Ilgnr_D ---> @differentiable(linear) @callee_guaranteed (@in_guaranteed A) -> (@out B) $sS3fIedgyywd_D ---> @escaping @differentiable @callee_guaranteed (@unowned Swift.Float, @unowned @noDerivative Swift.Float) -> (@unowned Swift.Float) diff --git a/test/IDE/complete_decl_attribute.swift b/test/IDE/complete_decl_attribute.swift index 752ba9e08b5f1..23606dacfa21e 100644 --- a/test/IDE/complete_decl_attribute.swift +++ b/test/IDE/complete_decl_attribute.swift @@ -3,7 +3,6 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYWORD2 | %FileCheck %s -check-prefix=KEYWORD2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYWORD3 | %FileCheck %s -check-prefix=KEYWORD3 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYWORD3_2 | %FileCheck %s -check-prefix=KEYWORD3 -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYWORD3 -enable-experimental-concurrency | %FileCheck %s -check-prefix=KEYWORD3_ASYNC // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYWORD4 | %FileCheck %s -check-prefix=KEYWORD4 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYWORD5 | %FileCheck %s -check-prefix=KEYWORD5 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ON_GLOBALVAR | %FileCheck %s -check-prefix=ON_GLOBALVAR @@ -92,8 +91,6 @@ struct MyStruct {} // KEYWORD3-NEXT: Keyword/None: propertyWrapper[#Class Attribute#]; name=propertyWrapper // KEYWORD3-NEXT: End completions -// KEYWORD3_ASYNC: Keyword/None: actor[#Class Attribute#]; name=actor - @#^KEYWORD3_2^#IB class C2 {} // Same as KEYWORD3. diff --git a/test/IRGen/ptrauth-actor.swift b/test/IRGen/ptrauth-actor.swift new file mode 100644 index 0000000000000..4cd1f44ccb567 --- /dev/null +++ b/test/IRGen/ptrauth-actor.swift @@ -0,0 +1,24 @@ +// RUN: %swift -swift-version 5 -target arm64e-apple-macos11.0 -parse-stdlib %s -emit-ir -disable-llvm-optzns -enable-experimental-concurrency -o - | %FileCheck %s + +// REQUIRES: CODEGENERATOR=ARM +// REQUIRES: concurrency +// REQUIRES: CPU=arm64e +// REQUIRES: OS=macosx + +import _Concurrency +import Swift + +public actor class A1 { + var x: Int = 17 +} + +open actor class A3: Actor { + open func f() { } +} + +// enqueue(partialTask:) has the same discriminator across all classes. +// CHECK: s4main2A1C7enqueue11partialTasky12_Concurrency012PartialAsyncE0V_tF.ptrauth{{.*}}i64 36669 + +// CHECK: @"$s4main2A3CyxG12_Concurrency5ActorAaeFP7enqueue11partialTaskyAE012PartialAsyncG0V_tFTW" +// CHECK-NOT: ret void +// CHECK: call i64 @llvm.ptrauth.blend.i64(i64 %{{[0-9]+}}, i64 36669) diff --git a/test/SILGen/synthesized_conformance_actor.swift b/test/SILGen/synthesized_conformance_actor.swift new file mode 100644 index 0000000000000..365b3fee56e92 --- /dev/null +++ b/test/SILGen/synthesized_conformance_actor.swift @@ -0,0 +1,53 @@ +// RUN: %target-swift-frontend -emit-silgen %s -swift-version 5 -enable-experimental-concurrency | %FileCheck -check-prefix CHECK %s +// REQUIRES: concurrency + +import _Concurrency + +public protocol DefaultInit { + init() +} + +public actor class A1 { + var x: Int = 17 + var y: T = T() + + public func f() { } +} + +extension Int: DefaultInit { } + +public actor class A2 { + func f() { } + @actorIndependent public func enqueue(partialTask: PartialAsyncTask) { } +} + +func buildIt() { + _ = A1() +} + +// A1.enqueue(partialTask:) +// CHECK-LABEL: sil [ossa] @$s29synthesized_conformance_actor2A1C7enqueue11partialTasky12_Concurrency012PartialAsyncG0V_tF : $@convention(method) (@in_guaranteed PartialAsyncTask, @guaranteed A1) -> () { +// CHECK: bb0([[PARTIAL_TASK:%.*]] : $*PartialAsyncTask, [[SELF:%.*]] : @guaranteed $A1): +// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]] : $A1 +// CHECK-NEXT: [[SELF_ANY_OBJECT:%.*]] = init_existential_ref [[SELF_COPY]] : $A1 : $A1, $AnyObject +// CHECK-NEXT: [[PROPERTY_REF:%.*]] = ref_element_addr [[SELF]] : $A1, #A1.$__actor_storage +// FIXME: Need to eliminate this exclusivity check. +// CHECK-NEXT: [[DYNAMIC_ACCESS:%.*]] = begin_access [modify] [dynamic] [[PROPERTY_REF]] : $*_NativeActorQueue +// CHECK: [[ENQUEUE_FN:%.*]] = function_ref @$s12_Concurrency36_defaultActorQueueEnqueuePartialTask5actor5queue07partialG0yyXl_AA07_NativecD0VzAA0f5AsyncG0VtF : $@convention(thin) (@guaranteed AnyObject, @inout _NativeActorQueue, @in_guaranteed PartialAsyncTask) -> () +// CHECK-NEXT: apply [[ENQUEUE_FN]]([[SELF_ANY_OBJECT]], [[DYNAMIC_ACCESS]], [[PARTIAL_TASK]]) : $@convention(thin) (@guaranteed AnyObject, @inout _NativeActorQueue, @in_guaranteed PartialAsyncTask) -> () +// CHECK-NEXT: end_access [[DYNAMIC_ACCESS]] : $*_NativeActorQueue + +// variable initialization expression of A1.$__actor_storage +// CHECK-LABEL: sil [transparent] [ossa] @$s29synthesized_conformance_actor2A1C03$__C8_storage33{{.*}}12_Concurrency17_NativeActorQueueVvpfi : $@convention(thin) () -> @out _NativeActorQueue { +// CHECK: bb0([[PROPERTY:%.*]] : $*_NativeActorQueue): +// CHECK-NEXT: [[META:%.*]] = metatype $@thick A1.Type +// CHECK-NEXT: [[ERASED_META:%.*]] = init_existential_metatype [[META]] : $@thick A1.Type, $@thick AnyObject.Type +// CHECK: [[INIT_FN:%.*]] = function_ref @$s12_Concurrency24_defaultActorQueueCreateyAA07_NativecD0VyXlXpF : $@convention(thin) (@thick AnyObject.Type) -> @out _NativeActorQueue +// CHECK-NEXT: = apply [[INIT_FN]]([[PROPERTY]], [[ERASED_META]]) : $@convention(thin) (@thick AnyObject.Type) -> @out _NativeActorQueue + +// Ensure that enqueue(partialTask:) is the first slot in the vtable. +// CHECK-LABEL: sil_vtable [serialized] A1 { +// CHECK-NEXT: #A1.enqueue: (A1) -> (PartialAsyncTask) -> () : @$s29synthesized_conformance_actor2A1C7enqueue11partialTasky12_Concurrency012PartialAsyncG0V_tF + +// CHECK-LABEL: sil_vtable [serialized] A2 { +// CHECK-NEXT: #A2.enqueue: (A2) -> (PartialAsyncTask) -> () : @$s29synthesized_conformance_actor2A2C7enqueue11partialTasky12_Concurrency012PartialAsyncG0V_tF // A2.enqueue(partialTask:) diff --git a/test/SILOptimizer/cast_optimizer_conditional_conformance.sil b/test/SILOptimizer/cast_optimizer_conditional_conformance.sil index 87688a532e593..355dc0d053251 100644 --- a/test/SILOptimizer/cast_optimizer_conditional_conformance.sil +++ b/test/SILOptimizer/cast_optimizer_conditional_conformance.sil @@ -98,8 +98,6 @@ bb6: // CHECK: [[IEDA:%.*]] = init_enum_data_addr [[OPT]] : $*Optional, #Optional.some!enumelt // CHECK: checked_cast_addr_br take_always S1 in [[VAL]] : $*S1 to HasFoo in [[IEDA]] : $*HasFoo, bb1, bb2 // bbs... -// CHECK: switch_enum_addr [[OPT]] : $*Optional, case #Optional.some!enumelt: bb4, case #Optional.none!enumelt: bb5 -// bbs... // CHECK: [[UNWRAP:%.*]] = unchecked_take_enum_data_addr [[OPT]] : $*Optional, #Optional.some!enumelt // CHECK: copy_addr [take] [[UNWRAP]] to [initialization] [[EXIS]] : $*HasFoo // CHECK: [[OPEN:%.*]] = open_existential_addr immutable_access [[EXIS]] : $*HasFoo to $*@opened("4E16CBC0-FD9F-11E8-A311-D0817AD9F6DD") HasFoo diff --git a/test/SILOptimizer/enum_jump_thread.sil b/test/SILOptimizer/enum_jump_thread.sil index 22d76c7a9142f..3ce09bbe2112a 100644 --- a/test/SILOptimizer/enum_jump_thread.sil +++ b/test/SILOptimizer/enum_jump_thread.sil @@ -49,3 +49,83 @@ bb5(%7 : $E2): return %7 : $E2 } +// CHECK-LABEL: sil @test_enum_addr +sil @test_enum_addr : $@convention(thin) () -> Builtin.Int32 { +bb0: + %2 = alloc_stack $E + cond_br undef, bb1, bb2 + +// CHECK: bb1: +// CHECK-NEXT: inject_enum_addr +// CHECK-NEXT: switch_enum_addr +bb1: + inject_enum_addr %2 : $*E, #E.A!enumelt + br bb3 + +// CHECK: bb2: +// CHECK-NEXT: inject_enum_addr +// CHECK-NEXT: switch_enum_addr +bb2: + inject_enum_addr %2 : $*E, #E.B!enumelt + br bb3 + +bb3: + switch_enum_addr %2 : $*E, case #E.A!enumelt: bb4, case #E.B!enumelt: bb5 + +bb4: + %10 = integer_literal $Builtin.Int32, 1 + br bb6(%10 : $Builtin.Int32) + +bb5: + %11 = integer_literal $Builtin.Int32, 2 + br bb6(%11 : $Builtin.Int32) + +bb6(%12 : $Builtin.Int32): + dealloc_stack %2 : $*E + return %12 : $Builtin.Int32 +// CHECK: } // end sil function 'test_enum_addr' +} + +// CHECK-LABEL: sil @dont_jumpthread_enum_addr +sil @dont_jumpthread_enum_addr : $@convention(thin) (E) -> Builtin.Int32 { +bb0(%0 : $E): + %2 = alloc_stack $E + %3 = alloc_stack $E + cond_br undef, bb1, bb2 + +// CHECK: bb1: +// CHECK-NEXT: inject_enum_addr +// CHECK-NEXT: store +// CHECK-NEXT: br bb3 +bb1: + inject_enum_addr %2 : $*E, #E.A!enumelt + store %0 to %2 : $*E + br bb3 + +// CHECK: bb2: +// CHECK-NEXT: inject_enum_addr +// CHECK-NEXT: br bb3 +bb2: + inject_enum_addr %3 : $*E, #E.A!enumelt + br bb3 + +// CHECK: bb3: +// CHECK-NEXT: switch_enum_addr +bb3: + switch_enum_addr %2 : $*E, case #E.A!enumelt: bb4, case #E.B!enumelt: bb5 + +bb4: + %10 = integer_literal $Builtin.Int32, 1 + br bb6(%10 : $Builtin.Int32) + +bb5: + %11 = integer_literal $Builtin.Int32, 2 + br bb6(%11 : $Builtin.Int32) + +bb6(%12 : $Builtin.Int32): + dealloc_stack %3 : $*E + dealloc_stack %2 : $*E + return %12 : $Builtin.Int32 +// CHECK: } // end sil function 'dont_jumpthread_enum_addr' +} + diff --git a/test/SILOptimizer/generic_loop.swift b/test/SILOptimizer/generic_loop.swift new file mode 100644 index 0000000000000..55facdb5ab61f --- /dev/null +++ b/test/SILOptimizer/generic_loop.swift @@ -0,0 +1,17 @@ +// RUN: %target-swift-frontend -primary-file %s -O -sil-verify-all -module-name=test -emit-sil | %FileCheck %s + +// REQUIRES: swift_stdlib_no_asserts,optimized_stdlib + + +// Check that we can eliminate all optionals from a loop which is iterating +// over an array of address-only elements. + +// CHECK-LABEL: sil @$s4test0A18_no_optionals_usedyySayxGlF : $@convention(thin) (@guaranteed Array) -> () { +// CHECK-NOT: Optional +// CHECK: } // end sil function '$s4test0A18_no_optionals_usedyySayxGlF' +public func test_no_optionals_used(_ items: [T]) { + for i in items { + print(i) + } +} + diff --git a/test/SILOptimizer/sil_combine_concrete_existential.swift b/test/SILOptimizer/sil_combine_concrete_existential.swift index 3fe0399faa9d7..5a840d7ffbc67 100644 --- a/test/SILOptimizer/sil_combine_concrete_existential.swift +++ b/test/SILOptimizer/sil_combine_concrete_existential.swift @@ -95,10 +95,11 @@ struct SS: PPP { // The first apply has been devirtualized and inlined. The second remains unspecialized. // CHECK-LABEL: sil @$s32sil_combine_concrete_existential37testWitnessReturnOptionalIndirectSelfyyF : $@convention(thin) () -> () { +// CHECK: [[O1:%.*]] = open_existential_addr immutable_access %{{.*}} : $*PPP to $*@opened("{{.*}}") PPP // CHECK: switch_enum_addr %{{.*}} : $*Optional<@opened("{{.*}}") PPP>, case #Optional.some!enumelt: bb{{.*}}, case #Optional.none!enumelt: bb{{.*}} -// CHECK: [[O:%.*]] = open_existential_addr immutable_access %{{.*}} : $*PPP to $*@opened("{{.*}}") PPP -// CHECK: [[W:%.*]] = witness_method $@opened("{{.*}}") PPP, #PPP.returnsOptionalIndirect : (Self) -> () -> Self?, [[O]] : $*@opened("{{.*}}") PPP : $@convention(witness_method: PPP) <τ_0_0 where τ_0_0 : PPP> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0> -// CHECK: apply [[W]]<@opened("{{.*}}") PPP>(%{{.*}}, [[O]]) : $@convention(witness_method: PPP) <τ_0_0 where τ_0_0 : PPP> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0> +// CHECK: [[O2:%.*]] = open_existential_addr immutable_access %{{.*}} : $*PPP to $*@opened("{{.*}}") PPP +// CHECK: [[W:%.*]] = witness_method $@opened("{{.*}}") PPP, #PPP.returnsOptionalIndirect : (Self) -> () -> Self?, [[O1]] : $*@opened("{{.*}}") PPP : $@convention(witness_method: PPP) <τ_0_0 where τ_0_0 : PPP> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0> +// CHECK: apply [[W]]<@opened("{{.*}}") PPP>(%{{.*}}, [[O2]]) : $@convention(witness_method: PPP) <τ_0_0 where τ_0_0 : PPP> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0> // CHECK-LABEL: } // end sil function '$s32sil_combine_concrete_existential37testWitnessReturnOptionalIndirectSelfyyF' public func testWitnessReturnOptionalIndirectSelf() { let p: PPP = S() diff --git a/test/SILOptimizer/sil_combine_enums.sil b/test/SILOptimizer/sil_combine_enums.sil index 03378b8025f95..89a82f48777d8 100644 --- a/test/SILOptimizer/sil_combine_enums.sil +++ b/test/SILOptimizer/sil_combine_enums.sil @@ -504,6 +504,7 @@ enum MP { } sil @take_s : $@convention(thin) (@in S) -> () +sil @take_t : $@convention(thin) (@in T) -> () sil @use_mp : $@convention(thin) (@in_guaranteed MP) -> () // CHECK-LABEL: sil @expand_alloc_stack_of_enum1 @@ -568,6 +569,37 @@ bb3: return %11 : $() } +// CHECK-LABEL: sil @expand_alloc_stack_of_enum_multiple_cases +// CHECK: [[A:%[0-9]+]] = alloc_stack $T +// CHECK: bb1: +// CHECK-NEXT: store %0 to [[A]] +// CHECK: apply {{%[0-9]+}}([[A]]) +// CHECK: bb2: +// CHECK-NEXT: br bb3 +// CHECK: bb3: +// CHECK: } // end sil function 'expand_alloc_stack_of_enum_multiple_cases' +sil @expand_alloc_stack_of_enum_multiple_cases : $@convention(method) (T) -> () { +bb0(%0 : $T): + %1 = alloc_stack $X + cond_br undef, bb1, bb2 +bb1: + %2 = init_enum_data_addr %1 : $*X, #X.some!enumelt + store %0 to %2 : $*T + inject_enum_addr %1 : $*X, #X.some!enumelt + %7 = unchecked_take_enum_data_addr %1 : $*X, #X.some!enumelt + %8 = function_ref @take_t : $@convention(thin) (@in T) -> () + %9 = apply %8(%7) : $@convention(thin) (@in T) -> () + br bb3 +bb2: + inject_enum_addr %1 : $*X, #X.none!enumelt + destroy_addr %1 : $*X + br bb3 +bb3: + dealloc_stack %1 : $*X + %11 = tuple () + return %11 : $() +} + // CHECK-LABEL: sil @dont_expand_alloc_stack_of_enum_multiple_cases // CHECK: alloc_stack $MP // CHECK: } // end sil function 'dont_expand_alloc_stack_of_enum_multiple_cases' @@ -592,6 +624,28 @@ bb3: return %11 : $() } +// CHECK-LABEL: sil @dont_expand_alloc_stack_of_enum_multiple_cases2 +// CHECK: alloc_stack $X +// CHECK: } // end sil function 'dont_expand_alloc_stack_of_enum_multiple_cases2' +sil @dont_expand_alloc_stack_of_enum_multiple_cases2 : $@convention(method) (T) -> () { +bb0(%0 : $T): + %1 = alloc_stack $X + cond_br undef, bb1, bb2 +bb1: + %2 = init_enum_data_addr %1 : $*X, #X.some!enumelt + store %0 to %2 : $*T + inject_enum_addr %1 : $*X, #X.some!enumelt + br bb3 +bb2: + inject_enum_addr %1 : $*X, #X.none!enumelt + br bb3 +bb3: + destroy_addr %1 : $*X + dealloc_stack %1 : $*X + %11 = tuple () + return %11 : $() +} + // CHECK-LABEL: sil @dont_expand_alloc_stack_of_enum_unknown_use // CHECK: alloc_stack $MP // CHECK: } // end sil function 'dont_expand_alloc_stack_of_enum_unknown_use' diff --git a/test/SILOptimizer/templvalueopt.sil b/test/SILOptimizer/templvalueopt.sil index 81f57e2d4da75..42b6d63ed236a 100644 --- a/test/SILOptimizer/templvalueopt.sil +++ b/test/SILOptimizer/templvalueopt.sil @@ -3,7 +3,7 @@ import Swift import Builtin -// CHECK-LABEL: sil @test_enum_with_initialize +// CHECK-LABEL: sil @test_enum_with_initialize : // CHECK: bb0(%0 : $*Optional, %1 : $*Any): // CHECK-NEXT: [[E:%[0-9]+]] = init_enum_data_addr %0 // CHECK-NEXT: copy_addr [take] %1 to [initialization] [[E]] @@ -22,7 +22,7 @@ bb0(%0 : $*Optional, %1 : $*Any): return %6 : $() } -// CHECK-LABEL: sil @test_enum_without_initialize +// CHECK-LABEL: sil @test_enum_without_initialize : // CHECK: bb0(%0 : $*Optional, %1 : $*Any): // CHECK-NEXT: destroy_addr %0 // CHECK-NEXT: [[E:%[0-9]+]] = init_enum_data_addr %0 @@ -48,7 +48,7 @@ struct ConformingStruct : Proto { @_hasStorage let a: Any } -// CHECK-LABEL: sil @test_existential +// CHECK-LABEL: sil @test_existential : // CHECK: bb0(%0 : $*Proto, %1 : $*ConformingStruct): // CHECK-NEXT: [[E:%[0-9]+]] = init_existential_addr %0 // CHECK-NEXT: copy_addr [take] %1 to [initialization] [[E]] @@ -80,7 +80,7 @@ struct AddressOnlyPayload { // There should only be a single copy_addr after optimization. // -// CHECK-LABEL: sil @test_initialize_struct +// CHECK-LABEL: sil @test_initialize_struct : // CHECK: bb0(%0 : $*TestStruct, %1 : $*Any, %2 : $Int): // CHECK-NEXT: [[E:%[0-9]+]] = struct_element_addr %0 // CHECK-NEXT: [[LEFT:%[0-9]+]] = init_enum_data_addr [[E]] @@ -114,7 +114,7 @@ bb0(%0 : $*TestStruct, %1 : $*Any, %2 : $Int): return %20 : $() } -// CHECK-LABEL: sil @bail_on_write_to_dest +// CHECK-LABEL: sil @bail_on_write_to_dest : // CHECK: alloc_stack // CHECK: copy_addr // CHECK: copy_addr @@ -132,7 +132,7 @@ bb0(%0 : $*Optional, %1 : $*Any): return %6 : $() } -// CHECK-LABEL: sil @write_to_dest_ok_if_before_liferange +// CHECK-LABEL: sil @write_to_dest_ok_if_before_liferange : // CHECK: bb0(%0 : $*Optional, %1 : $*Any): // CHECK-NEXT: destroy_addr // CHECK-NEXT: init_enum_data_addr @@ -161,7 +161,7 @@ struct StructWithEnum : Proto { @_hasStorage let e: Enum } -// CHECK-LABEL: sil @move_projections +// CHECK-LABEL: sil @move_projections : // CHECK: bb0(%0 : $*Proto, %1 : $*Any): // CHECK-NEXT: [[S:%[0-9]+]] = init_existential_addr %0 : $*Proto, $StructWithEnum // CHECK-NEXT: [[E:%[0-9]+]] = struct_element_addr [[S]] : $*StructWithEnum, #StructWithEnum.e @@ -188,7 +188,7 @@ bb0(%0 : $*Proto, %1 : $*Any): return %10 : $() } -// CHECK-LABEL: sil @cant_move_projections +// CHECK-LABEL: sil @cant_move_projections : // CHECK: alloc_stack // CHECK: copy_addr // CHECK: load @@ -210,7 +210,7 @@ bb0(%0 : $*Any, %1 : $*Builtin.RawPointer): sil @init_optional : $@convention(thin) () -> @out Optional -// CHECK-LABEL: sil @instructions_after_copy_addr +// CHECK-LABEL: sil @instructions_after_copy_addr : // CHECK: alloc_stack // CHECK: copy_addr // CHECK: copy_addr @@ -231,7 +231,7 @@ bb0(%0 : $*Optional, %1 : $*Any): return %6 : $() } -// CHECK-LABEL: sil @dont_optimize_swap +// CHECK-LABEL: sil @dont_optimize_swap : // CHECK: alloc_stack // CHECK: copy_addr // CHECK: copy_addr diff --git a/test/SILOptimizer/templvalueopt_ossa.sil b/test/SILOptimizer/templvalueopt_ossa.sil new file mode 100644 index 0000000000000..e37a777091b80 --- /dev/null +++ b/test/SILOptimizer/templvalueopt_ossa.sil @@ -0,0 +1,251 @@ +// RUN: %target-sil-opt -enable-sil-verify-all %s -temp-lvalue-opt | %FileCheck %s + +import Swift +import Builtin + +// CHECK-LABEL: sil [ossa] @test_enum_with_initialize : +// CHECK: bb0(%0 : $*Optional, %1 : $*Any): +// CHECK-NEXT: [[E:%[0-9]+]] = init_enum_data_addr %0 +// CHECK-NEXT: copy_addr [take] %1 to [initialization] [[E]] +// CHECK-NEXT: inject_enum_addr %0 : $*Optional, #Optional.some!enumelt +// CHECK-NOT: copy_addr +// CHECK: } // end sil function 'test_enum_with_initialize' +sil [ossa] @test_enum_with_initialize : $@convention(thin) (@in Any) -> @out Optional { +bb0(%0 : $*Optional, %1 : $*Any): + %2 = alloc_stack $Optional + %3 = init_enum_data_addr %2 : $*Optional, #Optional.some!enumelt + copy_addr [take] %1 to [initialization] %3 : $*Any + inject_enum_addr %2 : $*Optional, #Optional.some!enumelt + copy_addr [take] %2 to [initialization] %0 : $*Optional + dealloc_stack %2 : $*Optional + %6 = tuple () + return %6 : $() +} + +// CHECK-LABEL: sil [ossa] @test_enum_without_initialize : +// CHECK: bb0(%0 : $*Optional, %1 : $*Any): +// CHECK-NEXT: destroy_addr %0 +// CHECK-NEXT: [[E:%[0-9]+]] = init_enum_data_addr %0 +// CHECK-NEXT: copy_addr [take] %1 to [initialization] [[E]] +// CHECK-NEXT: inject_enum_addr %0 : $*Optional, #Optional.some!enumelt +// CHECK-NOT: copy_addr +// CHECK: } // end sil function 'test_enum_without_initialize' +sil [ossa] @test_enum_without_initialize : $@convention(thin) (@inout Optional, @in Any) -> () { +bb0(%0 : $*Optional, %1 : $*Any): + %2 = alloc_stack $Optional + %3 = init_enum_data_addr %2 : $*Optional, #Optional.some!enumelt + copy_addr [take] %1 to [initialization] %3 : $*Any + inject_enum_addr %2 : $*Optional, #Optional.some!enumelt + copy_addr [take] %2 to %0 : $*Optional + dealloc_stack %2 : $*Optional + %6 = tuple () + return %6 : $() +} + +protocol Proto {} + +struct ConformingStruct : Proto { + @_hasStorage let a: Any +} + +// CHECK-LABEL: sil [ossa] @test_existential : +// CHECK: bb0(%0 : $*Proto, %1 : $*ConformingStruct): +// CHECK-NEXT: [[E:%[0-9]+]] = init_existential_addr %0 +// CHECK-NEXT: copy_addr [take] %1 to [initialization] [[E]] +// CHECK-NOT: copy_addr +// CHECK: } // end sil function 'test_existential' +sil [ossa] @test_existential : $@convention(thin) (@in ConformingStruct) -> @out Proto { +bb0(%0 : $*Proto, %1 : $*ConformingStruct): + %2 = alloc_stack $Proto + %3 = init_existential_addr %2 : $*Proto, $ConformingStruct + copy_addr [take] %1 to [initialization] %3 : $*ConformingStruct + copy_addr [take] %2 to [initialization] %0 : $*Proto + dealloc_stack %2 : $*Proto + %6 = tuple () + return %6 : $() +} + +enum Either { + case left(Left), right(Right) +} + +public struct TestStruct { + @_hasStorage var e: Either +} + +struct AddressOnlyPayload { + @_hasStorage let a: Any + @_hasStorage let i: Int +} + +// There should only be a single copy_addr after optimization. +// +// CHECK-LABEL: sil [ossa] @test_initialize_struct : +// CHECK: bb0(%0 : $*TestStruct, %1 : $*Any, %2 : $Int): +// CHECK-NEXT: [[E:%[0-9]+]] = struct_element_addr %0 +// CHECK-NEXT: [[LEFT:%[0-9]+]] = init_enum_data_addr [[E]] +// CHECK-NEXT: [[A:%[0-9]+]] = struct_element_addr [[LEFT]] +// CHECK-NEXT: copy_addr [take] %1 to [initialization] [[A]] +// CHECK-NEXT: [[I:%[0-9]+]] = struct_element_addr [[LEFT]] +// CHECK-NEXT: store %2 to [trivial] [[I]] +// CHECK-NEXT: inject_enum_addr [[E]] +// CHECK-NOT: copy_addr +// CHECK: } // end sil function 'test_initialize_struct' +sil [ossa] @test_initialize_struct : $@convention(method) (@in Any, Int) -> @out TestStruct { +bb0(%0 : $*TestStruct, %1 : $*Any, %2 : $Int): + %3 = alloc_stack $TestStruct + %4 = alloc_stack $Either + %5 = alloc_stack $AddressOnlyPayload + %6 = struct_element_addr %5 : $*AddressOnlyPayload, #AddressOnlyPayload.a + copy_addr [take] %1 to [initialization] %6 : $*Any + %8 = struct_element_addr %5 : $*AddressOnlyPayload, #AddressOnlyPayload.i + store %2 to [trivial] %8 : $*Int + %10 = init_enum_data_addr %4 : $*Either, #Either.left!enumelt + copy_addr [take] %5 to [initialization] %10 : $*AddressOnlyPayload + inject_enum_addr %4 : $*Either, #Either.left!enumelt + dealloc_stack %5 : $*AddressOnlyPayload + %14 = struct_element_addr %3 : $*TestStruct, #TestStruct.e + copy_addr [take] %4 to [initialization] %14 : $*Either + dealloc_stack %4 : $*Either + copy_addr %3 to [initialization] %0 : $*TestStruct + destroy_addr %3 : $*TestStruct + dealloc_stack %3 : $*TestStruct + %20 = tuple () + return %20 : $() +} + +// CHECK-LABEL: sil [ossa] @bail_on_write_to_dest : +// CHECK: alloc_stack +// CHECK: copy_addr +// CHECK: copy_addr +// CHECK: } // end sil function 'bail_on_write_to_dest' +sil [ossa] @bail_on_write_to_dest : $@convention(thin) (@inout Optional, @in Any) -> () { +bb0(%0 : $*Optional, %1 : $*Any): + %2 = alloc_stack $Optional + %3 = init_enum_data_addr %2 : $*Optional, #Optional.some!enumelt + copy_addr [take] %1 to [initialization] %3 : $*Any + inject_enum_addr %2 : $*Optional, #Optional.some!enumelt + destroy_addr %0 : $*Optional + copy_addr [take] %2 to [initialization] %0 : $*Optional + dealloc_stack %2 : $*Optional + %6 = tuple () + return %6 : $() +} + +// CHECK-LABEL: sil [ossa] @write_to_dest_ok_if_before_liferange : +// CHECK: bb0(%0 : $*Optional, %1 : $*Any): +// CHECK-NEXT: destroy_addr +// CHECK-NEXT: init_enum_data_addr +// CHECK-NEXT: copy_addr +// CHECK-NEXT: inject_enum_addr +// CHECK-NOT: copy_addr +// CHECK: } // end sil function 'write_to_dest_ok_if_before_liferange' +sil [ossa] @write_to_dest_ok_if_before_liferange : $@convention(thin) (@inout Optional, @in Any) -> () { +bb0(%0 : $*Optional, %1 : $*Any): + %2 = alloc_stack $Optional + destroy_addr %0 : $*Optional + %3 = init_enum_data_addr %2 : $*Optional, #Optional.some!enumelt + copy_addr [take] %1 to [initialization] %3 : $*Any + inject_enum_addr %2 : $*Optional, #Optional.some!enumelt + copy_addr [take] %2 to [initialization] %0 : $*Optional + dealloc_stack %2 : $*Optional + %6 = tuple () + return %6 : $() +} + +enum Enum { + case A(Optional), B +} + +struct StructWithEnum : Proto { + @_hasStorage let e: Enum +} + +// CHECK-LABEL: sil [ossa] @move_projections : +// CHECK: bb0(%0 : $*Proto, %1 : $*Any): +// CHECK-NEXT: [[S:%[0-9]+]] = init_existential_addr %0 : $*Proto, $StructWithEnum +// CHECK-NEXT: [[E:%[0-9]+]] = struct_element_addr [[S]] : $*StructWithEnum, #StructWithEnum.e +// CHECK-NEXT: [[ENUMA:%[0-9]+]] = init_enum_data_addr [[E]] : $*Enum, #Enum.A!enumelt +// CHECK-NEXT: [[OPTIONAL:%[0-9]+]] = init_enum_data_addr [[ENUMA]] : $*Optional, #Optional.some!enumelt +// CHECK-NEXT: copy_addr [take] %1 to [initialization] [[OPTIONAL]] : $*Any +// CHECK-NEXT: inject_enum_addr [[ENUMA]] : $*Optional, #Optional.some!enumelt +// CHECK-NEXT: inject_enum_addr [[E]] : $*Enum, #Enum.A!enumelt +// CHECK-NOT: copy_addr +// CHECK: } // end sil function 'move_projections' +sil [ossa] @move_projections : $@convention(thin) (@in Any) -> @out Proto { +bb0(%0 : $*Proto, %1 : $*Any): + %2 = alloc_stack $Optional + %3 = init_enum_data_addr %2 : $*Optional, #Optional.some!enumelt + copy_addr [take] %1 to [initialization] %3 : $*Any + inject_enum_addr %2 : $*Optional, #Optional.some!enumelt + %4 = init_existential_addr %0 : $*Proto, $StructWithEnum + %5 = struct_element_addr %4 : $*StructWithEnum, #StructWithEnum.e + %6 = init_enum_data_addr %5 : $*Enum, #Enum.A!enumelt + copy_addr [take] %2 to [initialization] %6 : $*Optional + inject_enum_addr %5 : $*Enum, #Enum.A!enumelt + dealloc_stack %2 : $*Optional + %10 = tuple () + return %10 : $() +} + +// CHECK-LABEL: sil [ossa] @cant_move_projections : +// CHECK: alloc_stack +// CHECK: copy_addr +// CHECK: load +// CHECK: copy_addr +// CHECK: } // end sil function 'cant_move_projections' +sil [ossa] @cant_move_projections : $@convention(thin) (@in Any, @in_guaranteed Builtin.RawPointer) -> () { +bb0(%0 : $*Any, %1 : $*Builtin.RawPointer): + %2 = alloc_stack $Optional + %3 = init_enum_data_addr %2 : $*Optional, #Optional.some!enumelt + copy_addr [take] %0 to [initialization] %3 : $*Any + inject_enum_addr %2 : $*Optional, #Optional.some!enumelt + %4 = load [trivial] %1 : $*Builtin.RawPointer + %5 = pointer_to_address %4 : $Builtin.RawPointer to $*Optional + copy_addr [take] %2 to [initialization] %5 : $*Optional + dealloc_stack %2 : $*Optional + %10 = tuple () + return %10 : $() +} + +sil [ossa] @init_optional : $@convention(thin) () -> @out Optional + +// CHECK-LABEL: sil [ossa] @instructions_after_copy_addr : +// CHECK: alloc_stack +// CHECK: copy_addr +// CHECK: copy_addr +// CHECK: apply +// CHECK: } // end sil function 'instructions_after_copy_addr' +sil [ossa] @instructions_after_copy_addr : $@convention(thin) (@in Any) -> @out Optional { +bb0(%0 : $*Optional, %1 : $*Any): + %2 = alloc_stack $Optional + %3 = init_enum_data_addr %2 : $*Optional, #Optional.some!enumelt + copy_addr [take] %1 to [initialization] %3 : $*Any + inject_enum_addr %2 : $*Optional, #Optional.some!enumelt + copy_addr [take] %2 to [initialization] %0 : $*Optional + %4 = function_ref @init_optional : $@convention(thin) () -> @out Optional + %5 = apply %4(%2) : $@convention(thin) () -> @out Optional + destroy_addr %2 : $*Optional + dealloc_stack %2 : $*Optional + %6 = tuple () + return %6 : $() +} + +// CHECK-LABEL: sil [ossa] @dont_optimize_swap : +// CHECK: alloc_stack +// CHECK: copy_addr +// CHECK: copy_addr +// CHECK: copy_addr +// CHECK: dealloc_stack +// CHECK: } // end sil function 'dont_optimize_swap' +sil [ossa] @dont_optimize_swap : $@convention(thin) (@inout T, @inout T) -> () { +bb0(%0 : $*T, %1 : $*T): + %2 = alloc_stack $T + copy_addr [take] %0 to [initialization] %2 : $*T + copy_addr [take] %1 to [initialization] %0 : $*T + copy_addr [take] %2 to [initialization] %1 : $*T + dealloc_stack %2 : $*T + %78 = tuple () + return %78 : $() +} + diff --git a/test/attr/attr_objc_async.swift b/test/attr/attr_objc_async.swift index a3a2aad0c459d..59300a20cdb09 100644 --- a/test/attr/attr_objc_async.swift +++ b/test/attr/attr_objc_async.swift @@ -3,10 +3,11 @@ // RUN: not %target-swift-frontend -typecheck -dump-ast -disable-objc-attr-requires-foundation-module %s -swift-version 5 -enable-source-import -I %S/Inputs -enable-experimental-concurrency > %t.ast // RUN: %FileCheck -check-prefix CHECK-DUMP %s < %t.ast // REQUIRES: objc_interop +// REQUIRES: concurrency import Foundation -// CHECK: class Concurrency -class Concurrency { +// CHECK: class MyClass +class MyClass { // CHECK: @objc func doBigJob() async -> Int // CHECK-DUMP: func_decl{{.*}}doBigJob{{.*}}foreign_async=@convention(block) (Int) -> (),completion_handler_param=0 @objc func doBigJob() async -> Int { return 0 } @@ -21,3 +22,30 @@ class Concurrency { @objc class func createAsynchronously() async -> Self? { nil } // expected-error@-1{{asynchronous method returning 'Self' cannot be '@objc'}} } + +// Actor class exporting Objective-C entry points. + +// CHECK: class MyActor +actor class MyActor { + // CHECK: @objc func doBigJob() async -> Int + // CHECK-DUMP: func_decl{{.*}}doBigJob{{.*}}foreign_async=@convention(block) (Int) -> (),completion_handler_param=0 + @objc func doBigJob() async -> Int { return 0 } + + // CHECK: @objc func doBigJobOrFail(_: Int) async throws -> (AnyObject, Int) + // CHECK-DUMP: func_decl{{.*}}doBigJobOrFail{{.*}}foreign_async=@convention(block) (Optional, Int, Optional) -> (),completion_handler_param=1,error_param=2 + @objc func doBigJobOrFail(_: Int) async throws -> (AnyObject, Int) { return (self, 0) } + + // Actor-isolated entities cannot be exposed to Objective-C. + @objc func synchronousBad() { } // expected-error{{actor-isolated instance method 'synchronousBad()' cannot be @objc}} + // expected-note@-1{{add 'async' to function 'synchronousBad()' to make it asynchronous}} + // expected-note@-2{{add '@asyncHandler' to function 'synchronousBad()' to create an implicit asynchronous context}} + + @objc var badProp: AnyObject { self } // expected-error{{actor-isolated property 'badProp' cannot be @objc}} + @objc subscript(index: Int) -> AnyObject { self } // expected-error{{actor-isolated subscript 'subscript(_:)' cannot be @objc}} + + // CHECK: @objc @actorIndependent func synchronousGood() + @objc @actorIndependent func synchronousGood() { } +} + +// CHECK: @objc actor class MyObjCActor +@objc actor class MyObjCActor: NSObject { } diff --git a/test/decl/class/actor/noconcurrency.swift b/test/decl/class/actor/noconcurrency.swift index 48e4c7d018bc5..2773bafa44d6f 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' attribute is only valid when experimental concurrency is enabled}} +actor class C { } // expected-error{{'actor' modifier is only valid when experimental concurrency is enabled}} diff --git a/test/decl/protocol/special/Actor.swift b/test/decl/protocol/special/Actor.swift new file mode 100644 index 0000000000000..76c8f83b8a6ab --- /dev/null +++ b/test/decl/protocol/special/Actor.swift @@ -0,0 +1,72 @@ +// RUN: %target-typecheck-verify-swift -enable-experimental-concurrency +// REQUIRES: concurrency + +// Synthesis of for actor classes. +import _Concurrency + +actor class A1 { + var x: Int = 17 +} + +actor class A2: Actor { + var x: Int = 17 +} + +actor class A3: Actor { + var x: Int = 17 +} + +actor class A4: A1 { +} + +actor class A5: A2 { +} + +actor class A6: A1, Actor { // expected-error{{redundant conformance of 'A6' to protocol 'Actor'}} + // expected-note@-1{{'A6' inherits conformance to protocol 'Actor' from superclass here}} +} + +// Explicitly satisfying the requirement. + +actor class A7 { + // Okay: satisfy the requirement explicitly + @actorIndependent func enqueue(partialTask: PartialAsyncTask) { } +} + +// A non-actor class can conform to the Actor protocol, if it does it properly. +class C1: Actor { + func enqueue(partialTask: PartialAsyncTask) { } +} + +// Bad actors, that incorrectly try to satisfy the various requirements. + +// Method that is not usable as a witness. +actor class BA1 { + func enqueue(partialTask: PartialAsyncTask) { } // expected-error{{invalid redeclaration of synthesized implementation for protocol requirement 'enqueue(partialTask:)'}} +} + +// Method that isn't part of the main class definition cannot be used to +// satisfy the requirement, because then it would not have a vtable slot. +actor class BA2 { } + +extension BA2 { + // expected-error@+1{{'enqueue(partialTask:)' can only be implemented in the definition of actor class 'BA2'}} + @actorIndependent func enqueue(partialTask: PartialAsyncTask) { } +} + +// No synthesis for non-actor classes. +class C2: Actor { // expected-error{{type 'C2' does not conform to protocol 'Actor'}} +} + +// Make sure the conformances actually happen. +func acceptActor(_: T.Type) { } + +func testConformance() { + acceptActor(A1.self) + acceptActor(A2.self) + acceptActor(A3.self) + acceptActor(A4.self) + acceptActor(A5.self) + acceptActor(A6.self) + acceptActor(A7.self) +} diff --git a/unittests/AST/TestContext.cpp b/unittests/AST/TestContext.cpp index 174cf90630097..1cee32305944f 100644 --- a/unittests/AST/TestContext.cpp +++ b/unittests/AST/TestContext.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "TestContext.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/Module.h" #include "swift/AST/ParseRequests.h" #include "swift/Strings.h"