diff --git a/CHANGELOG.md b/CHANGELOG.md index 31ec6a15fa35d..b3564bae5b6f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,33 @@ CHANGELOG +Swift Next +---------- + +* [SE-0269][]: + + When an escaping closure explicitly captures `self` in its capture list, the + use of implicit `self` is enabled within that closure. This means that the + following code is now valid: + + ```swift + func doStuff(_ stuff: @escaping () -> Void) {} + + class C { + var x = 0 + + func method() { + doStuff { [self] in + x += 1 + } + } + } + ``` + + This proposal also introduces new diagnostics for inserting `self` into the + closure's capture list in addition to the existing 'use `self.` explicitly' + fix-it. + Swift 5.2 --------- @@ -7856,6 +7883,7 @@ Swift 1.0 [SE-0252]: [SE-0253]: [SE-0254]: +[SE-0269]: [SR-106]: [SR-419]: diff --git a/cmake/modules/FindLibEdit.cmake b/cmake/modules/FindLibEdit.cmake index b4f0cb3298114..bec05e328d6bb 100644 --- a/cmake/modules/FindLibEdit.cmake +++ b/cmake/modules/FindLibEdit.cmake @@ -59,6 +59,12 @@ else() LibEdit_LIBRARIES VERSION_VAR LibEdit_VERSION_STRING) - mark_as_advanced(LibEdit_INCLUDE_DIRS LibEdit_LIBRARIES) endif() +if(LibEdit_FOUND AND NOT TARGET libedit) + add_library(libedit UNKNOWN IMPORTED) + set_target_properties(libedit PROPERTIES + IMPORTED_LOCATION ${LibEdit_LIBRARIES} + INTERFACE_INCLUDE_DIRECTORIES ${LibEdit_INCLUDE_DIRS}) +endif() +mark_as_advanced(LibEdit_INCLUDE_DIRS LibEdit_LIBRARIES) diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 13c1b96ba02e1..be98a06362e3c 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -631,6 +631,10 @@ class ASTContext final { /// compiler for the target platform. AvailabilityContext getSwift52Availability(); + /// Get the runtime availability of features that have been introduced in the + /// Swift compiler for future versions of the target platform. + AvailabilityContext getSwiftFutureAvailability(); + //===--------------------------------------------------------------------===// // Diagnostics Helper functions diff --git a/include/swift/AST/AnyRequest.h b/include/swift/AST/AnyRequest.h index 0b6b9b5f4cfa0..cfe0e78941dc5 100644 --- a/include/swift/AST/AnyRequest.h +++ b/include/swift/AST/AnyRequest.h @@ -10,7 +10,8 @@ // //===----------------------------------------------------------------------===// // -// This file defines the AnyRequest class, which describes a stored request. +// This file defines type-erasing wrappers for requests used by the Evaluator +// class. // //===----------------------------------------------------------------------===// @@ -21,7 +22,6 @@ #include "swift/Basic/TypeID.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/Hashing.h" -#include "llvm/ADT/IntrusiveRefCntPtr.h" #include namespace llvm { @@ -35,261 +35,406 @@ using llvm::hash_value; class DiagnosticEngine; -/// Stores a request (for the \c Evaluator class) of any kind. -/// -/// Requests must be value types and provide the following API to be stored in -/// an \c AnyRequest instance: -/// -/// - Copy constructor -/// - Equality operator (==) -/// - Hashing support (hash_value) -/// - TypeID support (see swift/Basic/TypeID.h) -/// - Display support (free function): -/// void simple_display(llvm::raw_ostream &, const T &); -/// - Cycle diagnostics operations: -/// void diagnoseCycle(DiagnosticEngine &diags) const; -/// void noteCycleStep(DiagnosticEngine &diags) const; -/// -class AnyRequest { - friend llvm::DenseMapInfo; - - static hash_code hashForHolder(uint64_t typeID, hash_code requestHash) { - return hash_combine(typeID, requestHash); - } - - /// Abstract base class used to hold the specific request kind. - class HolderBase : public llvm::RefCountedBase { - public: - /// The type ID of the request being stored. - const uint64_t typeID; - - /// Hash value for the request itself. - const hash_code hash; - - protected: - /// Initialize base with type ID and hash code. - HolderBase(uint64_t typeID, hash_code hash) - : typeID(typeID), hash(AnyRequest::hashForHolder(typeID, hash)) { } - - public: - virtual ~HolderBase(); - - /// Determine whether this request is equivalent to the \c other - /// request. - virtual bool equals(const HolderBase &other) const = 0; - - /// Display. - virtual void display(llvm::raw_ostream &out) const = 0; - - /// Diagnose a cycle detected for this request. - virtual void diagnoseCycle(DiagnosticEngine &diags) const = 0; - - /// Note that this request is part of a cycle. - virtual void noteCycleStep(DiagnosticEngine &diags) const = 0; - - /// Retrieve the nearest source location to which this request applies. - virtual SourceLoc getNearestLoc() const = 0; - }; - - /// Holds a value that can be used as a request input/output. +/// A collection of functions that describe how to perform operations for a +/// specific concrete request, obtained using +/// \c AnyRequestVTable::get(). +struct AnyRequestVTable { template - class Holder final : public HolderBase { - public: - const Request request; - - Holder(const Request &request) - : HolderBase(TypeID::value, hash_value(request)), - request(request) { } - - Holder(Request &&request) - : HolderBase(TypeID::value, hash_value(request)), - request(std::move(request)) { } - - virtual ~Holder() { } - - /// Determine whether this request is equivalent to another. - /// - /// The caller guarantees that the typeIDs are the same. - virtual bool equals(const HolderBase &other) const override { - assert(typeID == other.typeID && "Caller should match typeIDs"); - return request == static_cast &>(other).request; + struct Impl { + static void copy(const void *input, void *output) { + new (output) Request(*static_cast(input)); } - - /// Display. - virtual void display(llvm::raw_ostream &out) const override { - simple_display(out, request); + static hash_code getHash(const void *ptr) { + return hash_value(*static_cast(ptr)); } - - /// Diagnose a cycle detected for this request. - virtual void diagnoseCycle(DiagnosticEngine &diags) const override { - request.diagnoseCycle(diags); + static void deleter(void *ptr) { + static_cast(ptr)->~Request(); } - - /// Note that this request is part of a cycle. - virtual void noteCycleStep(DiagnosticEngine &diags) const override { - request.noteCycleStep(diags); + static bool isEqual(const void *lhs, const void *rhs) { + return *static_cast(lhs) == + *static_cast(rhs); } - - /// Retrieve the nearest source location to which this request applies. - virtual SourceLoc getNearestLoc() const override { - return request.getNearestLoc(); + static void simpleDisplay(const void *ptr, llvm::raw_ostream &out) { + simple_display(out, *static_cast(ptr)); + } + static void diagnoseCycle(const void *ptr, DiagnosticEngine &diags) { + static_cast(ptr)->diagnoseCycle(diags); + } + static void noteCycleStep(const void *ptr, DiagnosticEngine &diags) { + static_cast(ptr)->noteCycleStep(diags); + } + static SourceLoc getNearestLoc(const void *ptr) { + return static_cast(ptr)->getNearestLoc(); } }; - /// FIXME: Inefficient. Use the low bits. - enum class StorageKind { + const uint64_t typeID; + const size_t requestSize; + const std::function copy; + const std::function getHash; + const std::function deleter; + const std::function isEqual; + const std::function simpleDisplay; + const std::function diagnoseCycle; + const std::function noteCycleStep; + const std::function getNearestLoc; + + template + static const AnyRequestVTable *get() { + static const AnyRequestVTable vtable = { + TypeID::value, + sizeof(Request), + &Impl::copy, + &Impl::getHash, + &Impl::deleter, + &Impl::isEqual, + &Impl::simpleDisplay, + &Impl::diagnoseCycle, + &Impl::noteCycleStep, + &Impl::getNearestLoc, + }; + return &vtable; + } +}; + +/// Base class for request type-erasing wrappers. +template +class AnyRequestBase { + friend llvm::DenseMapInfo; + +protected: + static hash_code hashForHolder(uint64_t typeID, hash_code requestHash) { + return hash_combine(typeID, requestHash); + } + + enum class StorageKind : uint8_t { Normal, Empty, Tombstone, - } storageKind = StorageKind::Normal; + }; + + /// The vtable and storage kind. + llvm::PointerIntPair vtableAndKind; - /// The data stored in this value. - llvm::IntrusiveRefCntPtr stored; + StorageKind getStorageKind() const { return vtableAndKind.getInt(); } - AnyRequest(StorageKind storageKind) : storageKind(storageKind) { - assert(storageKind != StorageKind::Normal); + /// Whether this object is storing a value, and is not empty or a tombstone. + bool hasStorage() const { + switch (getStorageKind()) { + case StorageKind::Empty: + case StorageKind::Tombstone: + return false; + case StorageKind::Normal: + return true; + } + llvm_unreachable("Unhandled case in switch"); } -public: - AnyRequest(const AnyRequest &other) = default; - AnyRequest &operator=(const AnyRequest &other) = default; + /// Retrieve the vtable to perform operations on the type-erased request. + const AnyRequestVTable *getVTable() const { + assert(hasStorage() && "Shouldn't be querying empty or tombstone"); + return vtableAndKind.getPointer(); + } - AnyRequest(AnyRequest &&other) - : storageKind(other.storageKind), stored(std::move(other.stored)) { - other.storageKind = StorageKind::Empty; + AnyRequestBase(const AnyRequestVTable *vtable, StorageKind storageKind) { + vtableAndKind.setPointer(vtable); + vtableAndKind.setInt(storageKind); + assert((bool)vtable == hasStorage() && "Must have a vtable with storage"); } - AnyRequest &operator=(AnyRequest &&other) { - storageKind = other.storageKind; - stored = std::move(other.stored); - other.storageKind = StorageKind::Empty; - other.stored = nullptr; - return *this; + AnyRequestBase(const AnyRequestBase &other) { + vtableAndKind = other.vtableAndKind; } - // Create a local template typename `ValueType` in the template specialization - // so that we can refer to it in the SFINAE condition as well as the body of - // the template itself. The SFINAE condition allows us to remove this - // constructor from candidacy when evaluating explicit construction with an - // instance of `AnyRequest`. If we do not do so, we will find ourselves with - // ambiguity with this constructor and the defined move constructor above. - /// Construct a new instance with the given value. - template ::type>::type, - typename = typename std::enable_if< - !std::is_same::value>::type> - explicit AnyRequest(T &&value) : storageKind(StorageKind::Normal) { - stored = llvm::IntrusiveRefCntPtr( - new Holder(std::forward(value))); +private: + Derived &asDerived() { + return *static_cast(this); + } + const Derived &asDerived() const { + return *static_cast(this); } + const void *getRawStorage() const { return asDerived().getRawStorage(); } + +public: /// Cast to a specific (known) type. template const Request &castTo() const { - assert(stored->typeID == TypeID::value && "wrong type in cast"); - return static_cast *>(stored.get())->request; + assert(getVTable()->typeID == TypeID::value && + "Wrong type in cast"); + return *static_cast(getRawStorage()); } /// Try casting to a specific (known) type, returning \c nullptr on /// failure. template const Request *getAs() const { - if (stored->typeID != TypeID::value) + if (getVTable()->typeID != TypeID::value) return nullptr; - return &static_cast *>(stored.get())->request; + return static_cast(getRawStorage()); } /// Diagnose a cycle detected for this request. void diagnoseCycle(DiagnosticEngine &diags) const { - stored->diagnoseCycle(diags); + getVTable()->diagnoseCycle(getRawStorage(), diags); } /// Note that this request is part of a cycle. void noteCycleStep(DiagnosticEngine &diags) const { - stored->noteCycleStep(diags); + getVTable()->noteCycleStep(getRawStorage(), diags); } /// Retrieve the nearest source location to which this request applies. SourceLoc getNearestLoc() const { - return stored->getNearestLoc(); + return getVTable()->getNearestLoc(getRawStorage()); } /// Compare two instances for equality. - friend bool operator==(const AnyRequest &lhs, const AnyRequest &rhs) { - if (lhs.storageKind != rhs.storageKind) { + friend bool operator==(const AnyRequestBase &lhs, + const AnyRequestBase &rhs) { + // If the storage kinds don't match, we're done. + if (lhs.getStorageKind() != rhs.getStorageKind()) return false; - } - if (lhs.storageKind != StorageKind::Normal) + // If the storage kinds do match, but there's no storage, they're trivially + // equal. + if (!lhs.hasStorage()) return true; - if (lhs.stored->typeID != rhs.stored->typeID) + // Must be storing the same kind of request. + if (lhs.getVTable()->typeID != rhs.getVTable()->typeID) return false; - return lhs.stored->equals(*rhs.stored); + return lhs.getVTable()->isEqual(lhs.getRawStorage(), rhs.getRawStorage()); } - friend bool operator!=(const AnyRequest &lhs, const AnyRequest &rhs) { + friend bool operator!=(const Derived &lhs, const Derived &rhs) { return !(lhs == rhs); } - friend hash_code hash_value(const AnyRequest &any) { - if (any.storageKind != StorageKind::Normal) + friend hash_code hash_value(const AnyRequestBase &req) { + // If there's no storage, return a trivial hash value. + if (!req.hasStorage()) return 1; - return any.stored->hash; + auto reqHash = req.getVTable()->getHash(req.getRawStorage()); + return hashForHolder(req.getVTable()->typeID, reqHash); } - friend void simple_display(llvm::raw_ostream &out, const AnyRequest &any) { - any.stored->display(out); + friend void simple_display(llvm::raw_ostream &out, + const AnyRequestBase &req) { + req.getVTable()->simpleDisplay(req.getRawStorage(), out); } +}; - /// Return the result of calling simple_display as a string. - std::string getAsString() const; +/// Provides a view onto a request that is stored on the stack. Objects of this +/// class must not outlive the request they reference. +/// +/// Requests must be value types and provide the following API: +/// +/// - Copy constructor +/// - Equality operator (==) +/// - Hashing support (hash_value) +/// - TypeID support (see swift/Basic/TypeID.h) +/// - Display support (free function): +/// void simple_display(llvm::raw_ostream &, const T &); +/// - Cycle diagnostics operations: +/// void diagnoseCycle(DiagnosticEngine &diags) const; +/// void noteCycleStep(DiagnosticEngine &diags) const; +/// +class ActiveRequest final : public AnyRequestBase { + template + friend class AnyRequestBase; + + friend class AnyRequest; + friend llvm::DenseMapInfo; + + /// Pointer to the request stored on the stack. + const void *storage; + + /// Creates an \c ActiveRequest without storage. + explicit ActiveRequest(StorageKind storageKind) + : AnyRequestBase(/*vtable*/ nullptr, storageKind) {} - static AnyRequest getEmptyKey() { - return AnyRequest(StorageKind::Empty); + const void *getRawStorage() const { return storage; } + +public: + /// Creates a new \c ActiveRequest referencing a concrete request on the + /// stack. + template + explicit ActiveRequest(const Request &request) + : AnyRequestBase(AnyRequestVTable::get(), StorageKind::Normal) { + storage = &request; } +}; - static AnyRequest getTombstoneKey() { - return AnyRequest(StorageKind::Tombstone); +/// Stores a request (for the \c Evaluator class) of any kind. Unlike +/// \c ActiveRequest, this wrapper has ownership of the underlying request. +/// +/// Requests must be value types and provide the following API to be stored in +/// an \c AnyRequest instance: +/// +/// - Copy constructor +/// - Equality operator (==) +/// - Hashing support (hash_value) +/// - TypeID support (see swift/Basic/TypeID.h) +/// - Display support (free function): +/// void simple_display(llvm::raw_ostream &, const T &); +/// - Cycle diagnostics operations: +/// void diagnoseCycle(DiagnosticEngine &diags) const; +/// void noteCycleStep(DiagnosticEngine &diags) const; +/// +class AnyRequest final : public AnyRequestBase { + template + friend class AnyRequestBase; + + friend llvm::DenseMapInfo; + + /// Pointer to the request on the heap. + void *storage; + + /// Creates an \c AnyRequest without storage. + explicit AnyRequest(StorageKind storageKind) + : AnyRequestBase(/*vtable*/ nullptr, storageKind) {} + + const void *getRawStorage() const { return storage; } + + /// Whether this wrapper is storing the same underlying request as an + /// \c ActiveRequest. + bool isStorageEqual(const ActiveRequest &other) const { + // If either wrapper isn't storing anything, just return false. + if (!hasStorage() || !other.hasStorage()) + return false; + + if (getVTable()->typeID != other.getVTable()->typeID) + return false; + + return getVTable()->isEqual(getRawStorage(), other.getRawStorage()); + } + +public: + AnyRequest(const AnyRequest &other) : AnyRequestBase(other) { + if (hasStorage()) { + // For now, just allocate a new buffer and copy across the request. This + // should only happen when performing operations on the (disabled by + // default) dependency graph. + storage = llvm::safe_malloc(getVTable()->requestSize); + getVTable()->copy(other.storage, storage); + } } + AnyRequest &operator=(const AnyRequest &other) { + if (&other != this) { + this->~AnyRequest(); + new (this) AnyRequest(other); + } + return *this; + } + + AnyRequest(AnyRequest &&other) : AnyRequestBase(other), + storage(other.storage) { + new (&other) AnyRequest(StorageKind::Empty); + } + + AnyRequest &operator=(AnyRequest &&other) { + if (&other != this) { + this->~AnyRequest(); + new (this) AnyRequest(std::move(other)); + } + return *this; + } + + // Create a local template typename `Request` in the template specialization + // so that we can refer to it in the SFINAE condition as well as the body of + // the template itself. The SFINAE condition allows us to remove this + // constructor from candidacy when evaluating explicit construction with an + // instance of `AnyRequest`. If we do not do so, we will find ourselves with + // ambiguity with this constructor and the defined move constructor above. + /// Construct a new instance with the given value. + template , + typename = typename std::enable_if< + !std::is_same::value>::type> + explicit AnyRequest(T &&request) + : AnyRequestBase(AnyRequestVTable::get(), StorageKind::Normal) { + storage = llvm::safe_malloc(sizeof(Request)); + new (storage) Request(std::forward(request)); + } + + /// Construct an \c AnyRequest from an \c ActiveRequest, allowing the + /// underlying request to persist. + explicit AnyRequest(const ActiveRequest &req) + : AnyRequestBase(req.getVTable(), StorageKind::Normal) { + assert(req.hasStorage()); + storage = llvm::safe_malloc(getVTable()->requestSize); + getVTable()->copy(req.storage, storage); + } + + ~AnyRequest() { + if (hasStorage()) { + getVTable()->deleter(storage); + std::free(storage); + } + } + + /// Return the result of calling simple_display as a string. + std::string getAsString() const; }; } // end namespace swift namespace llvm { + template<> + struct DenseMapInfo { + using ActiveRequest = swift::ActiveRequest; + static inline ActiveRequest getEmptyKey() { + return ActiveRequest(ActiveRequest::StorageKind::Empty); + } + static inline ActiveRequest getTombstoneKey() { + return ActiveRequest(ActiveRequest::StorageKind::Tombstone); + } + static unsigned getHashValue(const ActiveRequest &request) { + return hash_value(request); + } + static bool isEqual(const ActiveRequest &lhs, const ActiveRequest &rhs) { + return lhs == rhs; + } + }; + template<> struct DenseMapInfo { - static inline swift::AnyRequest getEmptyKey() { - return swift::AnyRequest::getEmptyKey(); + using AnyRequest = swift::AnyRequest; + using ActiveRequest = swift::ActiveRequest; + + static inline AnyRequest getEmptyKey() { + return AnyRequest(AnyRequest::StorageKind::Empty); } static inline swift::AnyRequest getTombstoneKey() { - return swift::AnyRequest::getTombstoneKey(); + return AnyRequest(AnyRequest::StorageKind::Tombstone); } - static unsigned getHashValue(const swift::AnyRequest &request) { + static unsigned getHashValue(const AnyRequest &request) { return hash_value(request); } template static unsigned getHashValue(const Request &request) { - return swift::AnyRequest::hashForHolder(swift::TypeID::value, - hash_value(request)); + return AnyRequest::hashForHolder(swift::TypeID::value, + hash_value(request)); } - static bool isEqual(const swift::AnyRequest &lhs, - const swift::AnyRequest &rhs) { + static unsigned getHashValue(const ActiveRequest &request) { + return hash_value(request); + } + static bool isEqual(const AnyRequest &lhs, const AnyRequest &rhs) { return lhs == rhs; } template - static bool isEqual(const Request &lhs, - const swift::AnyRequest &rhs) { - if (rhs == getEmptyKey() || rhs == getTombstoneKey()) - return false; - const Request *rhsRequest = rhs.getAs(); - if (!rhsRequest) + static bool isEqual(const Request &lhs, const AnyRequest &rhs) { + if (!rhs.hasStorage()) return false; - return lhs == *rhsRequest; + + auto *rhsRequest = rhs.getAs(); + return rhsRequest && lhs == *rhsRequest; + } + static bool isEqual(const ActiveRequest &lhs, const AnyRequest &rhs) { + return rhs.isStorageEqual(lhs); } }; diff --git a/include/swift/AST/Evaluator.h b/include/swift/AST/Evaluator.h index 4b4e89a8e3c43..6ad636f7f4566 100644 --- a/include/swift/AST/Evaluator.h +++ b/include/swift/AST/Evaluator.h @@ -208,7 +208,7 @@ class Evaluator { /// A vector containing all of the active evaluation requests, which /// is treated as a stack and is used to detect cycles. - llvm::SetVector activeRequests; + llvm::SetVector activeRequests; /// A cache that stores the results of requests. llvm::DenseMap cache; @@ -308,7 +308,7 @@ class Evaluator { typename std::enable_if::type* = nullptr> void cacheOutput(const Request &request, typename Request::OutputType &&output) { - cache.insert({getCanonicalRequest(request), std::move(output)}); + cache.insert({AnyRequest(request), std::move(output)}); } /// Clear the cache stored within this evaluator. @@ -320,24 +320,13 @@ class Evaluator { /// Is the given request, or an equivalent, currently being evaluated? template bool hasActiveRequest(const Request &request) const { - return activeRequests.count(AnyRequest(request)); + return activeRequests.count(ActiveRequest(request)); } private: - template - const AnyRequest &getCanonicalRequest(const Request &request) { - // FIXME: DenseMap ought to let us do this with one hash lookup. - auto iter = dependencies.find_as(request); - if (iter != dependencies.end()) - return iter->first; - auto insertResult = dependencies.insert({AnyRequest(request), {}}); - assert(insertResult.second && "just checked if the key was already there"); - return insertResult.first->first; - } - /// Diagnose a cycle detected in the evaluation of the given /// request. - void diagnoseCycle(const AnyRequest &request); + void diagnoseCycle(const ActiveRequest &request); /// Check the dependency from the current top of the stack to /// the given request, including cycle detection and diagnostics. @@ -345,14 +334,16 @@ class Evaluator { /// \returns true if a cycle was detected, in which case this function has /// already diagnosed the cycle. Otherwise, returns \c false and adds this /// request to the \c activeRequests stack. - bool checkDependency(const AnyRequest &request); + bool checkDependency(const ActiveRequest &request); /// Produce the result of the request without caching. template llvm::Expected getResultUncached(const Request &request) { + auto activeReq = ActiveRequest(request); + // Check for a cycle. - if (checkDependency(getCanonicalRequest(request))) { + if (checkDependency(activeReq)) { return llvm::Error( llvm::make_unique>(request, *this)); } @@ -360,7 +351,7 @@ class Evaluator { // Make sure we remove this from the set of active requests once we're // done. SWIFT_DEFER { - assert(activeRequests.back().castTo() == request); + assert(activeRequests.back() == activeReq); activeRequests.pop_back(); }; @@ -421,7 +412,7 @@ class Evaluator { return result; // Cache the result. - cache.insert({getCanonicalRequest(request), *result}); + cache.insert({AnyRequest(request), *result}); return result; } diff --git a/include/swift/AST/SILOptions.h b/include/swift/AST/SILOptions.h index 31344711acc8f..1ce85e82224f5 100644 --- a/include/swift/AST/SILOptions.h +++ b/include/swift/AST/SILOptions.h @@ -57,6 +57,10 @@ class SILOptions { /// purposes. bool EnableOSSAOptimizations = true; + /// Controls whether to turn on speculative devirtualization. + /// It is turned off by default. + bool EnableSpeculativeDevirtualization = false; + /// Should we run any SIL performance optimizations /// /// Useful when you want to enable -O LLVM opts but not -O SIL opts. diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 0ffd3a600eb17..2d64b050c2f7b 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -3637,13 +3637,35 @@ inline bool isGuaranteedParameter(ParameterConvention conv) { llvm_unreachable("bad convention kind"); } +/// The differentiability of a SIL function type parameter. +enum class SILParameterDifferentiability : unsigned { + /// Either differentiable or not applicable. + /// + /// - If the function type is not `@differentiable`, parameter + /// differentiability is not applicable. This case is the default value. + /// - If the function type is `@differentiable`, the function is + /// differentiable with respect to this parameter. + DifferentiableOrNotApplicable, + + /// Not differentiable: a `@noDerivative` parameter. + /// + /// May be applied only to parameters of `@differentiable` function types. + /// The function type is not differentiable with respect to this parameter. + NotDifferentiable, +}; + /// A parameter type and the rules for passing it. class SILParameterInfo { llvm::PointerIntPair TypeAndConvention; + SILParameterDifferentiability Differentiability : 1; + public: SILParameterInfo() = default;//: Ty(), Convention((ParameterConvention)0) {} - SILParameterInfo(CanType type, ParameterConvention conv) - : TypeAndConvention(type, conv) { + SILParameterInfo( + CanType type, ParameterConvention conv, + SILParameterDifferentiability differentiability = + SILParameterDifferentiability::DifferentiableOrNotApplicable) + : TypeAndConvention(type, conv), Differentiability(differentiability) { assert(type->isLegalSILType() && "SILParameterInfo has illegal SIL type"); } @@ -3698,6 +3720,16 @@ class SILParameterInfo { return isGuaranteedParameter(getConvention()); } + SILParameterDifferentiability getDifferentiability() const { + return Differentiability; + } + + SILParameterInfo getWithDifferentiability( + SILParameterDifferentiability differentiability) const { + return SILParameterInfo(getInterfaceType(), getConvention(), + differentiability); + } + /// The SIL storage type determines the ABI for arguments based purely on the /// formal parameter conventions. The actual SIL type for the argument values /// may differ in canonical SIL. In particular, opaque values require indirect @@ -3726,6 +3758,7 @@ class SILParameterInfo { void profile(llvm::FoldingSetNodeID &id) { id.AddPointer(getInterfaceType().getPointer()); id.AddInteger((unsigned)getConvention()); + id.AddInteger((unsigned)getDifferentiability()); } SWIFT_DEBUG_DUMP; @@ -3739,8 +3772,9 @@ class SILParameterInfo { } bool operator==(SILParameterInfo rhs) const { - return getInterfaceType() == rhs.getInterfaceType() - && getConvention() == rhs.getConvention(); + return getInterfaceType() == rhs.getInterfaceType() && + getConvention() == rhs.getConvention() && + getDifferentiability() == rhs.getDifferentiability(); } bool operator!=(SILParameterInfo rhs) const { return !(*this == rhs); @@ -4093,6 +4127,13 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, return ExtInfo(NoEscape ? (Bits | NoEscapeMask) : (Bits & ~NoEscapeMask), Other); } + ExtInfo + withDifferentiabilityKind(DifferentiabilityKind differentiability) const { + return ExtInfo( + (Bits & ~DifferentiabilityMask) | + ((unsigned)differentiability << DifferentiabilityMaskOffset), + Other); + } std::pair getFuncAttrKey() const { return std::make_pair(Bits, Other.ClangFunctionType); @@ -4390,6 +4431,89 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, const clang::FunctionType *getClangFunctionType() const; + /// Returns the type of the derivative function for the given parameter + /// indices, result index, derivative function kind, derivative function + /// generic signature (optional), and other auxiliary parameters. + /// + /// Preconditions: + /// - Parameters corresponding to parameter indices must conform to + /// `Differentiable`. + /// - The result corresponding to the result index must conform to + /// `Differentiable`. + /// + /// Typing rules, given: + /// - Original function type: $(T0, T1, ...) -> (R0, R1, ...) + /// + /// Terminology: + /// - The derivative of a `Differentiable`-conforming type has the + /// `TangentVector` associated type. `TangentVector` is abbreviated as `Tan` + /// below. + /// - "wrt" parameters refers to parameters indicated by the parameter + /// indices. + /// - "wrt" result refers to the result indicated by the result index. + /// + /// JVP derivative type: + /// - Takes original parameters. + /// - Returns original results, followed by a differential function, which + /// takes "wrt" parameter derivatives and returns a "wrt" result derivative. + /// + /// $(T0, ...) -> (R0, ..., (T0.Tan, T1.Tan, ...) -> R0.Tan) + /// ^~~~~~~ ^~~~~~~~~~~~~~~~~~~ ^~~~~~ + /// original results | derivatives wrt params | derivative wrt result + /// + /// VJP derivative type: + /// - Takes original parameters. + /// - Returns original results, followed by a pullback function, which + /// takes a "wrt" result derivative and returns "wrt" parameter derivatives. + /// + /// $(T0, ...) -> (R0, ..., (R0.Tan) -> (T0.Tan, T1.Tan, ...)) + /// ^~~~~~~ ^~~~~~ ^~~~~~~~~~~~~~~~~~~ + /// original results | derivative wrt result | derivatives wrt params + /// + /// A "constrained derivative generic signature" is computed from + /// `derivativeFunctionGenericSignature`, if specified. Otherwise, it is + /// computed from the original generic signature. A "constrained derivative + /// generic signature" requires all "wrt" parameters to conform to + /// `Differentiable`; this is important for correctness. + /// + /// This "constrained derivative generic signature" is used for + /// parameter/result type lowering. It is used as the actual generic signature + /// of the derivative function type iff the original function type has a + /// generic signature and not all generic parameters are bound to concrete + /// types. Otherwise, no derivative generic signature is used. + /// + /// Other properties of the original function type are copied exactly: + /// `ExtInfo`, coroutine kind, callee convention, yields, optional error + /// result, witness method conformance, etc. + /// + /// Special cases: + /// - Reabstraction thunks have special derivative type calculation. The + /// original function-typed last parameter is transformed into a + /// `@differentiable` function-typed parameter in the derivative type. This + /// is necessary for the differentiation transform to support reabstraction + /// thunk differentiation because the function argument is opaque and cannot + /// be differentiated. Instead, the argument is made `@differentiable` and + /// reabstraction thunk JVP/VJP callers are responsible for passing a + /// `@differentiable` function. + /// - TODO(TF-1036): Investigate more efficient reabstraction thunk + /// derivative approaches. The last argument can simply be a + /// corresponding derivative function, instead of a `@differentiable` + /// function - this is more direct. It may be possible to implement + /// reabstraction thunk derivatives using "reabstraction thunks for + /// the original function's derivative", avoiding extra code generation. + /// + /// Caveats: + /// - We may support multiple result indices instead of a single result index + /// eventually. At the SIL level, this enables differentiating wrt multiple + /// function results. At the Swift level, this enables differentiating wrt + /// multiple tuple elements for tuple-returning functions. + CanSILFunctionType getAutoDiffDerivativeFunctionType( + IndexSubset *parameterIndices, unsigned resultIndex, + AutoDiffDerivativeFunctionKind kind, Lowering::TypeConverter &TC, + LookupConformanceFn lookupConformance, + CanGenericSignature derivativeFunctionGenericSignature = nullptr, + bool isReabstractionThunk = false); + ExtInfo getExtInfo() const { return ExtInfo(Bits.SILFunctionType.ExtInfoBits, getClangFunctionType()); } diff --git a/include/swift/Basic/AnyValue.h b/include/swift/Basic/AnyValue.h index 6d76e9ba43b75..7a24dfec61a0b 100644 --- a/include/swift/Basic/AnyValue.h +++ b/include/swift/Basic/AnyValue.h @@ -170,8 +170,9 @@ namespace llvm { void simple_display(raw_ostream &out, const Optional &opt) { if (opt) { simple_display(out, *opt); + } else { + out << "None"; } - out << "None"; } } // end namespace llvm diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index a5d369df049b5..f8fd3abd492b0 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -282,6 +282,9 @@ def disable_ossa_opts : Flag<["-"], "disable-ossa-opts">, def disable_sil_partial_apply : Flag<["-"], "disable-sil-partial-apply">, HelpText<"Disable use of partial_apply in SIL generation">; +def enable_spec_devirt : Flag<["-"], "enable-spec-devirt">, + HelpText<"Enable speculative devirtualization pass.">; + def enable_ownership_stripping_after_serialization : Flag<["-"], "enable-ownership-stripping-after-serialization">, HelpText<"Strip ownership after serialization">; diff --git a/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h b/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h index 832e40214e64b..c1d405c4d7f42 100644 --- a/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h @@ -660,7 +660,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis { : F(F), EA(EA), isSummaryGraph(isSummaryGraph) {} /// Returns true if the connection graph is empty. - bool isEmpty() { + bool isEmpty() const { return Values2Nodes.empty() && Nodes.empty() && UsePoints.empty(); } @@ -906,11 +906,10 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// Dump the connection graph to a DOT file for remote debugging. void dumpCG() const; - /// Checks if the graph is OK. - void verify(bool allowMerge = false) const; + /// Checks if the graph is valid and complete. + void verify() const; - /// Just verifies the graph structure. This function can also be called - /// during the graph is modified, e.g. in mergeAllScheduledNodes(). + /// Just verifies the graph nodes. void verifyStructure(bool allowMerge = false) const; friend struct ::CGForDotView; @@ -1045,8 +1044,9 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// If \p ai is an optimizable @_semantics("array.uninitialized") call, return /// valid call information. - ArrayUninitCall canOptimizeArrayUninitializedCall(ApplyInst *ai, - ConnectionGraph *conGraph); + ArrayUninitCall + canOptimizeArrayUninitializedCall(ApplyInst *ai, + const ConnectionGraph *conGraph); /// Return true of this tuple_extract is the result of an optimizable /// @_semantics("array.uninitialized") call. @@ -1174,25 +1174,9 @@ class EscapeAnalysis : public BottomUpIPAnalysis { virtual bool needsNotifications() override { return true; } - virtual void verify() const override { -#ifndef NDEBUG - for (auto Iter : Function2Info) { - FunctionInfo *FInfo = Iter.second; - FInfo->Graph.verify(); - FInfo->SummaryGraph.verify(); - } -#endif - } - - virtual void verify(SILFunction *F) const override { -#ifndef NDEBUG - if (FunctionInfo *FInfo = Function2Info.lookup(F)) { - FInfo->Graph.verify(); - FInfo->SummaryGraph.verify(); - } -#endif - } + virtual void verify() const override; + virtual void verify(SILFunction *F) const override; }; } // end namespace swift diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index b335fa071117b..ef6969430da40 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3327,6 +3327,15 @@ SILFunctionType::SILFunctionType( "Cannot return an @noescape function type"); } } + + // Check that `@noDerivative` parameters only exist on `@differentiable` + // functions. + if (!ext.isDifferentiable()) + for (auto param : getParameters()) + assert(param.getDifferentiability() == + SILParameterDifferentiability::DifferentiableOrNotApplicable && + "non-`@differentiable` function should not have NotDifferentiable " + "parameter"); #endif } diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 1fe355d76bc47..eeabdf4de8a65 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -4649,6 +4649,13 @@ void SILParameterInfo::print(raw_ostream &OS, const PrintOptions &Opts) const { } void SILParameterInfo::print(ASTPrinter &Printer, const PrintOptions &Opts) const { + switch (getDifferentiability()) { + case SILParameterDifferentiability::NotDifferentiable: + Printer << "@noDerivative "; + break; + default: + break; + } Printer << getStringForParameterConvention(getConvention()); getInterfaceType().print(Printer, Opts); } diff --git a/lib/AST/Availability.cpp b/lib/AST/Availability.cpp index 579fe7f0f3c24..538924ed8a23b 100644 --- a/lib/AST/Availability.cpp +++ b/lib/AST/Availability.cpp @@ -243,7 +243,7 @@ AvailabilityContext ASTContext::getTypesInAbstractMetadataStateAvailability() { } AvailabilityContext ASTContext::getPrespecializedGenericMetadataAvailability() { - return getSwift52Availability(); + return getSwiftFutureAvailability(); } AvailabilityContext ASTContext::getSwift52Availability() { @@ -262,3 +262,20 @@ AvailabilityContext ASTContext::getSwift52Availability() { return AvailabilityContext::alwaysAvailable(); } } + +AvailabilityContext ASTContext::getSwiftFutureAvailability() { + auto target = LangOpts.Target; + + if (target.isMacOSX() ) { + return AvailabilityContext( + VersionRange::allGTE(llvm::VersionTuple(10, 99, 0))); + } else if (target.isiOS()) { + return AvailabilityContext( + VersionRange::allGTE(llvm::VersionTuple(99, 0, 0))); + } else if (target.isWatchOS()) { + return AvailabilityContext( + VersionRange::allGTE(llvm::VersionTuple(9, 99, 0))); + } else { + return AvailabilityContext::alwaysAvailable(); + } +} diff --git a/lib/AST/Evaluator.cpp b/lib/AST/Evaluator.cpp index f229cd50838d0..3d831f24d1971 100644 --- a/lib/AST/Evaluator.cpp +++ b/lib/AST/Evaluator.cpp @@ -24,8 +24,6 @@ using namespace swift; -AnyRequest::HolderBase::~HolderBase() { } - std::string AnyRequest::getAsString() const { std::string result; { @@ -75,35 +73,43 @@ void Evaluator::emitRequestEvaluatorGraphViz(llvm::StringRef graphVizPath) { printDependenciesGraphviz(out); } -bool Evaluator::checkDependency(const AnyRequest &request) { +bool Evaluator::checkDependency(const ActiveRequest &request) { if (buildDependencyGraph) { + // Insert the request into the dependency graph if we haven't already. + auto req = AnyRequest(request); + dependencies.insert({req, {}}); + // If there is an active request, record it's dependency on this request. - if (!activeRequests.empty()) - dependencies[activeRequests.back()].push_back(request); + if (!activeRequests.empty()) { + auto activeDeps = dependencies.find_as(activeRequests.back()); + assert(activeDeps != dependencies.end()); + activeDeps->second.push_back(req); + } } // Record this as an active request. - if (activeRequests.insert(request)) { + if (activeRequests.insert(request)) return false; - } // Diagnose cycle. diagnoseCycle(request); + return true; +} +void Evaluator::diagnoseCycle(const ActiveRequest &request) { if (debugDumpCycles) { llvm::errs() << "===CYCLE DETECTED===\n"; llvm::DenseSet visitedAnywhere; llvm::SmallVector visitedAlongPath; std::string prefixStr; - printDependencies(activeRequests.front(), llvm::errs(), visitedAnywhere, - visitedAlongPath, activeRequests.getArrayRef(), + SmallVector highlightPath; + for (auto &req : activeRequests) + highlightPath.push_back(AnyRequest(req)); + printDependencies(AnyRequest(activeRequests.front()), llvm::errs(), + visitedAnywhere, visitedAlongPath, highlightPath, prefixStr, /*lastChild=*/true); } - return true; -} - -void Evaluator::diagnoseCycle(const AnyRequest &request) { request.diagnoseCycle(diags); for (const auto &step : llvm::reverse(activeRequests)) { if (step == request) return; diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index e60015f6530df..3bc3c4b5d1e3d 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -2867,22 +2867,23 @@ void ClangModuleUnit::lookupValue(DeclName name, NLKind lookupKind, } } -/// Determine whether the given Clang entry is visible. -/// -/// FIXME: this is an elaborate hack to badly reflect Clang's -/// submodule visibility into Swift. -static bool isVisibleClangEntry(clang::ASTContext &ctx, - SwiftLookupTable::SingleEntry entry) { - if (auto clangDecl = entry.dyn_cast()) { - // For a declaration, check whether the declaration is hidden. - if (!clangDecl->isHidden()) return true; +bool ClangImporter::Implementation::isVisibleClangEntry( + const clang::NamedDecl *clangDecl) { + // For a declaration, check whether the declaration is hidden. + if (!clangDecl->isHidden()) return true; - // Is any redeclaration visible? - for (auto redecl : clangDecl->redecls()) { - if (!cast(redecl)->isHidden()) return true; - } + // Is any redeclaration visible? + for (auto redecl : clangDecl->redecls()) { + if (!cast(redecl)->isHidden()) return true; + } - return false; + return false; +} + +bool ClangImporter::Implementation::isVisibleClangEntry( + SwiftLookupTable::SingleEntry entry) { + if (auto clangDecl = entry.dyn_cast()) { + return isVisibleClangEntry(clangDecl); } // If it's a macro from a module, check whether the module has been imported. @@ -2917,15 +2918,13 @@ ClangModuleUnit::lookupNestedType(Identifier name, if (!baseTypeContext) return nullptr; - auto &clangCtx = owner.getClangASTContext(); - // FIXME: This is very similar to what's in Implementation::lookupValue and // Implementation::loadAllMembers. SmallVector results; for (auto entry : lookupTable->lookup(SerializedSwiftName(name.str()), baseTypeContext)) { // If the entry is not visible, skip it. - if (!isVisibleClangEntry(clangCtx, entry)) continue; + if (!owner.isVisibleClangEntry(entry)) continue; auto *clangDecl = entry.dyn_cast(); if (!clangDecl) @@ -2993,14 +2992,13 @@ void ClangImporter::loadExtensions(NominalTypeDecl *nominal, // Dig through each of the Swift lookup tables, creating extensions // where needed. - auto &clangCtx = Impl.getClangASTContext(); (void)Impl.forEachLookupTable([&](SwiftLookupTable &table) -> bool { // FIXME: If we already looked at this for this generation, // skip. for (auto entry : table.allGlobalsAsMembersInContext(effectiveClangContext)) { // If the entry is not visible, skip it. - if (!isVisibleClangEntry(clangCtx, entry)) continue; + if (!Impl.isVisibleClangEntry(entry)) continue; if (auto decl = entry.dyn_cast()) { // Import the context of this declaration, which has the @@ -3581,7 +3579,7 @@ void ClangImporter::Implementation::lookupValue( for (auto entry : table.lookup(name.getBaseName(), clangTU)) { // If the entry is not visible, skip it. - if (!isVisibleClangEntry(clangCtx, entry)) continue; + if (!isVisibleClangEntry(entry)) continue; ValueDecl *decl; // If it's a Clang declaration, try to import it. @@ -3685,11 +3683,9 @@ void ClangImporter::Implementation::lookupObjCMembers( SwiftLookupTable &table, DeclName name, VisibleDeclConsumer &consumer) { - auto &clangCtx = getClangASTContext(); - for (auto clangDecl : table.lookupObjCMembers(name.getBaseName())) { // If the entry is not visible, skip it. - if (!isVisibleClangEntry(clangCtx, clangDecl)) continue; + if (!isVisibleClangEntry(clangDecl)) continue; forEachDistinctName(clangDecl, [&](ImportedName importedName, @@ -3801,8 +3797,6 @@ ClangImporter::Implementation::loadNamedMembers( auto table = findLookupTable(*CMO); assert(table && "clang module without lookup table"); - clang::ASTContext &clangCtx = getClangASTContext(); - assert(isa(CD) || isa(CD)); ensureSuperclassMembersAreLoaded(dyn_cast(D)); @@ -3812,7 +3806,7 @@ ClangImporter::Implementation::loadNamedMembers( effectiveClangContext)) { if (!entry.is()) continue; auto member = entry.get(); - if (!isVisibleClangEntry(clangCtx, member)) continue; + if (!isVisibleClangEntry(member)) continue; // Skip Decls from different clang::DeclContexts if (member->getDeclContext() != CDC) continue; @@ -3833,7 +3827,7 @@ ClangImporter::Implementation::loadNamedMembers( effectiveClangContext)) { if (!entry.is()) continue; auto member = entry.get(); - if (!isVisibleClangEntry(clangCtx, member)) continue; + if (!isVisibleClangEntry(member)) continue; // Skip Decls from different clang::DeclContexts if (member->getDeclContext() != CDC) continue; diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index cee4054672513..752c3fc9056e5 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -8670,7 +8670,8 @@ void ClangImporter::Implementation::collectMembersToAdd( for (const clang::Decl *m : objcContainer->decls()) { auto nd = dyn_cast(m); if (nd && nd == nd->getCanonicalDecl() && - nd->getDeclContext() == objcContainer) + nd->getDeclContext() == objcContainer && + isVisibleClangEntry(nd)) insertMembersAndAlternates(nd, members); } diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index 8f1bd96b4000f..6c851d5468d8d 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -1299,6 +1299,13 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// false otherwise. bool forEachLookupTable(llvm::function_ref fn); + /// Determine whether the given Clang entry is visible. + /// + /// FIXME: this is an elaborate hack to badly reflect Clang's + /// submodule visibility into Swift. + bool isVisibleClangEntry(const clang::NamedDecl *clangDecl); + bool isVisibleClangEntry(SwiftLookupTable::SingleEntry entry); + /// Look for namespace-scope values with the given name in the given /// Swift lookup table. void lookupValue(SwiftLookupTable &table, DeclName name, diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index c1b940b601fd4..3ac0cd2dc59fd 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -959,6 +959,7 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args, Opts.EnableARCOptimizations &= !Args.hasArg(OPT_disable_arc_opts); Opts.EnableOSSAOptimizations &= !Args.hasArg(OPT_disable_ossa_opts); + Opts.EnableSpeculativeDevirtualization |= Args.hasArg(OPT_enable_spec_devirt); Opts.DisableSILPerfOptimizations |= Args.hasArg(OPT_disable_sil_perf_optzns); Opts.CrossModuleOptimization |= Args.hasArg(OPT_CrossModuleOptimization); Opts.VerifyAll |= Args.hasArg(OPT_sil_verify_all); diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index fac4c166f9308..a39ff7e63e4cd 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -467,6 +467,11 @@ bool swift::performLLVM(const IRGenOptions &Opts, DiagnosticEngine *Diags, StringRef OutputFilename, UnifiedStatsReporter *Stats) { #ifndef NDEBUG +// FIXME: Some bots are failing. See: rdar://54708850 +//#define DEBUG_VERIFY_GENERATED_CODE +#endif + +#ifdef DEBUG_VERIFY_GENERATED_CODE // To check that we only skip generating code when it would have no effect, in // assertion builds we still generate the code, but write it into a temporary // file that we compare to the original file. @@ -499,7 +504,7 @@ bool swift::performLLVM(const IRGenOptions &Opts, DiagnosticEngine *Diags, !Opts.PrintInlineTree && !needsRecompile(OutputFilename, HashData, HashGlobal, DiagMutex)) { // The llvm IR did not change. We don't need to re-create the object file. -#ifdef NDEBUG +#ifndef DEBUG_VERIFY_GENERATED_CODE return false; #else // ...but we're in an asserts build, so we want to check that assumption. @@ -603,8 +608,7 @@ bool swift::performLLVM(const IRGenOptions &Opts, DiagnosticEngine *Diags, if (DiagMutex) DiagMutex->unlock(); } -#if 0 -#ifndef NDEBUG +#ifdef DEBUG_VERIFY_GENERATED_CODE if (!OriginalOutputFilename.empty()) { // We're done changing the file; make sure it's saved before we compare. RawOS->close(); @@ -639,7 +643,6 @@ bool swift::performLLVM(const IRGenOptions &Opts, DiagnosticEngine *Diags, llvm_unreachable("one of these should be a temporary file"); } } -#endif #endif return false; diff --git a/lib/IRGen/SwitchBuilder.h b/lib/IRGen/SwitchBuilder.h index 550098f1d6a19..2a90fd013adf7 100644 --- a/lib/IRGen/SwitchBuilder.h +++ b/lib/IRGen/SwitchBuilder.h @@ -165,10 +165,9 @@ class SwitchSwitchBuilder final : public SwitchBuilder { } }; -std::unique_ptr SwitchBuilder::create(IRGenFunction &IGF, - llvm::Value *Subject, - SwitchDefaultDest Default, - unsigned NumCases) { +inline std::unique_ptr +SwitchBuilder::create(IRGenFunction &IGF, llvm::Value *Subject, + SwitchDefaultDest Default, unsigned NumCases) { // Pick a builder based on how many total reachable destinations we intend // to have. switch (NumCases + (Default.getInt() == IsNotUnreachable)) { diff --git a/lib/Immediate/CMakeLists.txt b/lib/Immediate/CMakeLists.txt index 01bbe6ae504f3..195ef7e7cc00f 100644 --- a/lib/Immediate/CMakeLists.txt +++ b/lib/Immediate/CMakeLists.txt @@ -16,5 +16,5 @@ if(LibEdit_FOUND AND LibEdit_HAS_UNICODE) target_compile_definitions(swiftImmediate PRIVATE HAVE_LIBEDIT) target_link_libraries(swiftImmediate PRIVATE - ${LibEdit_LIBRARIES}) + libedit) endif() diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp index df9384141bf26..6e0fac061678f 100644 --- a/lib/SIL/SILFunctionType.cpp +++ b/lib/SIL/SILFunctionType.cpp @@ -22,6 +22,7 @@ #include "swift/AST/DiagnosticsSIL.h" #include "swift/AST/ForeignInfo.h" #include "swift/AST/GenericEnvironment.h" +#include "swift/AST/GenericSignatureBuilder.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" #include "swift/AST/ProtocolConformance.h" @@ -190,6 +191,196 @@ SILFunctionType::getWitnessMethodClass(SILModule &M) const { return nullptr; } +// Returns the canonical generic signature for an autodiff derivative function +// given an existing derivative function generic signature. All +// differentiability parameters are required to conform to `Differentiable`. +static CanGenericSignature getAutoDiffDerivativeFunctionGenericSignature( + CanGenericSignature derivativeFnGenSig, + ArrayRef originalParameters, + IndexSubset *parameterIndices, ModuleDecl *module) { + if (!derivativeFnGenSig) + return nullptr; + auto &ctx = module->getASTContext(); + GenericSignatureBuilder builder(ctx); + // Add derivative function generic signature. + builder.addGenericSignature(derivativeFnGenSig); + // All differentiability parameters are required to conform to + // `Differentiable`. + auto source = + GenericSignatureBuilder::FloatingRequirementSource::forAbstract(); + auto *differentiableProtocol = + ctx.getProtocol(KnownProtocolKind::Differentiable); + for (unsigned paramIdx : parameterIndices->getIndices()) { + auto paramType = originalParameters[paramIdx].getInterfaceType(); + Requirement req(RequirementKind::Conformance, paramType, + differentiableProtocol->getDeclaredType()); + builder.addRequirement(req, source, module); + } + return std::move(builder) + .computeGenericSignature(SourceLoc(), /*allowConcreteGenericParams*/ true) + ->getCanonicalSignature(); +} + +CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType( + IndexSubset *parameterIndices, unsigned resultIndex, + AutoDiffDerivativeFunctionKind kind, TypeConverter &TC, + LookupConformanceFn lookupConformance, + CanGenericSignature derivativeFnGenSig, bool isReabstractionThunk) { + auto &ctx = getASTContext(); + + // Returns true if `index` is a differentiability parameter index. + auto isDiffParamIndex = [&](unsigned index) -> bool { + return index < parameterIndices->getCapacity() && + parameterIndices->contains(index); + }; + + // Calculate differentiability parameter infos. + SmallVector diffParams; + for (auto valueAndIndex : enumerate(getParameters())) + if (isDiffParamIndex(valueAndIndex.index())) + diffParams.push_back(valueAndIndex.value()); + + // Get the canonical derivative function generic signature. + if (!derivativeFnGenSig) + derivativeFnGenSig = getSubstGenericSignature(); + derivativeFnGenSig = getAutoDiffDerivativeFunctionGenericSignature( + derivativeFnGenSig, getParameters(), parameterIndices, &TC.M); + + // Given a type, returns its formal SIL parameter info. + auto getTangentParameterInfoForOriginalResult = + [&](CanType tanType, ResultConvention origResConv) -> SILParameterInfo { + AbstractionPattern pattern(derivativeFnGenSig, tanType); + auto &tl = + TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); + ParameterConvention conv; + switch (origResConv) { + case ResultConvention::Owned: + case ResultConvention::Autoreleased: + conv = tl.isTrivial() ? ParameterConvention::Direct_Unowned + : ParameterConvention::Direct_Guaranteed; + break; + case ResultConvention::Unowned: + case ResultConvention::UnownedInnerPointer: + conv = ParameterConvention::Direct_Unowned; + break; + case ResultConvention::Indirect: + conv = ParameterConvention::Indirect_In_Guaranteed; + break; + } + return {tanType, conv}; + }; + + // Given a type, returns its formal SIL result info. + auto getTangentResultInfoForOriginalParameter = + [&](CanType tanType, ParameterConvention origParamConv) -> SILResultInfo { + AbstractionPattern pattern(derivativeFnGenSig, tanType); + auto &tl = + TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); + ResultConvention conv; + switch (origParamConv) { + case ParameterConvention::Direct_Owned: + case ParameterConvention::Direct_Guaranteed: + case ParameterConvention::Direct_Unowned: + conv = + tl.isTrivial() ? ResultConvention::Unowned : ResultConvention::Owned; + break; + case ParameterConvention::Indirect_In: + case ParameterConvention::Indirect_Inout: + case ParameterConvention::Indirect_In_Constant: + case ParameterConvention::Indirect_In_Guaranteed: + case ParameterConvention::Indirect_InoutAliasable: + conv = ResultConvention::Indirect; + break; + } + return {tanType, conv}; + }; + + CanSILFunctionType closureType; + switch (kind) { + case AutoDiffDerivativeFunctionKind::JVP: { + SmallVector differentialParams; + for (auto ¶m : diffParams) { + auto paramTan = + param.getInterfaceType()->getAutoDiffTangentSpace(lookupConformance); + assert(paramTan && "Parameter type does not have a tangent space?"); + differentialParams.push_back( + {paramTan->getCanonicalType(), param.getConvention()}); + } + SmallVector differentialResults; + auto &result = getResults()[resultIndex]; + auto resultTan = + result.getInterfaceType()->getAutoDiffTangentSpace(lookupConformance); + assert(resultTan && "Result type does not have a tangent space?"); + differentialResults.push_back( + {resultTan->getCanonicalType(), result.getConvention()}); + closureType = SILFunctionType::get( + /*genericSignature*/ nullptr, ExtInfo(), SILCoroutineKind::None, + ParameterConvention::Direct_Guaranteed, differentialParams, {}, + differentialResults, None, getSubstitutions(), + isGenericSignatureImplied(), ctx); + break; + } + case AutoDiffDerivativeFunctionKind::VJP: { + SmallVector pullbackParams; + auto &origRes = getResults()[resultIndex]; + auto resultTan = + origRes.getInterfaceType()->getAutoDiffTangentSpace(lookupConformance); + assert(resultTan && "Result type does not have a tangent space?"); + pullbackParams.push_back(getTangentParameterInfoForOriginalResult( + resultTan->getCanonicalType(), origRes.getConvention())); + SmallVector pullbackResults; + for (auto ¶m : diffParams) { + auto paramTan = + param.getInterfaceType()->getAutoDiffTangentSpace(lookupConformance); + assert(paramTan && "Parameter type does not have a tangent space?"); + pullbackResults.push_back(getTangentResultInfoForOriginalParameter( + paramTan->getCanonicalType(), param.getConvention())); + } + closureType = SILFunctionType::get( + /*genericSignature*/ nullptr, ExtInfo(), SILCoroutineKind::None, + ParameterConvention::Direct_Guaranteed, pullbackParams, {}, + pullbackResults, {}, getSubstitutions(), isGenericSignatureImplied(), + ctx); + break; + } + } + + SmallVector newParameters; + newParameters.reserve(getNumParameters()); + for (auto ¶m : getParameters()) { + newParameters.push_back(param.getWithInterfaceType( + param.getInterfaceType()->getCanonicalType(derivativeFnGenSig))); + } + // TODO(TF-1124): Upstream reabstraction thunk derivative typing rules. + // Blocked by TF-1125: `SILFunctionType::getWithDifferentiability`. + SmallVector newResults; + newResults.reserve(getNumResults() + 1); + for (auto &result : getResults()) { + newResults.push_back(result.getWithInterfaceType( + result.getInterfaceType()->getCanonicalType(derivativeFnGenSig))); + } + newResults.push_back({closureType->getCanonicalType(derivativeFnGenSig), + ResultConvention::Owned}); + // Derivative function type has a generic signature only if the original + // function type does, and if `derivativeFnGenSig` does not have all concrete + // generic parameters. + CanGenericSignature canGenSig; + if (getSubstGenericSignature() && derivativeFnGenSig && + !derivativeFnGenSig->areAllParamsConcrete()) + canGenSig = derivativeFnGenSig; + // If original function is `@convention(c)`, the derivative function should + // have `@convention(thin)`. IRGen does not support `@convention(c)` functions + // with multiple results. + auto extInfo = getExtInfo(); + if (getRepresentation() == SILFunctionTypeRepresentation::CFunctionPointer) + extInfo = extInfo.withRepresentation(SILFunctionTypeRepresentation::Thin); + return SILFunctionType::get(canGenSig, extInfo, getCoroutineKind(), + getCalleeConvention(), newParameters, getYields(), + newResults, getOptionalErrorResult(), + getSubstitutions(), isGenericSignatureImplied(), + ctx, getWitnessMethodConformanceOrInvalid()); +} + static CanType getKnownType(Optional &cacheSlot, ASTContext &C, StringRef moduleName, StringRef typeName) { if (!cacheSlot) { @@ -754,8 +945,8 @@ class DestructureInputs { auto eltPattern = origType.getFunctionParamType(i); auto flags = params[i].getParameterFlags(); - visit(flags.getValueOwnership(), /*forSelf=*/false, - eltPattern, ty, silRepresentation); + visit(flags.getValueOwnership(), /*forSelf=*/false, eltPattern, ty, + silRepresentation, flags.isNoDerivative()); } // Process the self parameter. Note that we implicitly drop self @@ -776,7 +967,8 @@ class DestructureInputs { void visit(ValueOwnership ownership, bool forSelf, AbstractionPattern origType, CanType substType, - SILFunctionTypeRepresentation rep) { + SILFunctionTypeRepresentation rep, + bool isNonDifferentiable = false) { assert(!isa(substType)); // Tuples get handled specially, in some cases: @@ -829,9 +1021,12 @@ class DestructureInputs { substTLConv); assert(!isIndirectFormalParameter(convention)); } - - Inputs.push_back(SILParameterInfo( - substTL.getLoweredType().getASTType(), convention)); + + SILParameterInfo param(substTL.getLoweredType().getASTType(), convention); + if (isNonDifferentiable) + param = param.getWithDifferentiability( + SILParameterDifferentiability::NotDifferentiable); + Inputs.push_back(param); maybeAddForeignParameters(); } @@ -1269,7 +1464,8 @@ static CanSILFunctionType getSILFunctionType( auto silExtInfo = SILFunctionType::ExtInfo() .withRepresentation(extInfo.getSILRepresentation()) .withIsPseudogeneric(pseudogeneric) - .withNoEscape(extInfo.isNoEscape()); + .withNoEscape(extInfo.isNoEscape()) + .withDifferentiabilityKind(extInfo.getDifferentiabilityKind()); // Build the substituted generic signature we extracted. bool impliedSignature = false; @@ -2734,7 +2930,7 @@ class SILTypeSubstituter : SILParameterInfo substInterface(SILParameterInfo orig) { return SILParameterInfo(visit(orig.getInterfaceType()), - orig.getConvention()); + orig.getConvention(), orig.getDifferentiability()); } /// Tuples need to have their component types substituted by these diff --git a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp index 9a7c9ff814832..dbfa9931c9cb1 100644 --- a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp @@ -609,7 +609,7 @@ void EscapeAnalysis::ConnectionGraph::mergeAllScheduledNodes() { // To pointsTo-> NodeB (but still has a pointsTo edge to NodeB) while (!ToMerge.empty()) { if (EnableInternalVerify) - verify(/*allowMerge=*/true); + verifyStructure(true /*allowMerge*/); CGNode *From = ToMerge.pop_back_val(); CGNode *To = From->getMergeTarget(); @@ -745,7 +745,6 @@ void EscapeAnalysis::ConnectionGraph::mergeAllScheduledNodes() { From->isMerged = true; if (From->mappedValue) { - // If possible, transfer 'From's mappedValue to 'To' for clarity. Any // values previously mapped to 'From' but not transferred to 'To's // mappedValue must remain mapped to 'From'. Lookups on those values will // find 'To' via the mergeTarget. Dropping a value's mapping is illegal @@ -762,7 +761,7 @@ void EscapeAnalysis::ConnectionGraph::mergeAllScheduledNodes() { From->pointsTo = nullptr; } if (EnableInternalVerify) - verify(/*allowMerge=*/true); + verifyStructure(true /*allowMerge*/); } // As a result of a merge, update the pointsTo field of initialNode and @@ -1574,21 +1573,40 @@ bool CGNode::matchPointToOfDefers(bool allowMerge) const { return true; } -void EscapeAnalysis::ConnectionGraph::verify(bool allowMerge) const { +void EscapeAnalysis::ConnectionGraph::verify() const { #ifndef NDEBUG - verifyStructure(allowMerge); + // Invalidating EscapeAnalysis clears the connection graph. + if (isEmpty()) + return; - // Check graph invariants - for (CGNode *Nd : Nodes) { - // ConnectionGraph invariant #4: For any node N, all paths starting at N - // which consist of only defer-edges and a single trailing points-to edge - // must lead to the same - assert(Nd->matchPointToOfDefers(allowMerge)); - if (Nd->mappedValue && !(allowMerge && Nd->isMerged)) { - assert(Nd == Values2Nodes.lookup(Nd->mappedValue)); - assert(EA->isPointer(Nd->mappedValue)); - // Nodes must always be mapped from the pointer root value. - assert(Nd->mappedValue == EA->getPointerRoot(Nd->mappedValue)); + verifyStructure(); + + // Verify that all pointer nodes are still mapped, otherwise the process of + // merging nodes may have lost information. + for (SILBasicBlock &BB : *F) { + for (auto &I : BB) { + if (isNonWritableMemoryAddress(&I)) + continue; + + if (auto ai = dyn_cast(&I)) { + if (EA->canOptimizeArrayUninitializedCall(ai, this).isValid()) + continue; + } + for (auto result : I.getResults()) { + if (EA->getPointerBase(result)) + continue; + + if (!EA->isPointer(result)) + continue; + + if (!Values2Nodes.lookup(result)) { + llvm::dbgs() << "No CG mapping for "; + result->dumpInContext(); + llvm::dbgs() << " in:\n"; + F->dump(); + llvm_unreachable("Missing escape connection graph mapping"); + } + } } } #endif @@ -1597,6 +1615,7 @@ void EscapeAnalysis::ConnectionGraph::verify(bool allowMerge) const { void EscapeAnalysis::ConnectionGraph::verifyStructure(bool allowMerge) const { #ifndef NDEBUG for (CGNode *Nd : Nodes) { + // Verify the graph structure... if (Nd->isMerged) { assert(Nd->mergeTo); assert(!Nd->pointsTo); @@ -1625,6 +1644,19 @@ void EscapeAnalysis::ConnectionGraph::verifyStructure(bool allowMerge) const { } if (Nd->isInterior()) assert(Nd->pointsTo && "Interior content node requires a pointsTo node"); + + // ConnectionGraph invariant #4: For any node N, all paths starting at N + // which consist of only defer-edges and a single trailing points-to edge + // must lead to the same + assert(Nd->matchPointToOfDefers(allowMerge)); + + // Verify the node to value mapping... + if (Nd->mappedValue && !(allowMerge && Nd->isMerged)) { + assert(Nd == Values2Nodes.lookup(Nd->mappedValue)); + assert(EA->isPointer(Nd->mappedValue)); + // Nodes must always be mapped from the pointer root value. + assert(Nd->mappedValue == EA->getPointerRoot(Nd->mappedValue)); + } } #endif } @@ -1780,8 +1812,8 @@ bool EscapeAnalysis::buildConnectionGraphForDestructor( } EscapeAnalysis::ArrayUninitCall -EscapeAnalysis::canOptimizeArrayUninitializedCall(ApplyInst *ai, - ConnectionGraph *conGraph) { +EscapeAnalysis::canOptimizeArrayUninitializedCall( + ApplyInst *ai, const ConnectionGraph *conGraph) { ArrayUninitCall call; // This must be an exact match so we don't accidentally optimize // "array.uninitialized_intrinsic". @@ -2020,12 +2052,9 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I, ConGraph->getNode(cast(I)); return; -#define UNCHECKED_REF_STORAGE(Name, ...) \ - case SILInstructionKind::StrongCopy##Name##ValueInst: #define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ case SILInstructionKind::Name##RetainInst: \ - case SILInstructionKind::StrongRetain##Name##Inst: \ - case SILInstructionKind::StrongCopy##Name##ValueInst: + case SILInstructionKind::StrongRetain##Name##Inst: #include "swift/AST/ReferenceStorage.def" case SILInstructionKind::DeallocStackInst: case SILInstructionKind::StrongRetainInst: @@ -2043,8 +2072,11 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I, case SILInstructionKind::SetDeallocatingInst: case SILInstructionKind::FixLifetimeInst: case SILInstructionKind::ClassifyBridgeObjectInst: - case SILInstructionKind::ValueToBridgeObjectInst: - // These instructions don't have any effect on escaping. + // Early bailout: These instructions never produce a pointer value and + // have no escaping effect on their operands. + assert(!llvm::any_of(I->getResults(), [this](SILValue result) { + return isPointer(result); + })); return; #define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ @@ -2425,7 +2457,7 @@ void EscapeAnalysis::recompute(FunctionInfo *Initial) { if (BottomUpOrder.wasRecomputedWithCurrentUpdateID(FInfo)) { FInfo->Graph.computeUsePoints(); FInfo->Graph.verify(); - FInfo->SummaryGraph.verify(); + FInfo->SummaryGraph.verifyStructure(); } } } @@ -2766,6 +2798,25 @@ void EscapeAnalysis::handleDeleteNotification(SILNode *node) { } } +void EscapeAnalysis::verify() const { +#ifndef NDEBUG + for (auto Iter : Function2Info) { + FunctionInfo *FInfo = Iter.second; + FInfo->Graph.verify(); + FInfo->SummaryGraph.verifyStructure(); + } +#endif +} + +void EscapeAnalysis::verify(SILFunction *F) const { +#ifndef NDEBUG + if (FunctionInfo *FInfo = Function2Info.lookup(F)) { + FInfo->Graph.verify(); + FInfo->SummaryGraph.verifyStructure(); + } +#endif +} + SILAnalysis *swift::createEscapeAnalysis(SILModule *M) { return new EscapeAnalysis(M); } diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index 382c28bfdc48e..5868d453a4653 100644 --- a/lib/SILOptimizer/PassManager/PassPipeline.cpp +++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp @@ -488,7 +488,9 @@ static void addClosureSpecializePassPipeline(SILPassPipelinePlan &P) { P.addStackPromotion(); // Speculate virtual call targets. - P.addSpeculativeDevirtualization(); + if (P.getOptions().EnableSpeculativeDevirtualization) { + P.addSpeculativeDevirtualization(); + } // There should be at least one SILCombine+SimplifyCFG between the // ClosureSpecializer, etc. and the last inliner. Cleaning up after these diff --git a/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp b/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp index 5c2fb108633a1..2ca01e247fd21 100644 --- a/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp +++ b/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp @@ -596,6 +596,7 @@ namespace { void run() override { auto &CurFn = *getFunction(); + // Don't perform speculative devirtualization at -Os. if (CurFn.optimizeForSize()) return; diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index 963a53fadf51c..1511965adda5b 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -324,27 +324,11 @@ class BuilderClosureVisitor CONTROL_FLOW_STMT(Yield) CONTROL_FLOW_STMT(Defer) - /// Whether we can handle all of the conditions for this statement. - static bool canHandleStmtConditions(StmtCondition condition) { - for (const auto &element : condition) { - switch (element.getKind()) { - case StmtConditionElement::CK_Boolean: - continue; - - case StmtConditionElement::CK_PatternBinding: - case StmtConditionElement::CK_Availability: - return false; - } - } - - return true; - } - static bool isBuildableIfChainRecursive(IfStmt *ifStmt, unsigned &numPayloads, bool &isOptional) { // Check whether we can handle the conditional. - if (!canHandleStmtConditions(ifStmt->getCond())) + if (!ConstraintSystem::canGenerateConstraints(ifStmt->getCond())) return false; // The 'then' clause contributes a payload. @@ -470,38 +454,12 @@ class BuilderClosureVisitor payloadIndex + 1, numPayloads, isOptional); } - // Condition must convert to Bool. - // FIXME: This should be folded into constraint generation for conditions. - auto boolDecl = ctx.getBoolDecl(); - if (!boolDecl) { + // Generate constraints for the conditions. + if (cs->generateConstraints(ifStmt->getCond(), dc)) { hadError = true; return nullptr; } - // Generate constraints for the conditions. - for (const auto &condElement : ifStmt->getCond()) { - switch (condElement.getKind()) { - case StmtConditionElement::CK_Boolean: { - Expr *condExpr = condElement.getBoolean(); - condExpr = cs->generateConstraints(condExpr, dc); - if (!condExpr) { - hadError = true; - return nullptr; - } - - cs->addConstraint(ConstraintKind::Conversion, - cs->getType(condExpr), - boolDecl->getDeclaredType(), - cs->getConstraintLocator(condExpr)); - continue; - } - - case StmtConditionElement::CK_PatternBinding: - case StmtConditionElement::CK_Availability: - llvm_unreachable("unhandled statement condition"); - } - } - // The operand should have optional type if we had optional results, // so we just need to call `buildIf` now, since we're at the top level. if (isOptional && isTopLevel) { @@ -873,6 +831,9 @@ class BuilderClosureRewriter auto condition = ifStmt->getCond(); for (auto &condElement : condition) { switch (condElement.getKind()) { + case StmtConditionElement::CK_Availability: + continue; + case StmtConditionElement::CK_Boolean: { auto condExpr = condElement.getBoolean(); auto finalCondExpr = rewriteExpr(condExpr); @@ -888,7 +849,6 @@ class BuilderClosureRewriter } case StmtConditionElement::CK_PatternBinding: - case StmtConditionElement::CK_Availability: llvm_unreachable("unhandled statement condition"); } } diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index d66a82630c88c..6860d71f77ef7 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -221,7 +221,6 @@ class FailureDiagnosis :public ASTVisitor{ validateContextualType(Type contextualType, ContextualTypePurpose CTP); bool visitExpr(Expr *E); - bool visitIdentityExpr(IdentityExpr *E); bool visitTryExpr(TryExpr *E); bool visitApplyExpr(ApplyExpr *AE); @@ -1447,29 +1446,6 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { auto lhsType = CS.getType(lhsExpr)->getRValueType(); auto rhsType = CS.getType(rhsExpr)->getRValueType(); - // TODO(diagnostics): There are still cases not yet handled by new - // diagnostics framework e.g. - // - // var tuple = (1, 2, 3) - // switch tuple { - // case (let (_, _, _)) + 1: break - // } - if (callExpr->isImplicit() && overloadName == "~=") { - auto flags = ParameterTypeFlags(); - if (calleeInfo.candidates.size() == 1) - if (auto fnType = calleeInfo.candidates[0].getFunctionType()) - flags = fnType->getParams()[0].getParameterFlags(); - - auto *locator = CS.getConstraintLocator( - callExpr, - {ConstraintLocator::ApplyArgument, - LocatorPathElt::ApplyArgToParam(0, 0, flags)}, - /*summaryFlags=*/0); - - ArgumentMismatchFailure failure(CS, lhsType, rhsType, locator); - return failure.diagnosePatternMatchingMismatch(); - } - if (isContextualConversionFailure(argTuple)) return false; @@ -1517,41 +1493,6 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { AnyFunctionType::decomposeInput(CS.getType(argExpr), params); auto argString = AnyFunctionType::getParamListAsString(params); - // If we couldn't get the name of the callee, then it must be something of a - // more complex "value of function type". - if (overloadName.empty()) { - // If we couldn't infer the result type of the closure expr, then we have - // some sort of ambiguity, let the ambiguity diagnostic stuff handle this. - if (auto ffty = fnType->getAs()) - if (ffty->getResult()->hasTypeVariable()) { - diagnoseAmbiguity(fnExpr); - return true; - } - - // The most common unnamed value of closure type is a ClosureExpr, so - // special case it. - if (isa(fnExpr->getValueProvidingExpr())) { - if (fnType->hasTypeVariable()) - diagnose(argExpr->getStartLoc(), diag::cannot_invoke_closure, argString) - .highlight(fnExpr->getSourceRange()); - else - diagnose(argExpr->getStartLoc(), diag::cannot_invoke_closure_type, - fnType, argString) - .highlight(fnExpr->getSourceRange()); - - } else if (fnType->hasTypeVariable()) { - diagnose(argExpr->getStartLoc(), diag::cannot_call_function_value, - argString) - .highlight(fnExpr->getSourceRange()); - } else { - diagnose(argExpr->getStartLoc(), diag::cannot_call_value_of_function_type, - fnType, argString) - .highlight(fnExpr->getSourceRange()); - } - - return true; - } - if (auto MTT = fnType->getAs()) { if (MTT->getInstanceType()->isExistentialType()) { diagnose(fnExpr->getLoc(), diag::construct_protocol_value, fnType); @@ -1582,21 +1523,6 @@ visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E) { return false; } -/// An IdentityExpr doesn't change its argument, but it *can* propagate its -/// contextual type information down. -bool FailureDiagnosis::visitIdentityExpr(IdentityExpr *E) { - auto contextualType = CS.getContextualType(E); - - // If we have a paren expr and our contextual type is a ParenType, remove the - // paren expr sugar. - if (contextualType) - contextualType = contextualType->getWithoutParens(); - if (!typeCheckChildIndependently(E->getSubExpr(), contextualType, - CS.getContextualTypePurpose(E))) - return true; - return false; -} - /// A TryExpr doesn't change it's argument, nor does it change the contextual /// type. bool FailureDiagnosis::visitTryExpr(TryExpr *E) { @@ -1756,22 +1682,6 @@ void FailureDiagnosis::diagnoseAmbiguity(Expr *E) { if (auto *assignment = dyn_cast(E)) { if (isa(assignment->getDest())) { auto *srcExpr = assignment->getSrc(); - - bool diagnosedInvalidUseOfDiscardExpr = false; - srcExpr->forEachChildExpr([&](Expr *expr) -> Expr * { - if (auto *DAE = dyn_cast(expr)) { - diagnose(DAE->getLoc(), diag::discard_expr_outside_of_assignment) - .highlight(srcExpr->getSourceRange()); - diagnosedInvalidUseOfDiscardExpr = true; - return nullptr; - } - - return expr; - }); - - if (diagnosedInvalidUseOfDiscardExpr) - return; - diagnoseAmbiguity(srcExpr); return; } @@ -1785,15 +1695,6 @@ void FailureDiagnosis::diagnoseAmbiguity(Expr *E) { return; } - // A DiscardAssignmentExpr (spelled "_") needs contextual type information to - // infer its type. If we see one at top level, diagnose that it must be part - // of an assignment so we don't get a generic "expression is ambiguous" error. - if (isa(E)) { - diagnose(E->getLoc(), diag::discard_expr_outside_of_assignment) - .highlight(E->getSourceRange()); - return; - } - // Diagnose ".foo" expressions that lack context specifically. if (auto UME = dyn_cast(E->getSemanticsProvidingExpr())) { @@ -1805,22 +1706,6 @@ void FailureDiagnosis::diagnoseAmbiguity(Expr *E) { } } - // Diagnose empty collection literals that lack context specifically. - if (auto CE = dyn_cast(E->getSemanticsProvidingExpr())) { - if (CE->getNumElements() == 0) { - diagnose(E->getLoc(), diag::unresolved_collection_literal) - .highlight(E->getSourceRange()); - return; - } - } - - // Diagnose 'nil' without a contextual type. - if (isa(E->getSemanticsProvidingExpr())) { - diagnose(E->getLoc(), diag::unresolved_nil_literal) - .highlight(E->getSourceRange()); - return; - } - // Attempt to re-type-check the entire expression, allowing ambiguity, but // ignoring a contextual type. if (expr == E) { diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index a0a68fe45b717..df3bd12ac70d2 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -337,8 +337,9 @@ bool RequirementFailure::diagnoseAsError() { return true; } - if (genericCtx != reqDC && (genericCtx->isChildContextOf(reqDC) || - isStaticOrInstanceMember(AffectedDecl))) { + if (reqDC->isTypeContext() && genericCtx != reqDC && + (genericCtx->isChildContextOf(reqDC) || + isStaticOrInstanceMember(AffectedDecl))) { auto *NTD = reqDC->getSelfNominalTypeDecl(); emitDiagnostic(anchor->getLoc(), getDiagnosticInRereference(), AffectedDecl->getDescriptiveKind(), diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 78402bbf3e69d..071767fe08891 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2827,7 +2827,8 @@ namespace { Type visitDiscardAssignmentExpr(DiscardAssignmentExpr *expr) { auto locator = CS.getConstraintLocator(expr); - auto typeVar = CS.createTypeVariable(locator, TVO_CanBindToNoEscape); + auto typeVar = CS.createTypeVariable(locator, TVO_CanBindToNoEscape | + TVO_CanBindToHole); return LValueType::get(typeVar); } @@ -3798,6 +3799,61 @@ Type ConstraintSystem::generateConstraints(Pattern *pattern, return cg.getTypeForPattern(pattern, locator); } +bool ConstraintSystem::canGenerateConstraints(StmtCondition condition) { + for (const auto &element : condition) { + switch (element.getKind()) { + case StmtConditionElement::CK_Availability: + case StmtConditionElement::CK_Boolean: + continue; + + case StmtConditionElement::CK_PatternBinding: + return false; + } + } + + return true; +} + +bool ConstraintSystem::generateConstraints(StmtCondition condition, + DeclContext *dc) { + // FIXME: This should be folded into constraint generation for conditions. + auto boolDecl = getASTContext().getBoolDecl(); + if (!boolDecl) { + return true; + } + + Type boolTy = boolDecl->getDeclaredType(); + for (const auto &condElement : condition) { + switch (condElement.getKind()) { + case StmtConditionElement::CK_Availability: + // Nothing to do here. + continue; + + case StmtConditionElement::CK_Boolean: { + Expr *condExpr = condElement.getBoolean(); + setContextualType(condExpr, TypeLoc::withoutLoc(boolTy), CTP_Condition); + + condExpr = generateConstraints(condExpr, dc); + if (!condExpr) { + return true; + } + + addConstraint(ConstraintKind::Conversion, + getType(condExpr), + boolTy, + getConstraintLocator(condExpr, + LocatorPathElt::ContextualType())); + continue; + } + + case StmtConditionElement::CK_PatternBinding: + llvm_unreachable("unhandled statement condition"); + } + } + + return false; +} + void ConstraintSystem::optimizeConstraints(Expr *e) { if (getASTContext().TypeCheckerOpts.DisableConstraintSolverPerformanceHacks) return; diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index 263fe0217946f..94b00f9e3a435 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -168,6 +168,10 @@ Solution ConstraintSystem::finalize() { solution.addedNodeTypes.insert(nodeType); } + // Remember contextual types. + solution.contextualTypes.assign( + contextualTypes.begin(), contextualTypes.end()); + for (auto &e : CheckedConformances) solution.Conformances.push_back({e.first, e.second}); @@ -232,6 +236,14 @@ void ConstraintSystem::applySolution(const Solution &solution) { setType(nodeType.first, nodeType.second); } + // Add the contextual types. + for (const auto &contextualType : solution.contextualTypes) { + if (!getContextualTypeInfo(contextualType.first)) { + setContextualType(contextualType.first, contextualType.second.typeLoc, + contextualType.second.purpose); + } + } + // Register the conformances checked along the way to arrive to solution. for (auto &conformance : solution.Conformances) CheckedConformances.push_back(conformance); diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 1b2ed2328cc6e..1cd0c4724e7a4 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -787,6 +787,15 @@ using OpenedType = std::pair; using OpenedTypeMap = llvm::DenseMap; +/// Describes contextual type information about a particular expression +/// within a constraint system. +struct ContextualTypeInfo { + TypeLoc typeLoc; + ContextualTypePurpose purpose; + + Type getType() const { return typeLoc.getType(); } +}; + /// A complete solution to a constraint system. /// /// A solution to a constraint system consists of type variable bindings to @@ -849,6 +858,9 @@ class Solution { /// The node -> type mappings introduced by this solution. llvm::MapVector addedNodeTypes; + /// Contextual types introduced by this solution. + std::vector> contextualTypes; + std::vector> Conformances; @@ -1300,13 +1312,6 @@ class ConstraintSystem { llvm::DenseMap, TypeBase *> KeyPathComponentTypes; - struct ContextualTypeInfo { - TypeLoc typeLoc; - ContextualTypePurpose purpose; - - Type getType() const { return typeLoc.getType(); } - }; - /// Contextual type information for expressions that are part of this /// constraint system. llvm::MapVector contextualTypes; @@ -2174,35 +2179,36 @@ class ConstraintSystem { return E; } - void setContextualType(Expr *expr, TypeLoc T, ContextualTypePurpose purpose) { + void setContextualType( + const Expr *expr, TypeLoc T, ContextualTypePurpose purpose) { assert(expr != nullptr && "Expected non-null expression!"); assert(contextualTypes.count(expr) == 0 && "Already set this contextual type"); contextualTypes[expr] = { T, purpose }; } - Optional getContextualTypeInfo(Expr *expr) const { + Optional getContextualTypeInfo(const Expr *expr) const { auto known = contextualTypes.find(expr); if (known == contextualTypes.end()) return None; return known->second; } - Type getContextualType(Expr *expr) const { + Type getContextualType(const Expr *expr) const { auto result = getContextualTypeInfo(expr); if (result) return result->typeLoc.getType(); return Type(); } - TypeLoc getContextualTypeLoc(Expr *expr) const { + TypeLoc getContextualTypeLoc(const Expr *expr) const { auto result = getContextualTypeInfo(expr); if (result) return result->typeLoc; return TypeLoc(); } - ContextualTypePurpose getContextualTypePurpose(Expr *expr) const { + ContextualTypePurpose getContextualTypePurpose(const Expr *expr) const { auto result = getContextualTypeInfo(expr); if (result) return result->purpose; @@ -3080,6 +3086,16 @@ class ConstraintSystem { /// \returns a possibly-sanitized initializer, or null if an error occurred. Type generateConstraints(Pattern *P, ConstraintLocatorBuilder locator); + /// Determines whether we can generate constraints for this statement + /// condition. + static bool canGenerateConstraints(StmtCondition condition); + + /// Generate constraints for a statement condition. + /// + /// \returns true if there was an error in constraint generation, false + /// if generation succeeded. + bool generateConstraints(StmtCondition condition, DeclContext *dc); + /// Generate constraints for a given set of overload choices. /// /// \param constraints The container of generated constraint choices. diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 3cc68bf07d601..ad3ab2f99e947 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -2948,6 +2948,8 @@ SILParameterInfo TypeResolver::resolveSILParameter( auto convention = DefaultParameterConvention; Type type; bool hadError = false; + auto differentiability = + SILParameterDifferentiability::DifferentiableOrNotApplicable; if (auto attrRepr = dyn_cast(repr)) { auto attrs = attrRepr->getAttrs(); @@ -2973,6 +2975,10 @@ SILParameterInfo TypeResolver::resolveSILParameter( checkFor(TypeAttrKind::TAK_owned, ParameterConvention::Direct_Owned); checkFor(TypeAttrKind::TAK_guaranteed, ParameterConvention::Direct_Guaranteed); + if (attrs.has(TAK_noDerivative)) { + attrs.clearAttribute(TAK_noDerivative); + differentiability = SILParameterDifferentiability::NotDifferentiable; + } type = resolveAttributedType(attrs, attrRepr->getTypeRepr(), options); } else { @@ -2989,7 +2995,8 @@ SILParameterInfo TypeResolver::resolveSILParameter( } if (hadError) type = ErrorType::get(Context); - return SILParameterInfo(type->getCanonicalType(), convention); + return SILParameterInfo(type->getCanonicalType(), convention, + differentiability); } bool TypeResolver::resolveSingleSILResult(TypeRepr *repr, diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index fc0abb60f83b7..64ab317c826ab 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -4503,6 +4503,21 @@ Optional getActualParameterConvention(uint8_t raw) { return None; } +/// Translate from the serialization SILParameterDifferentiability enumerators, +/// which are guaranteed to be stable, to the AST ones. +static Optional +getActualSILParameterDifferentiability(uint8_t raw) { + switch (serialization::SILParameterDifferentiability(raw)) { +#define CASE(ID) \ + case serialization::SILParameterDifferentiability::ID: \ + return swift::SILParameterDifferentiability::ID; + CASE(DifferentiableOrNotApplicable) + CASE(NotDifferentiable) +#undef CASE + } + return None; +} + /// Translate from the serialization ResultConvention enumerators, /// which are guaranteed to be stable, to the AST ones. static @@ -5144,15 +5159,26 @@ class TypeDeserializer { if (!calleeConvention.hasValue()) MF.fatal(); - auto processParameter = [&](TypeID typeID, uint64_t rawConvention) - -> llvm::Expected { + auto processParameter = + [&](TypeID typeID, uint64_t rawConvention, + uint64_t ramDifferentiability) -> llvm::Expected { auto convention = getActualParameterConvention(rawConvention); if (!convention) MF.fatal(); auto type = MF.getTypeChecked(typeID); if (!type) return type.takeError(); - return SILParameterInfo(type.get()->getCanonicalType(), *convention); + auto differentiability = + swift::SILParameterDifferentiability::DifferentiableOrNotApplicable; + if (diffKind != DifferentiabilityKind::NonDifferentiable) { + auto differentiabilityOpt = + getActualSILParameterDifferentiability(ramDifferentiability); + if (!differentiabilityOpt) + MF.fatal(); + differentiability = *differentiabilityOpt; + } + return SILParameterInfo(type.get()->getCanonicalType(), *convention, + differentiability); }; auto processYield = [&](TypeID typeID, uint64_t rawConvention) @@ -5191,7 +5217,10 @@ class TypeDeserializer { for (unsigned i = 0; i != numParams; ++i) { auto typeID = variableData[nextVariableDataIndex++]; auto rawConvention = variableData[nextVariableDataIndex++]; - auto param = processParameter(typeID, rawConvention); + uint64_t differentiability = 0; + if (diffKind != DifferentiabilityKind::NonDifferentiable) + differentiability = variableData[nextVariableDataIndex++]; + auto param = processParameter(typeID, rawConvention, differentiability); if (!param) return param.takeError(); allParams.push_back(param.get()); diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 1306adfb3341b..265ea709a7c89 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 533; // removed @_implicitly_synthesizes_nested_requirement +const uint16_t SWIFTMODULE_VERSION_MINOR = 534; // add SIL parameter differentiability /// A standard hash seed used for all string hashes in a serialized module. /// @@ -347,6 +347,13 @@ enum class ParameterConvention : uint8_t { }; using ParameterConventionField = BCFixed<4>; +// These IDs must \em not be renumbered or reordered without incrementing +// the module version. +enum class SILParameterDifferentiability : uint8_t { + DifferentiableOrNotApplicable, + NotDifferentiable, +}; + // These IDs must \em not be renumbered or reordered without incrementing // the module version. enum class ResultConvention : uint8_t { diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index f49d466d52bfb..ce49f72c4bccc 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3766,6 +3766,17 @@ static uint8_t getRawStableParameterConvention(swift::ParameterConvention pc) { llvm_unreachable("bad parameter convention kind"); } +/// Translate from AST SILParameterDifferentiability enum to the Serialization +/// enum values, which are guaranteed to be stable. +static uint8_t +getRawSILParameterDifferentiability(swift::SILParameterDifferentiability pd) { + switch (pd) { + SIMPLE_CASE(SILParameterDifferentiability, DifferentiableOrNotApplicable) + SIMPLE_CASE(SILParameterDifferentiability, NotDifferentiable) + } + llvm_unreachable("bad parameter differentiability kind"); +} + /// Translate from the AST ResultConvention enum to the /// Serialization enum values, which are guaranteed to be stable. static uint8_t getRawStableResultConvention(swift::ResultConvention rc) { @@ -4075,6 +4086,9 @@ class Serializer::TypeSerializer : public TypeVisitor { variableData.push_back(S.addTypeRef(param.getInterfaceType())); unsigned conv = getRawStableParameterConvention(param.getConvention()); variableData.push_back(TypeID(conv)); + if (fnTy->isDifferentiable()) + variableData.push_back(TypeID( + getRawSILParameterDifferentiability(param.getDifferentiability()))); } for (auto yield : fnTy->getYields()) { variableData.push_back(S.addTypeRef(yield.getInterfaceType())); diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index 0f7aa8edc7332..52fce52ee4938 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -24,11 +24,6 @@ function(add_swift_target_executable name) # All Swift executables depend on the swiftSwiftOnoneSupport library. list(APPEND SWIFTEXE_TARGET_DEPENDS swiftSwiftOnoneSupport) - if(NOT "${SWIFT_BUILD_STDLIB}") - list(REMOVE_ITEM SWIFTEXE_TARGET_LINK_LIBRARIES - swiftCore) - endif() - foreach(sdk ${SWIFT_SDKS}) foreach(arch ${SWIFT_SDK_${sdk}_ARCHITECTURES}) set(VARIANT_SUFFIX "-${SWIFT_SDK_${sdk}_LIB_SUBDIR}-${arch}") diff --git a/stdlib/public/Reflection/CMakeLists.txt b/stdlib/public/Reflection/CMakeLists.txt index 427c2c721584f..bae4f12e2d443 100644 --- a/stdlib/public/Reflection/CMakeLists.txt +++ b/stdlib/public/Reflection/CMakeLists.txt @@ -19,12 +19,9 @@ if (LLVM_ENABLE_ASSERTIONS) "${SWIFT_SOURCE_DIR}/lib/Demangling/NodeDumper.cpp") endif(LLVM_ENABLE_ASSERTIONS) -if(SWIFT_BUILD_STDLIB) - add_swift_target_library(swiftReflection STATIC - ${swiftReflection_SOURCES} - C_COMPILE_FLAGS ${SWIFT_RUNTIME_CXX_FLAGS} -DswiftCore_EXPORTS - LINK_FLAGS ${SWIFT_RUNTIME_LINK_FLAGS} - SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} - INSTALL_IN_COMPONENT dev) -endif() - +add_swift_target_library(swiftReflection STATIC + ${swiftReflection_SOURCES} + C_COMPILE_FLAGS ${SWIFT_RUNTIME_CXX_FLAGS} -DswiftCore_EXPORTS + LINK_FLAGS ${SWIFT_RUNTIME_LINK_FLAGS} + SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} + INSTALL_IN_COMPONENT dev) diff --git a/stdlib/public/core/DictionaryStorage.swift b/stdlib/public/core/DictionaryStorage.swift index 39ac76578f126..ac931fd2ed51c 100644 --- a/stdlib/public/core/DictionaryStorage.swift +++ b/stdlib/public/core/DictionaryStorage.swift @@ -196,6 +196,35 @@ extension __RawDictionaryStorage { return Builtin.bridgeFromRawPointer( Builtin.addressof(&_swiftEmptyDictionarySingleton)) } + + @_alwaysEmitIntoClient + @inline(__always) + internal final func uncheckedKey(at bucket: _HashTable.Bucket) -> Key { + defer { _fixLifetime(self) } + _internalInvariant(_hashTable.isOccupied(bucket)) + let keys = _rawKeys.assumingMemoryBound(to: Key.self) + return keys[bucket.offset] + } + + @_alwaysEmitIntoClient + @inline(never) + internal final func find(_ key: Key) -> (bucket: _HashTable.Bucket, found: Bool) { + return find(key, hashValue: key._rawHashValue(seed: _seed)) + } + + @_alwaysEmitIntoClient + @inline(never) + internal final func find(_ key: Key, hashValue: Int) -> (bucket: _HashTable.Bucket, found: Bool) { + let hashTable = _hashTable + var bucket = hashTable.idealBucket(forHashValue: hashValue) + while hashTable._isOccupied(bucket) { + if uncheckedKey(at: bucket) == key { + return (bucket, true) + } + bucket = hashTable.bucket(wrappedAfter: bucket) + } + return (bucket, false) + } } @usableFromInline diff --git a/stdlib/public/core/NativeDictionary.swift b/stdlib/public/core/NativeDictionary.swift index 4dcbd68ce642d..e387b966f4b09 100644 --- a/stdlib/public/core/NativeDictionary.swift +++ b/stdlib/public/core/NativeDictionary.swift @@ -161,7 +161,7 @@ extension _NativeDictionary { // Low-level lookup operations @inlinable @inline(__always) internal func find(_ key: Key) -> (bucket: Bucket, found: Bool) { - return find(key, hashValue: self.hashValue(for: key)) + return _storage.find(key) } /// Search for a given element, assuming it has the specified hash value. @@ -174,58 +174,54 @@ extension _NativeDictionary { // Low-level lookup operations _ key: Key, hashValue: Int ) -> (bucket: Bucket, found: Bool) { - let hashTable = self.hashTable - var bucket = hashTable.idealBucket(forHashValue: hashValue) - while hashTable._isOccupied(bucket) { - if uncheckedKey(at: bucket) == key { - return (bucket, true) - } - bucket = hashTable.bucket(wrappedAfter: bucket) - } - return (bucket, false) + return _storage.find(key, hashValue: hashValue) } } extension _NativeDictionary { // ensureUnique - @inlinable - internal mutating func resize(capacity: Int) { + @_alwaysEmitIntoClient + @inline(never) + internal mutating func _copyOrMoveAndResize( + capacity: Int, + moveElements: Bool + ) { let capacity = Swift.max(capacity, self.capacity) let newStorage = _DictionaryStorage.resize( original: _storage, capacity: capacity, - move: true) + move: moveElements) let result = _NativeDictionary(newStorage) if count > 0 { for bucket in hashTable { - let key = (_keys + bucket.offset).move() - let value = (_values + bucket.offset).move() + let key: Key + let value: Value + if moveElements { + key = (_keys + bucket.offset).move() + value = (_values + bucket.offset).move() + } else { + key = self.uncheckedKey(at: bucket) + value = self.uncheckedValue(at: bucket) + } result._unsafeInsertNew(key: key, value: value) } - // Clear out old storage, ensuring that its deinit won't overrelease the - // elements we've just moved out. - _storage._hashTable.clear() - _storage._count = 0 + if moveElements { + // Clear out old storage, ensuring that its deinit won't overrelease the + // elements we've just moved out. + _storage._hashTable.clear() + _storage._count = 0 + } } _storage = result._storage } @inlinable - @_semantics("optimize.sil.specialize.generic.size.never") + internal mutating func resize(capacity: Int) { + _copyOrMoveAndResize(capacity: capacity, moveElements: true) + } + + @inlinable internal mutating func copyAndResize(capacity: Int) { - let capacity = Swift.max(capacity, self.capacity) - let newStorage = _DictionaryStorage.resize( - original: _storage, - capacity: capacity, - move: false) - let result = _NativeDictionary(newStorage) - if count > 0 { - for bucket in hashTable { - result._unsafeInsertNew( - key: self.uncheckedKey(at: bucket), - value: self.uncheckedValue(at: bucket)) - } - } - _storage = result._storage + _copyOrMoveAndResize(capacity: capacity, moveElements: false) } @inlinable diff --git a/test/AutoDiff/SIL/Serialization/differentiation.swift b/test/AutoDiff/SIL/Serialization/differentiation.swift index e72bdd001b680..828b08ccb52b7 100644 --- a/test/AutoDiff/SIL/Serialization/differentiation.swift +++ b/test/AutoDiff/SIL/Serialization/differentiation.swift @@ -26,3 +26,23 @@ bb0(%0 : $@differentiable(linear) (Float) -> Float): // CHECK: bb0([[ARG:%.*]] : $@differentiable(linear) (Float) -> Float): // CHECK: return [[ARG]] : $@differentiable(linear) (Float) -> Float // CHECK: } + +sil @c : $@convention(thin) (@differentiable (Float, @noDerivative Float) -> Float) -> @differentiable (Float, @noDerivative Float) -> Float { +bb0(%0 : $@differentiable (Float, @noDerivative Float) -> Float): + return %0 : $@differentiable (Float, @noDerivative Float) -> Float +} + +// CHECK-LABEL: sil @c : $@convention(thin) (@differentiable (Float, @noDerivative Float) -> Float) -> @differentiable (Float, @noDerivative Float) -> Float { +// CHECK: bb0(%0 : $@differentiable (Float, @noDerivative Float) -> Float): +// CHECK: return %0 : $@differentiable (Float, @noDerivative Float) -> Float +// CHECK: } + +sil @d : $@convention(thin) (@differentiable(linear) (Float, @noDerivative Float) -> Float) -> @differentiable(linear) (Float, @noDerivative Float) -> Float { +bb0(%0 : $@differentiable(linear) (Float, @noDerivative Float) -> Float): + return %0 : $@differentiable(linear) (Float, @noDerivative Float) -> Float +} + +// CHECK-LABEL: sil @d : $@convention(thin) (@differentiable(linear) (Float, @noDerivative Float) -> Float) -> @differentiable(linear) (Float, @noDerivative Float) -> Float { +// CHECK: bb0(%0 : $@differentiable(linear) (Float, @noDerivative Float) -> Float): +// CHECK: return %0 : $@differentiable(linear) (Float, @noDerivative Float) -> Float +// CHECK: } diff --git a/test/AutoDiff/SILGen/differentiable_function.swift b/test/AutoDiff/SILGen/differentiable_function.swift new file mode 100644 index 0000000000000..bd1282fa59199 --- /dev/null +++ b/test/AutoDiff/SILGen/differentiable_function.swift @@ -0,0 +1,56 @@ +// RUN: %target-swift-frontend -emit-silgen -enable-experimental-differentiable-programming %s | %FileCheck %s +// REQUIRES: differentiable_programming + +// Test SILGen for `@differentiable` function typed values. + +import _Differentiation + +@_silgen_name("differentiable") +func differentiable(_ fn: @escaping @differentiable (Float) -> Float) + -> @differentiable (Float) -> Float { + return fn +} + +@_silgen_name("linear") +func linear(_ fn: @escaping @differentiable(linear) (Float) -> Float) + -> @differentiable(linear) (Float) -> Float { + return fn +} + +@_silgen_name("differentiable_noDerivative") +func differentiable_noDerivative( + _ fn: @escaping @differentiable (Float, @noDerivative Float) -> Float +) -> @differentiable (Float, @noDerivative Float) -> Float { + return fn +} + +@_silgen_name("linear_noDerivative") +func linear_noDerivative( + _ fn: @escaping @differentiable(linear) (Float, @noDerivative Float) -> Float +) -> @differentiable(linear) (Float, @noDerivative Float) -> Float { + return fn +} + +// CHECK-LABEL: sil hidden [ossa] @differentiable : $@convention(thin) (@guaranteed @differentiable @callee_guaranteed (Float) -> Float) -> @owned @differentiable @callee_guaranteed (Float) -> Float { +// CHECK: bb0([[FN:%.*]] : @guaranteed $@differentiable @callee_guaranteed (Float) -> Float): +// CHECK: [[COPIED_FN:%.*]] = copy_value [[FN]] : $@differentiable @callee_guaranteed (Float) -> Float +// CHECK: return [[COPIED_FN]] : $@differentiable @callee_guaranteed (Float) -> Float +// CHECK: } + +// CHECK-LABEL: sil hidden [ossa] @linear : $@convention(thin) (@guaranteed @differentiable(linear) @callee_guaranteed (Float) -> Float) -> @owned @differentiable(linear) @callee_guaranteed (Float) -> Float { +// CHECK: bb0([[FN:%.*]] : @guaranteed $@differentiable(linear) @callee_guaranteed (Float) -> Float): +// CHECK: [[COPIED_FN:%.*]] = copy_value [[FN]] : $@differentiable(linear) @callee_guaranteed (Float) -> Float +// CHECK: return [[COPIED_FN]] : $@differentiable(linear) @callee_guaranteed (Float) -> Float +// CHECK: } + +// CHECK-LABEL: sil hidden [ossa] @differentiable_noDerivative : $@convention(thin) (@guaranteed @differentiable @callee_guaranteed (Float, @noDerivative Float) -> Float) -> @owned @differentiable @callee_guaranteed (Float, @noDerivative Float) -> Float { +// CHECK: bb0([[FN:%.*]] : @guaranteed $@differentiable @callee_guaranteed (Float, @noDerivative Float) -> Float): +// CHECK: [[COPIED_FN:%.*]] = copy_value [[FN]] : $@differentiable @callee_guaranteed (Float, @noDerivative Float) -> Float +// CHECK: return [[COPIED_FN]] : $@differentiable @callee_guaranteed (Float, @noDerivative Float) -> Float +// CHECK: } + +// CHECK-LABEL: sil hidden [ossa] @linear_noDerivative : $@convention(thin) (@guaranteed @differentiable(linear) @callee_guaranteed (Float, @noDerivative Float) -> Float) -> @owned @differentiable(linear) @callee_guaranteed (Float, @noDerivative Float) -> Float { +// CHECK: bb0([[FN:%.*]] : @guaranteed $@differentiable(linear) @callee_guaranteed (Float, @noDerivative Float) -> Float): +// CHECK: [[COPIED_FN:%.*]] = copy_value [[FN]] : $@differentiable(linear) @callee_guaranteed (Float, @noDerivative Float) -> Float +// CHECK: return [[COPIED_FN]] : $@differentiable(linear) @callee_guaranteed (Float, @noDerivative Float) -> Float +// CHECK: } diff --git a/test/ClangImporter/Inputs/SwiftPrivateAttr.txt b/test/ClangImporter/Inputs/SwiftPrivateAttr.txt index 97cb55de5cd60..ed38550938e26 100644 --- a/test/ClangImporter/Inputs/SwiftPrivateAttr.txt +++ b/test/ClangImporter/Inputs/SwiftPrivateAttr.txt @@ -1,4 +1,4 @@ -import Foundation +@_exported import Foundation protocol __PrivProto { } diff --git a/test/ClangImporter/Inputs/custom-modules/module.map b/test/ClangImporter/Inputs/custom-modules/module.map index a2241846ad55e..6e9e9113650cd 100644 --- a/test/ClangImporter/Inputs/custom-modules/module.map +++ b/test/ClangImporter/Inputs/custom-modules/module.map @@ -165,6 +165,7 @@ module SubclassExistentialsExtra { module SwiftPrivateAttr { header "SwiftPrivateAttr.h" + export * } module TestProtocols { header "Protocols.h" } diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index f441234e43f92..c603df2c04b76 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -1271,7 +1271,7 @@ func badTypes() { // rdar://34357545 func unresolvedTypeExistential() -> Bool { return (Int.self==_{}) - // expected-error@-1 {{expression type 'Bool' is ambiguous without more context}} + // expected-error@-1 {{'_' can only appear in a pattern or on the left side of an assignment}} } func rdar43525641(_ a: Int, _ b: Int = 0, c: Int = 0, _ d: Int) {} diff --git a/test/Constraints/function_builder_availability.swift b/test/Constraints/function_builder_availability.swift new file mode 100644 index 0000000000000..ac63adc4a7f7f --- /dev/null +++ b/test/Constraints/function_builder_availability.swift @@ -0,0 +1,74 @@ +// RUN: %target-typecheck-verify-swift -target x86_64-apple-macosx10.50 + +// REQUIRES: OS=macosx + +enum Either { + case first(T) + case second(U) +} + +@_functionBuilder +struct TupleBuilder { + static func buildBlock(_ t1: T1) -> (T1) { + return (t1) + } + + static func buildBlock(_ t1: T1, _ t2: T2) -> (T1, T2) { + return (t1, t2) + } + + static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3) + -> (T1, T2, T3) { + return (t1, t2, t3) + } + + static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4) + -> (T1, T2, T3, T4) { + return (t1, t2, t3, t4) + } + + static func buildBlock( + _ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4, _ t5: T5 + ) -> (T1, T2, T3, T4, T5) { + return (t1, t2, t3, t4, t5) + } + + static func buildDo(_ value: T) -> T { return value } + static func buildIf(_ value: T?) -> T? { return value } + + static func buildEither(first value: T) -> Either { + return .first(value) + } + static func buildEither(second value: U) -> Either { + return .second(value) + } +} + +func tuplify(_ cond: Bool, @TupleBuilder body: (Bool) -> T) { + print(body(cond)) +} + +@available(OSX, introduced: 10.9) +func globalFuncAvailableOn10_9() -> Int { return 9 } + +@available(OSX, introduced: 10.51) +func globalFuncAvailableOn10_51() -> Int { return 10 } + +@available(OSX, introduced: 10.52) +func globalFuncAvailableOn10_52() -> Int { return 11 } + +tuplify(true) { cond in + globalFuncAvailableOn10_9() + if #available(OSX 10.51, *) { + globalFuncAvailableOn10_51() + tuplify(false) { cond2 in + if cond, #available(OSX 10.52, *) { + cond2 + globalFuncAvailableOn10_52() + } else { + globalFuncAvailableOn10_52() // expected-error{{'globalFuncAvailableOn10_52()' is only available in macOS 10.52 or newer}} + // expected-note@-1{{add 'if #available' version check}} + } + } + } +} diff --git a/test/Constraints/function_builder_diags.swift b/test/Constraints/function_builder_diags.swift index 70e15160d4865..8769496a8bb7b 100644 --- a/test/Constraints/function_builder_diags.swift +++ b/test/Constraints/function_builder_diags.swift @@ -257,7 +257,7 @@ struct MyTuplifiedStruct { } } -// Check that we're performing syntactic use diagnostics/ +// Check that we're performing syntactic use diagnostics. func acceptMetatype(_: T.Type) -> Bool { true } func syntacticUses(_: T) { @@ -269,3 +269,18 @@ func syntacticUses(_: T) { } } } + +// Check custom diagnostics within "if" conditions. +struct HasProperty { + var property: Bool = false +} + +func checkConditions(cond: Bool) { + var x = HasProperty() + + tuplify(cond) { value in + if x.property = value { // expected-error{{use of '=' in a boolean context, did you mean '=='?}} + "matched it" + } + } +} diff --git a/test/IDE/Inputs/custom-modules/ImportAsMemberC.h b/test/IDE/Inputs/custom-modules/ImportAsMemberC.h index 089152904d268..ee6bd68fd64e2 100644 --- a/test/IDE/Inputs/custom-modules/ImportAsMemberC.h +++ b/test/IDE/Inputs/custom-modules/ImportAsMemberC.h @@ -1,3 +1,5 @@ +@import ObjectiveC; + typedef const void *CFTypeRef __attribute__((objc_bridge(id))); typedef const struct __attribute__((objc_bridge(id))) CCPowerSupply *CCPowerSupplyRef; diff --git a/test/IDE/Inputs/custom-modules/module.map b/test/IDE/Inputs/custom-modules/module.map index d87b1692cc467..222d9bc7337d1 100644 --- a/test/IDE/Inputs/custom-modules/module.map +++ b/test/IDE/Inputs/custom-modules/module.map @@ -35,6 +35,7 @@ module ImportAsMember { module C { requires objc header "ImportAsMemberC.h" + export * } module APINotes { diff --git a/test/IDE/import_as_member.swift b/test/IDE/import_as_member.swift index 7e5e81126c377..05e34cba2e111 100644 --- a/test/IDE/import_as_member.swift +++ b/test/IDE/import_as_member.swift @@ -106,6 +106,9 @@ // PRINT-APINOTES-4: @available(swift, obsoleted: 3, renamed: "Struct1.NewApiNoteType") // PRINT-APINOTES-4-NEXT: typealias IAMStruct1APINoteType = Struct1.NewApiNoteType +#if canImport(Foundation) +import Foundation +#endif import ImportAsMember.A import ImportAsMember.B import ImportAsMember.APINotes diff --git a/test/IRGen/Inputs/usr/include/module.map b/test/IRGen/Inputs/usr/include/module.map index e6ca8ec2e7d35..438caf2c8b194 100644 --- a/test/IRGen/Inputs/usr/include/module.map +++ b/test/IRGen/Inputs/usr/include/module.map @@ -1,32 +1,40 @@ module gizmo { header "Gizmo.h" + export * } module SRoA { header "SRoA.h" + export * } module ObjectiveC { header "BridgeTestObjectiveC.h" + export * } module CoreCooling { header "CoreCooling.h" + export * } module Foundation { header "BridgeTestFoundation.h" + export * } module CoreFoundation { header "BridgeTestCoreFoundation.h" + export * } module ObjCInterop { header "ObjCInterop.h" + export * } module error_domains { header "error_domains.h" + export * } diff --git a/test/Parse/matching_patterns.swift b/test/Parse/matching_patterns.swift index 39cadef2359ec..0448390a53a97 100644 --- a/test/Parse/matching_patterns.swift +++ b/test/Parse/matching_patterns.swift @@ -288,8 +288,7 @@ case (_, var e, 3) +++ (1, 2, 3): // expected-error@-2{{'var' binding pattern cannot appear in an expression}} () case (let (_, _, _)) + 1: -// expected-error@-1 2 {{'var' binding pattern cannot appear in an expression}} -// expected-error@-2 {{expression pattern of type 'Int' cannot match values of type '(Int, Int, Int)'}} +// expected-error@-1 {{expression pattern of type 'Int' cannot match values of type '(Int, Int, Int)'}} () } diff --git a/test/SILGen/import_as_member.swift b/test/SILGen/import_as_member.swift index 8e73fa17a8a18..b6e7a2764bbab 100644 --- a/test/SILGen/import_as_member.swift +++ b/test/SILGen/import_as_member.swift @@ -2,6 +2,7 @@ // REQUIRES: objc_interop import ImportAsMember.A import ImportAsMember.Class +import Foundation public func returnGlobalVar() -> Double { return Struct1.globalVar @@ -65,7 +66,6 @@ extension SomeClass { } public func useSpecialInit() -> Struct1 { - // FIXME: the below triggers an assert, due to number or params mismatch - // return Struct1(specialLabel:()) + return Struct1(specialLabel:()) } diff --git a/test/SILOptimizer/devirt_base_class.swift b/test/SILOptimizer/devirt_base_class.swift index cf82d7b893c82..76239f4259366 100644 --- a/test/SILOptimizer/devirt_base_class.swift +++ b/test/SILOptimizer/devirt_base_class.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -O -emit-sil %s | %FileCheck %s +// RUN: %target-swift-frontend -enable-spec-devirt -O -emit-sil %s | %FileCheck %s public class Base1 { @inline(never) func f() -> Int { return 0 } } diff --git a/test/SILOptimizer/devirt_covariant_return.swift b/test/SILOptimizer/devirt_covariant_return.swift index dc12740d9343f..0f63101cc62cd 100644 --- a/test/SILOptimizer/devirt_covariant_return.swift +++ b/test/SILOptimizer/devirt_covariant_return.swift @@ -1,5 +1,5 @@ -// RUN: %target-swift-frontend -module-name devirt_covariant_return -Xllvm -sil-full-demangle -O -Xllvm -disable-sil-cm-rr-cm=0 -Xllvm -sil-inline-generics=false -primary-file %s -emit-sil -sil-inline-threshold 1000 -Xllvm -sil-disable-pass=ObjectOutliner -sil-verify-all | %FileCheck %s +// RUN: %target-swift-frontend -module-name devirt_covariant_return -Xllvm -sil-full-demangle -enable-spec-devirt -O -Xllvm -disable-sil-cm-rr-cm=0 -Xllvm -sil-inline-generics=false -primary-file %s -emit-sil -sil-inline-threshold 1000 -Xllvm -sil-disable-pass=ObjectOutliner -sil-verify-all | %FileCheck %s // Make sure that we can dig all the way through the class hierarchy and // protocol conformances with covariant return types correctly. The verifier diff --git a/test/SILOptimizer/devirt_default_case.swift b/test/SILOptimizer/devirt_default_case.swift index d3598e59df367..6d485265edf67 100644 --- a/test/SILOptimizer/devirt_default_case.swift +++ b/test/SILOptimizer/devirt_default_case.swift @@ -1,6 +1,6 @@ -// RUN: %target-swift-frontend -O -module-name devirt_default_case -emit-sil %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-NORMAL %s -// RUN: %target-swift-frontend -O -module-name devirt_default_case -emit-sil -enable-testing %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-TESTABLE %s +// RUN: %target-swift-frontend -enable-spec-devirt -O -module-name devirt_default_case -emit-sil %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-NORMAL %s +// RUN: %target-swift-frontend -enable-spec-devirt -O -module-name devirt_default_case -emit-sil -enable-testing %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-TESTABLE %s @_silgen_name("action") func action(_ n:Int) -> () diff --git a/test/SILOptimizer/devirt_protocol_method_invocations.swift b/test/SILOptimizer/devirt_protocol_method_invocations.swift index 1cddbd37c749c..3741185505380 100644 --- a/test/SILOptimizer/devirt_protocol_method_invocations.swift +++ b/test/SILOptimizer/devirt_protocol_method_invocations.swift @@ -1,5 +1,5 @@ -// RUN: %target-swift-frontend -module-name devirt_protocol_method_invocations -O -Xllvm -sil-disable-pass=ExistentialSpecializer -emit-sil %s | %FileCheck %s +// RUN: %target-swift-frontend -module-name devirt_protocol_method_invocations -enable-spec-devirt -O -Xllvm -sil-disable-pass=ExistentialSpecializer -emit-sil %s | %FileCheck %s protocol PPP { func f() diff --git a/test/SILOptimizer/devirt_speculate.swift b/test/SILOptimizer/devirt_speculate.swift index e45f573d1147a..7167716153be1 100644 --- a/test/SILOptimizer/devirt_speculate.swift +++ b/test/SILOptimizer/devirt_speculate.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend %/s -parse-as-library -O -emit-sil -save-optimization-record-path %t.opt.yaml | %FileCheck %s +// RUN: %target-swift-frontend %/s -parse-as-library -enable-spec-devirt -O -emit-sil -save-optimization-record-path %t.opt.yaml | %FileCheck %s // RUN: %FileCheck -check-prefix=YAML -input-file=%t.opt.yaml %s // RUN: %target-swift-frontend %/s -parse-as-library -Osize -emit-sil | %FileCheck %s --check-prefix=OSIZE // diff --git a/test/SILOptimizer/devirt_speculative_init.swift b/test/SILOptimizer/devirt_speculative_init.swift index 28ce888723bfe..7f126ca1cea59 100644 --- a/test/SILOptimizer/devirt_speculative_init.swift +++ b/test/SILOptimizer/devirt_speculative_init.swift @@ -1,5 +1,5 @@ -// RUN: %target-swift-frontend %s -parse-as-library -O -emit-sil | %FileCheck %s +// RUN: %target-swift-frontend %s -parse-as-library -enable-spec-devirt -O -emit-sil | %FileCheck %s // RUN: %target-swift-frontend %s -parse-as-library -Osize -emit-sil // // Test speculative devirtualization. diff --git a/test/SILOptimizer/devirt_speculative_nested.swift b/test/SILOptimizer/devirt_speculative_nested.swift index c6c5fec6ad6fa..5dc8d089c6ecf 100644 --- a/test/SILOptimizer/devirt_speculative_nested.swift +++ b/test/SILOptimizer/devirt_speculative_nested.swift @@ -1,5 +1,5 @@ -// RUN: %target-swift-frontend -module-name devirt_speculative_nested %s -parse-as-library -O -emit-sil | %FileCheck %s +// RUN: %target-swift-frontend -module-name devirt_speculative_nested %s -parse-as-library -enable-spec-devirt -O -emit-sil | %FileCheck %s // RUN: %target-swift-frontend -module-name devirt_speculative_nested %s -parse-as-library -Osize -emit-sil // // Test speculative devirtualization. diff --git a/test/SILOptimizer/devirt_unbound_generic.swift b/test/SILOptimizer/devirt_unbound_generic.swift index e36a0f440cffb..67427ef9223ca 100644 --- a/test/SILOptimizer/devirt_unbound_generic.swift +++ b/test/SILOptimizer/devirt_unbound_generic.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -Xllvm -sil-inline-generics -emit-sorted-sil -emit-sil -O %s | %FileCheck %s +// RUN: %target-swift-frontend -Xllvm -sil-inline-generics -emit-sorted-sil -emit-sil -enable-spec-devirt -O %s | %FileCheck %s // We used to crash on this when trying to devirtualize t.boo(a, 1), // because it is an "apply" with replacement types that contain diff --git a/test/SILOptimizer/devirt_value_metatypes.swift b/test/SILOptimizer/devirt_value_metatypes.swift index 215ebfe9fc4d8..23dd0e226376b 100644 --- a/test/SILOptimizer/devirt_value_metatypes.swift +++ b/test/SILOptimizer/devirt_value_metatypes.swift @@ -1,5 +1,5 @@ -// RUN: %target-swift-frontend -module-name devirt_value_metatypes -emit-sil -O %s | %FileCheck %s +// RUN: %target-swift-frontend -module-name devirt_value_metatypes -emit-sil -enable-spec-devirt -O %s | %FileCheck %s open class A { @inline(never) diff --git a/test/SILOptimizer/escape_analysis.sil b/test/SILOptimizer/escape_analysis.sil index 46af879e675bd..eddfac11b7f09 100644 --- a/test/SILOptimizer/escape_analysis.sil +++ b/test/SILOptimizer/escape_analysis.sil @@ -1844,3 +1844,47 @@ bb3(%4 : $AnyObject): %5 = tuple () return %5 : $() } + +// Test value_to_bridge_object merged with a local reference. A graph node +// must be created for all values involved, and they must point to an +// escaping content node. +// CHECK-LABEL: CG of testValueToBridgeObject +// CHECK-NEXT: Val [ref] %1 Esc: , Succ: (%5.1) +// CHECK-NEXT: Val [ref] %5 Esc: , Succ: (%5.1) +// CHECK-NEXT: Con [int] %5.1 Esc: G, Succ: (%5.2) +// CHECK-NEXT: Con %5.2 Esc: G, Succ: +// CHECK-NEXT: Val [ref] %7 Esc: , Succ: (%5.1), %1, %5 +// CHECK-NEXT: Ret [ref] return Esc: , Succ: %7 +// CHECK-LABEL: End +sil @testValueToBridgeObject : $@convention(thin) (Builtin.Word) -> C { +bb0(%0 : $Builtin.Word): + %1 = alloc_ref $C + cond_br undef, bb1, bb2 + +bb1: + %derived = ref_to_bridge_object %1 : $C, %0 : $Builtin.Word + br bb3(%derived : $Builtin.BridgeObject) + +bb2: + %5 = value_to_bridge_object %0 : $Builtin.Word + br bb3(%5 : $Builtin.BridgeObject) + +bb3(%7 : $Builtin.BridgeObject): + %result = bridge_object_to_ref %7 : $Builtin.BridgeObject to $C + return %result : $C +} + +// Test strong_copy_unowned_value returned. It must be marked escaping, +// not simply "returned", because it's reference is formed from a +// function argument. +// CHECK-LABEL: CG of testStrongCopyUnowned +// CHECK-NEXT: Val [ref] %1 Esc: , Succ: (%1.1) +// CHECK-NEXT: Con [int] %1.1 Esc: G, Succ: (%1.2) +// CHECK-NEXT: Con %1.2 Esc: G, Succ: +// CHECK-NEXT: Ret [ref] return Esc: , Succ: %1 +// CHECK-LABEL: End +sil [ossa] @testStrongCopyUnowned : $@convention(thin) (@guaranteed @sil_unowned Builtin.NativeObject) -> @owned Builtin.NativeObject { +bb0(%0 : @guaranteed $@sil_unowned Builtin.NativeObject): + %1 = strong_copy_unowned_value %0 : $@sil_unowned Builtin.NativeObject + return %1 : $Builtin.NativeObject +} diff --git a/test/SILOptimizer/inline_cache_and_arc.swift b/test/SILOptimizer/inline_cache_and_arc.swift index 0601f30466049..f251ee07fd56f 100644 --- a/test/SILOptimizer/inline_cache_and_arc.swift +++ b/test/SILOptimizer/inline_cache_and_arc.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -parse-as-library -O -emit-sil %s | %FileCheck %s +// RUN: %target-swift-frontend -parse-as-library -enable-spec-devirt -O -emit-sil %s | %FileCheck %s // REQUIRES: swift_stdlib_no_asserts,optimized_stdlib,CPU=x86_64 // Test inline cache with a global class. Make sure the retain|release pair @@ -19,7 +19,6 @@ public func testit() { // CHECK-LABEL: sil @{{.*}}testityyF // CHECK: bb0: // CHECK-NOT: {{.*(retain|release).*}} -// CHECK: checked_cast_br // CHECK: bb1{{.*}}: // CHECK-NOT: {{.*(retain|release).*}} // CHECK: return diff --git a/test/SILOptimizer/opt_mode.swift b/test/SILOptimizer/opt_mode.swift index d2257d7c1d0ad..cfe34c25aea42 100644 --- a/test/SILOptimizer/opt_mode.swift +++ b/test/SILOptimizer/opt_mode.swift @@ -15,16 +15,6 @@ class B : A { func donothing(_ x: Int) -> Int { return x } -// CHECK-LABEL: sil {{.*}} [Ospeed] @{{.*}}test_ospeed -// CHECK: checked_cast_br -// CHECK: checked_cast_br -// CHECK: } -// CHECK-IR: define hidden {{.*}}test_ospeed{{.*}} [[NOSIZE_ATTR:#[0-9]+]] -@_optimize(speed) -func test_ospeed(_ a: A) -> Int { - return donothing(a.foo(27)) -} - // CHECK-LABEL: sil {{.*}} [Osize] @{{.*}}test_osize // CHECK: [[M:%[0-9]+]] = class_method // CHECK: [[A:%[0-9]+]] = apply [[M]] @@ -46,6 +36,16 @@ func test_onone(_ a: A) -> Int { return donothing(a.foo(27)) } +// CHECK-LABEL: sil {{.*}} [Ospeed] @{{.*}}test_ospeed +// CHECK: [[M:%[0-9]+]] = class_method +// CHECK: [[A:%[0-9]+]] = apply [[M]] +// CHECK: return [[A]] +// CHECK-IR: define hidden {{.*}}test_ospeed{{.*}} [[NOSIZE_ATTR:#[0-9]+]] +@_optimize(speed) +func test_ospeed(_ a: A) -> Int { + return donothing(a.foo(27)) +} + -// CHECK-IR: attributes [[NOSIZE_ATTR]] = { " // CHECK-IR: attributes [[SIZE_ATTR]] = { minsize " +// CHECK-IR: attributes [[NOSIZE_ATTR]] = { " diff --git a/test/api-digester/Inputs/Foo-new-version/foo.h b/test/api-digester/Inputs/Foo-new-version/foo.h index 61b56a05a5f17..b307b23510839 100644 --- a/test/api-digester/Inputs/Foo-new-version/foo.h +++ b/test/api-digester/Inputs/Foo-new-version/foo.h @@ -1,4 +1,4 @@ -#import +@import ObjectiveC; @protocol ObjcProt -(void) someFunctionFromProt; diff --git a/test/api-digester/Inputs/Foo-new-version/module.modulemap b/test/api-digester/Inputs/Foo-new-version/module.modulemap index 6522d75170250..57c5884f04377 100644 --- a/test/api-digester/Inputs/Foo-new-version/module.modulemap +++ b/test/api-digester/Inputs/Foo-new-version/module.modulemap @@ -1,3 +1,4 @@ module Foo { header "foo.h" + export * } diff --git a/test/api-digester/Inputs/Foo/foo.h b/test/api-digester/Inputs/Foo/foo.h index 7a52230b2d45a..93bcc41eb96be 100644 --- a/test/api-digester/Inputs/Foo/foo.h +++ b/test/api-digester/Inputs/Foo/foo.h @@ -1,4 +1,4 @@ -#import +@import ObjectiveC; @protocol ObjcProt -(void) someFunctionFromProt; diff --git a/test/api-digester/Inputs/Foo/module.modulemap b/test/api-digester/Inputs/Foo/module.modulemap index 6522d75170250..57c5884f04377 100644 --- a/test/api-digester/Inputs/Foo/module.modulemap +++ b/test/api-digester/Inputs/Foo/module.modulemap @@ -1,3 +1,4 @@ module Foo { header "foo.h" + export * } diff --git a/test/expr/expressions.swift b/test/expr/expressions.swift index d14e2671e841b..43af91bfcfebb 100644 --- a/test/expr/expressions.swift +++ b/test/expr/expressions.swift @@ -708,7 +708,7 @@ func test() { func unusedExpressionResults() { // Unused l-value _ // expected-error{{'_' can only appear in a pattern or on the left side of an assignment}} - + // expected-error@-1 {{expression resolves to an unused variable}} // Conditional Optional binding hides compiler error let optionalc:C? = nil diff --git a/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake b/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake index 8efd59710305b..b33c54d66f70b 100644 --- a/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake +++ b/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake @@ -213,21 +213,16 @@ endmacro() # add_sourcekit_executable(name # Name of the executable # [LLVM_LINK_COMPONENTS comp1 ...] # LLVM components this executable # # depends on -# [EXCLUDE_FROM_ALL] # Whether to exclude this executable from -# # the ALL_BUILD target # source1 [source2 source3 ...]) # Sources to add into this executable macro(add_sourcekit_executable name) - cmake_parse_arguments(SOURCEKITEXE - "EXCLUDE_FROM_ALL" - "" - "LLVM_LINK_COMPONENTS" - ${ARGN}) - - if (${SOURCEKITEXE_EXCLUDE_FROM_ALL}) - add_executable(${name} EXCLUDE_FROM_ALL ${SOURCEKITEXE_UNPARSED_ARGUMENTS}) - else() - add_executable(${name} ${SOURCEKITEXE_UNPARSED_ARGUMENTS}) - endif() + set(SOURCEKIT_EXECUTABLE_options) + set(SOURCEKIT_EXECUTABLE_single_parameter_options) + set(SOURCEKIT_EXECUTABLE_multiple_parameter_options LLVM_LINK_COMPONENTS) + cmake_parse_arguments(SOURCEKITEXE "${SOURCEKIT_EXECUTABLE_options}" + "${SOURCEKIT_EXECUTABLE_single_parameter_options}" + "${SOURCEKIT_EXECUTABLE_multiple_parameter_options}" ${ARGN}) + + add_executable(${name} ${SOURCEKITEXE_UNPARSED_ARGUMENTS}) if(NOT SWIFT_BUILT_STANDALONE AND NOT CMAKE_C_COMPILER_ID MATCHES Clang) add_dependencies(${name} clang) endif() @@ -245,17 +240,6 @@ macro(add_sourcekit_executable name) target_link_libraries(${name} PRIVATE ${LLVM_COMMON_LIBS}) set_target_properties(${name} PROPERTIES FOLDER "SourceKit executables") - if (NOT SWIFT_ASAN_BUILD) - if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") - set_target_properties(${name} - PROPERTIES - LINK_FLAGS "-Wl,-exported_symbol,_main") - endif() - if(SWIFT_ANALYZE_CODE_COVERAGE) - set_property(TARGET "${name}" APPEND_STRING PROPERTY - LINK_FLAGS " -fprofile-instr-generate -fcoverage-mapping") - endif() - endif() add_sourcekit_default_compiler_flags("${name}") endmacro() diff --git a/tools/SourceKit/tools/complete-test/CMakeLists.txt b/tools/SourceKit/tools/complete-test/CMakeLists.txt index 71a9ffde2c46d..ec3437650a0bb 100644 --- a/tools/SourceKit/tools/complete-test/CMakeLists.txt +++ b/tools/SourceKit/tools/complete-test/CMakeLists.txt @@ -13,12 +13,12 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) BlocksRuntime) endif() -if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set_target_properties(complete-test - PROPERTIES - LINK_FLAGS "-Wl,-rpath -Wl,@executable_path/../lib") +if(CMAKE_SYSTEM_NAME STREQUAL Darwin) + set_target_properties(complete-test PROPERTIES + INSTALL_RPATH "@executable_path/../lib") + target_link_options(complete-test PRIVATE + "LINKER:-exported_symbol,_main") endif() - if(SWIFT_ANALYZE_CODE_COVERAGE) set_property(TARGET complete-test APPEND_STRING PROPERTY LINK_FLAGS " -fprofile-instr-generate -fcoverage-mapping") @@ -26,6 +26,4 @@ endif() add_dependencies(tools complete-test) swift_install_in_component(TARGETS complete-test - RUNTIME - DESTINATION bin - COMPONENT tools) + RUNTIME DESTINATION bin COMPONENT tools) diff --git a/tools/SourceKit/tools/sourcekitd-repl/CMakeLists.txt b/tools/SourceKit/tools/sourcekitd-repl/CMakeLists.txt index fe2bc449a0ab5..d4a3a77df2ac8 100644 --- a/tools/SourceKit/tools/sourcekitd-repl/CMakeLists.txt +++ b/tools/SourceKit/tools/sourcekitd-repl/CMakeLists.txt @@ -12,15 +12,14 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) dispatch BlocksRuntime) endif() -target_include_directories(sourcekitd-repl PRIVATE - ${LibEdit_INCLUDE_DIRS}) target_link_libraries(sourcekitd-repl PRIVATE - ${LibEdit_LIBRARIES}) + libedit) -if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set_target_properties(sourcekitd-repl - PROPERTIES - LINK_FLAGS "-Wl,-rpath -Wl,@executable_path/../lib") +if(CMAKE_SYSTEM_NAME STREQUAL Darwin) + set_target_properties(sourcekitd-repl PROPERTIES + INSTALL_RPATH "@executable_path/../lib") + target_link_options(sourcekitd-repl PRIVATE + "LINKER:-exported_symbol,_main") endif() if(SWIFT_ANALYZE_CODE_COVERAGE) set_property(TARGET sourcekitd-repl APPEND_STRING PROPERTY @@ -29,6 +28,4 @@ endif() add_dependencies(tools sourcekitd-repl) swift_install_in_component(TARGETS sourcekitd-repl - RUNTIME - DESTINATION bin - COMPONENT tools) + RUNTIME DESTINATION bin COMPONENT tools) diff --git a/tools/SourceKit/tools/sourcekitd-test/CMakeLists.txt b/tools/SourceKit/tools/sourcekitd-test/CMakeLists.txt index b2cd4056e599a..cf69c7b9c6e82 100644 --- a/tools/SourceKit/tools/sourcekitd-test/CMakeLists.txt +++ b/tools/SourceKit/tools/sourcekitd-test/CMakeLists.txt @@ -25,12 +25,12 @@ endif() add_dependencies(sourcekitd-test sourcekitdTestOptionsTableGen) -if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set_target_properties(sourcekitd-test - PROPERTIES - LINK_FLAGS "-Wl,-rpath -Wl,@executable_path/../lib") +if(CMAKE_SYSTEM_NAME STREQUAL Darwin) + set_target_properties(sourcekitd-test PROPERTIES + INSTALL_RPATH "@executable_path/../lib") + target_link_options(sourcekitd-test PRIVATE + "LINKER:-exported_symbol,_main") endif() - if(SWIFT_ANALYZE_CODE_COVERAGE) set_property(TARGET sourcekitd-test APPEND_STRING PROPERTY LINK_FLAGS " -fprofile-instr-generate -fcoverage-mapping") @@ -38,6 +38,4 @@ endif() add_dependencies(tools sourcekitd-test) swift_install_in_component(TARGETS sourcekitd-test - RUNTIME - DESTINATION bin - COMPONENT tools) + RUNTIME DESTINATION bin COMPONENT tools) diff --git a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp index 074b8bae5a568..2188f711a48dc 100644 --- a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp +++ b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp @@ -987,6 +987,13 @@ static int handleTestInvocation(TestOptions Opts, TestOptions &InitOpts) { sourcekitd_object_t Args = sourcekitd_request_array_create(nullptr, 0); if (!Opts.ModuleCachePath.empty()) { if (compilerArgsAreClang) { + // We need -fmodules or else the clang argument parsing does not honour + // -fmodules-cache-path. In reality, the swift ClangImporter will always + // enable modules when importing, so this should only impact the + // clang argument parsing. This is needed even if the header doesn't + // use modules, since Swift itself will import its shims module, and + // that needs to honour the -module-cache-path option when testing. + sourcekitd_request_array_set_string(Args, SOURCEKITD_ARRAY_APPEND, "-fmodules"); std::string opt = "-fmodules-cache-path=" + Opts.ModuleCachePath; sourcekitd_request_array_set_string(Args, SOURCEKITD_ARRAY_APPEND, opt.c_str()); } else { diff --git a/tools/sil-opt/SILOpt.cpp b/tools/sil-opt/SILOpt.cpp index c912ba085e724..c584a950a1ce2 100644 --- a/tools/sil-opt/SILOpt.cpp +++ b/tools/sil-opt/SILOpt.cpp @@ -102,6 +102,10 @@ static llvm::cl::opt VerifyExclusivity("enable-verify-exclusivity", llvm::cl::desc("Verify the access markers used to enforce exclusivity.")); +static llvm::cl::opt +EnableSpeculativeDevirtualization("enable-spec-devirt", + llvm::cl::desc("Enable Speculative Devirtualization pass.")); + namespace { enum EnforceExclusivityMode { Unchecked, // static only @@ -376,6 +380,8 @@ int main(int argc, char **argv) { } } + SILOpts.EnableSpeculativeDevirtualization = EnableSpeculativeDevirtualization; + serialization::ExtendedValidationInfo extendedInfo; llvm::ErrorOr> FileBufOrErr = Invocation.setUpInputForSILTool(InputFilename, ModuleName, diff --git a/utils/backtrace-check b/utils/backtrace-check index a304f68bc22ed..a8058cff27b46 100755 --- a/utils/backtrace-check +++ b/utils/backtrace-check @@ -1,54 +1,82 @@ #!/usr/bin/env python -# This script uses a regex to validate the output of our backtraces. -# The layout we assume is: -# -#
+ -# -# It currently just checks that the backtrace results in at least one correctly -# formatted entry. It does not directly validate the input since the output -# would not be robust against standard library changes. -# -# TODO: We could have the user pass in the frame number, library name, and -# demangled name. These we can always validate as true in a robust way. On the -# other hand, address and offset are more difficult to validate in a robust way -# in the face of small codegen differences, so without any further thought I -# imagine we can just check the format. -# -# 11 libswiftCore.dylib 0x000000000dce84d0l _fatalErrorMessage(StaticString, -# StaticString, StaticString, UInt, flags : UInt32) -> () + 444 - -from __future__ import print_function + +""" +This script uses a regex to validate the output of our backtraces. +The layout we assume is: + +
+ + +It currently just checks that the backtrace results in at least one correctly +formatted entry. It does not directly validate the input since the output +would not be robust against standard library changes. + +TODO: We could have the user pass in the frame number, library name, and +demangled name. These we can always validate as true in a robust way. On the +other hand, address and offset are more difficult to validate in a robust way +in the face of small codegen differences, so without any further thought I +imagine we can just check the format. + +11 libswiftCore.dylib 0x000000000dce84d0l _fatalErrorMessage(StaticString, +StaticString, StaticString, UInt, flags : UInt32) -> () + 444 +""" + + +from __future__ import absolute_import, print_function, unicode_literals import argparse import re import sys -def main(): +# ----------------------------------------------------------------------------- +# Constants + +DESCRIPTION = """ +Checks that a stacktrace dump follows canonical formatting. +""" + +TARGET_PATTERN = re.compile( + r'(?P\d+) +(?P\S+) +(?P
0x[0-9a-fA-F]{16}) ' + r'(?P[^+]+) [+] (?P\d+)') + +RESULTS_FORMAT = """Stack Trace Entry: +\tIndex: '%(index)s' +\tObject File: '%(object)s' +\tAddress: '%(address)s' +\tRoutine: '%(routine)s' +\tOffset: '%(offset)s' +""" + + +# ----------------------------------------------------------------------------- + +def parse_args(): parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, - description="""Checks that a stacktrace dump follows canonical -formatting.""") + description=DESCRIPTION) + parser.add_argument( - "-u", "--check-unavailable", action='store_true', - help="Checks if any symbols were unavailable") - args = parser.parse_args() + '-u', '--check-unavailable', + action='store_true', + help='Checks if any symbols were unavailable') - TARGET_RE = re.compile( - r"(?P\d+) +(?P\S+) +(?P
0x[0-9a-fA-F]{16}) " - r"(?P[^+]+) [+] (?P\d+)") + return parser.parse_args() + + +def main(): + args = parse_args() lines = sys.stdin.readlines() found_stack_trace_start = False found_stack_trace_entry = False for line in lines: - line = line.rstrip("\n") + line = line.rstrip('\n') # First see if we found the start of our stack trace start. If so, set # the found stack trace flag and continue. - if line == "Current stack trace:": + if line == 'Current stack trace:': assert(not found_stack_trace_start) found_stack_trace_start = True continue @@ -59,21 +87,19 @@ formatting.""") continue # Ok, we are in the middle of matching a stack trace entry. - m = TARGET_RE.match(line) + matches = TARGET_PATTERN.match(line) + # If we fail to match, we have exited the stack trace entry region - if m is None: + if matches is None: break # At this point, we know that we have some sort of match. found_stack_trace_entry = True - print("Stack Trace Entry:") - print("\tIndex: '%(index)s'\n\tObject File: '%(object)s'\n\tAddress: " - "'%(address)s'\n\tRoutine: '%(routine)s'\n\tOffset: '%(offset)s'" - "\n" % m.groupdict()) + print(RESULTS_FORMAT.format(**matches.groupdict())) # Check for unavailable symbols, if that was requested. if args.check_unavailable: - assert("unavailable" not in m.group("routine")) + assert('unavailable' not in matches.group('routine')) # Once we have processed all of the lines, make sure that we found at least # one stack trace entry. diff --git a/utils/build-overlay b/utils/build-overlay deleted file mode 100755 index 039d61369b88e..0000000000000 --- a/utils/build-overlay +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -function usage { - echo "usage: $0 OVERLAY SDK TARGET" - echo "SDK: OSX,IOS,IOS_SIMULATOR,TVOS,TVOS_SIMULATOR,WATCHOS,WATCHOS_SIMULATOR" - echo "TARGET: macosx,iphoneos,iphonesimulator,appletvos,appletvsimulator,watchos,watchsimulator" - echo "example: ./utils/build-overlay AVFoundation OSX macosx" - exit 1 -} - -OVERLAY=$1; SDK=$2; TARGET=$3 -if [ ! "$OVERLAY" ]; then echo "Overlay param required"; usage; fi -if [ ! "$SDK" ]; then echo "SDK param required"; usage; fi -if [ ! "$TARGET" ]; then echo "TARGET param required"; usage; fi - -function absolute_path { if [[ "$1" == /* ]]; then echo "$1"; else echo "$PWD/$1"; fi } -function dir_name { echo "${1%/*}"; } -function file_name { echo "${1##*/}"; } -script_absolute_path=$(absolute_path "${BASH_SOURCE[@]}") -script_dir_name=$(dir_name "${script_absolute_path}") -script_file_name=$(file_name "${script_absolute_path}") -overlay_source_path="${script_dir_name}/../stdlib/public/Darwin/$OVERLAY" -build_dir="${script_dir_name}/../../build/${OVERLAY}-${SDK}" -swift_source_root="${script_dir_name}/../../../" - -mkdir -p "$build_dir" && cd "$build_dir" || exit - -echo "OVERLAY: ${OVERLAY}" -echo "SDK: ${SDK}" -echo "TARGET: ${TARGET}" -echo "script_absolute_path: ${script_absolute_path}" -echo "script_dir_name: ${script_dir_name}" -echo "script_file_name: ${script_file_name}" -echo "overlay_source_path: ${overlay_source_path}" -echo "swift_source_root: ${swift_source_root}" -echo "build_dir: ${build_dir}" - -toolchain=$(xcode-select -p) -cmake -G Ninja -DSWIFT_SOURCE_ROOT="${swift_source_root}" -DSWIFT_DEST_ROOT="${build_dir}/root" -DSWIFT_HOST_VARIANT_SDK="${SDK}" -DTOOLCHAIN_DIR="${toolchain}/Toolchains/XcodeDefault.xctoolchain" "${overlay_source_path}" -NINJA_TARGET="swift${OVERLAY}-${TARGET}" -ninja "${NINJA_TARGET}" diff --git a/utils/build-script b/utils/build-script index 76ea91f740d65..120f75a5cd928 100755 --- a/utils/build-script +++ b/utils/build-script @@ -923,7 +923,8 @@ def main_preset(): "--distcc", help="use distcc", action=argparse.actions.StoreTrueAction, - nargs=argparse.Nargs.OPTIONAL) + nargs=argparse.Nargs.OPTIONAL, + default=os.environ.get('USE_DISTCC') == '1') parser.add_argument( "--cmake-c-launcher", help="the absolute path to set CMAKE_C_COMPILER_LAUNCHER", diff --git a/utils/build_swift/build_swift/driver_arguments.py b/utils/build_swift/build_swift/driver_arguments.py index 1f1587c5b20d0..108ea4793315a 100644 --- a/utils/build_swift/build_swift/driver_arguments.py +++ b/utils/build_swift/build_swift/driver_arguments.py @@ -400,6 +400,7 @@ def create_argument_parser(): option('--host-libtool', store_path(executable=True), help='the absolute path to libtool. Default is auto detected.') option('--distcc', toggle_true, + default=os.environ.get('USE_DISTCC') == '1', help='use distcc in pump mode') option('--enable-asan', toggle_true, help='enable Address Sanitizer') diff --git a/utils/error_enum_to_cases.pl b/utils/error_enum_to_cases.pl deleted file mode 100644 index fad0043f8b8ae..0000000000000 --- a/utils/error_enum_to_cases.pl +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/perl -w - -use strict; -use English; - -sub translateAvailability { - my $version = shift; - $version =~ s/^\s+|\s+$//g; - if ($version eq "NA") { return "unavailable"; } - $version =~ /([0-9]+)_([0-9]+)/; - return "introduced=$1.$2"; -} - -my $prefixLength = 2; -my %minimumValues = (); -my %maximumValues = (); -my %rangeAvailability = (); -my $prev_had_availability = 0; -foreach my $line () { - chomp $line; - if ($line =~ /([A-Za-z_][A-Za-z_0-9]+).*=[^0-9A-Za-z_-]*([A-Za-z0-9_-]+)/) { - my $fullname = $1; - my $value = $2; - my $has_availability = 0; - - my $availability = ""; -# if ($line =~ /AVAILABLE\s*[(](([0-9]+_[0-9]+)|(NA))[ ]*,[ ]*(([0-9]+_[0-9]+)|(NA))[)]/) { - if ($line =~ /AVAILABLE[ ]*[(]([^),]*),([^)]*)[)]/) { - $has_availability = 1; - my $osx = $1; - my $ios = $2; - $osx = translateAvailability($osx); - $ios = translateAvailability($ios); - $availability = " \@available(OSX, $osx) \@available(iOS, $ios)\n"; - } - - # If the full name ends in "Minimum" or "Maximum", it's for a range. - my $rangeName = ""; - if ($fullname =~ /(Minimum|Maximum)$/) { - $rangeName = substr $PREMATCH, $prefixLength; - if ($MATCH eq "Minimum") { - $minimumValues{$rangeName} = $value; - } else { - $maximumValues{$rangeName} = $value; - } - $rangeAvailability{$rangeName} = $availability; - } else { - if ($availability ne "") { - if ($prev_had_availability == 0) { - print("\n"); - } - print("$availability"); - } - my $casename = substr $fullname, $prefixLength; - print(" case $casename = $value\n"); - - if ($availability ne "") { - print("\n"); - $prev_had_availability = 1; - } else { - $prev_had_availability = 0; - } - } - } -} - -# Print properties for the ranges. -foreach my $key (sort keys(%minimumValues)) { - my $minimum = $minimumValues{$key}; - my $maximum = $maximumValues{$key}; - my $availability = $rangeAvailability{$key}; - print "\n"; - if ($availability ne "") { - print $availability; - } - print(" public var is$key: Bool {\n"); - print(" return rawValue >= $minimum && rawValue <= $maximum;\n"); - print(" }\n"); -} diff --git a/utils/guard-malloc-swift b/utils/guard-malloc-swift deleted file mode 100755 index 05660e54988ff..0000000000000 --- a/utils/guard-malloc-swift +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh -# Runs swift (found on the path) with -use-malloc and GuardMalloc enabled. -# Command-line arguments are forwarded to the swift compiler untouched. -# This script can be used to run the test suite with memory debugging enabled -# by setting the SWIFT environment variable to point to the script, as in: -# -# SWIFT=/path/to/guard-malloc-swift llvm-lit -sv test - -export MallocScribble=1 -export MallocPreScribble=1 -export MallocGuardEdges=1 -export MallocCheckHeapStart=100 -export MallocCheckHeapEach=100 -export MallocCheckHeapAbort=1 -export MallocErrorAbort=1 - -export DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib - -swift -use-malloc "$@" diff --git a/utils/swift_build_support/swift_build_support/targets.py b/utils/swift_build_support/swift_build_support/targets.py index 16dd1c22454e7..45bb45ca9916a 100644 --- a/utils/swift_build_support/swift_build_support/targets.py +++ b/utils/swift_build_support/swift_build_support/targets.py @@ -70,7 +70,7 @@ def __init__(self, name, archs, sdk_name=None, is_simulator=False): @property def is_embedded(self): """Check if this is a Darwin platform for embedded devices.""" - return self.name != "macosx" + return self.name != "macosx" and self.name != "maccatalyst" @property def supports_benchmark(self): diff --git a/validation-test/Reflection/Inputs/ObjCClasses/module.map b/validation-test/Reflection/Inputs/ObjCClasses/module.map index 6a802414978cf..b0c10f7c44921 100644 --- a/validation-test/Reflection/Inputs/ObjCClasses/module.map +++ b/validation-test/Reflection/Inputs/ObjCClasses/module.map @@ -1,3 +1,4 @@ module ObjCClasses { header "ObjCClasses.h" + export * } diff --git a/validation-test/Sema/type_checker_crashers_fixed/rdar49712364.swift b/validation-test/Sema/type_checker_crashers_fixed/rdar49712364.swift new file mode 100644 index 0000000000000..c4ee382b8dc5e --- /dev/null +++ b/validation-test/Sema/type_checker_crashers_fixed/rdar49712364.swift @@ -0,0 +1,15 @@ +// RUN: not %target-swift-frontend %s -typecheck + +protocol A {} + +class C where T: A {} + +extension C { + func foo() { + extension C where T: Undefined { + class Inner: Encodable { + var foo: Int + } + } + } +}