Skip to content

Commit

Permalink
Merge pull request #869 from swiftwasm/master
Browse files Browse the repository at this point in the history
[pull] swiftwasm from master
  • Loading branch information
pull[bot] authored May 1, 2020
2 parents a493040 + 7b787a6 commit da9e60e
Show file tree
Hide file tree
Showing 120 changed files with 1,253 additions and 778 deletions.
5 changes: 2 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ CHANGELOG
</details>

Swift 5.3
----------
---------

* [SR-7083][]:

Expand Down Expand Up @@ -653,8 +653,6 @@ Swift 5.1
`Array` and `ContiguousArray` now have `init(unsafeUninitializedCapacity:initializingWith:)`,
which provides access to the array's uninitialized storage.

**Add new entries to the top of this section, not here!**

Swift 5.0
---------

Expand Down Expand Up @@ -8108,4 +8106,5 @@ Swift 1.0
[SR-9827]: <https://bugs.swift.org/browse/SR-9827>
[SR-11298]: <https://bugs.swift.org/browse/SR-11298>
[SR-11429]: <https://bugs.swift.org/browse/SR-11429>
[SR-11700]: <https://bugs.swift.org/browse/SR-11700>
[SR-11841]: <https://bugs.swift.org/browse/SR-11841>
2 changes: 1 addition & 1 deletion docs/LibraryEvolution.rst
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ There are very few safe changes to make to protocols and their members:
themselves).
- The ``@discardableResult`` and ``@warn_unqualified_access`` attributes may
be added to or removed from a function requirement.
- A new `associatedtype` requirement may be added (with the appropriate
- A new ``associatedtype`` requirement may be added (with the appropriate
availability), as long as it has a default implementation.
- A new non-type requirement may be added (with the appropriate availability),
as long as it has an unconstrained default implementation. If the requirement
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/DiagnosticsCommon.def
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ WARNING(warn_property_wrapper_module_scope,none,
"wrapper %0; please qualify the reference with %1",
(DeclNameRef, Identifier))

NOTE(circular_type_resolution_note,none,
"while resolving type %0", (TypeRepr *))

//------------------------------------------------------------------------------
// MARK: Cross-import overlay loading diagnostics
//------------------------------------------------------------------------------
Expand Down
86 changes: 6 additions & 80 deletions include/swift/AST/Evaluator.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,6 @@ class DiagnosticEngine;
class Evaluator;
class UnifiedStatsReporter;

namespace detail {
// Remove this when the compiler bumps to C++17.
template <typename...>
using void_t = void;
}

/// An "abstract" request function pointer, which is the storage type
/// used for each of the
using AbstractRequestFunction = void(void);
Expand Down Expand Up @@ -231,37 +225,7 @@ class Evaluator {
/// so all clients must cope with cycles.
llvm::DenseMap<AnyRequest, std::vector<AnyRequest>> dependencies;

/// A stack of dependency sources in the order they were evaluated.
llvm::SmallVector<evaluator::DependencySource, 8> dependencySources;

/// An RAII type that manages manipulating the evaluator's
/// dependency source stack. It is specialized to be zero-cost for
/// requests that are not dependency sources.
template <typename Request, typename = detail::void_t<>>
struct IncrementalDependencyStackRAII {
IncrementalDependencyStackRAII(Evaluator &E, const Request &Req) {}
};

template <typename Request>
struct IncrementalDependencyStackRAII<
Request, typename std::enable_if<Request::isDependencySource>::type> {
NullablePtr<Evaluator> Eval;
IncrementalDependencyStackRAII(Evaluator &E, const Request &Req) {
auto Source = Req.readDependencySource(E);
// If there is no source to introduce, bail. This can occur if
// a request originates in the context of a module.
if (!Source.getPointer()) {
return;
}
E.dependencySources.emplace_back(Source);
Eval = &E;
}

~IncrementalDependencyStackRAII() {
if (Eval.isNonNull())
Eval.get()->dependencySources.pop_back();
}
};
evaluator::DependencyCollector collector;

/// Retrieve the request function for the given zone and request IDs.
AbstractRequestFunction *getAbstractRequestFunction(uint8_t zoneID,
Expand Down Expand Up @@ -303,7 +267,8 @@ class Evaluator {
typename std::enable_if<Request::isEverCached>::type * = nullptr>
llvm::Expected<typename Request::OutputType>
operator()(const Request &request) {
IncrementalDependencyStackRAII<Request> incDeps{*this, request};
evaluator::DependencyCollector::StackRAII<Request> incDeps{collector,
request};
// The request can be cached, but check a predicate to determine
// whether this particular instance is cached. This allows more
// fine-grained control over which instances get cache.
Expand All @@ -319,7 +284,8 @@ class Evaluator {
typename std::enable_if<!Request::isEverCached>::type * = nullptr>
llvm::Expected<typename Request::OutputType>
operator()(const Request &request) {
IncrementalDependencyStackRAII<Request> incDeps{*this, request};
evaluator::DependencyCollector::StackRAII<Request> incDeps{collector,
request};
return getResultUncached(request);
}

Expand Down Expand Up @@ -476,47 +442,7 @@ class Evaluator {
typename std::enable_if<Request::isDependencySink>::type * = nullptr>
void reportEvaluatedResult(const Request &r,
const typename Request::OutputType &o) {
if (auto *tracker = getActiveDependencyTracker())
r.writeDependencySink(*this, *tracker, o);
}

/// If there is an active dependency source, returns its
/// \c ReferencedNameTracker. Else, returns \c nullptr.
ReferencedNameTracker *getActiveDependencyTracker() const {
if (auto *source = getActiveDependencySourceOrNull())
return source->getRequestBasedReferencedNameTracker();
return nullptr;
}

public:
/// Returns \c true if the scope of the current active source cascades.
///
/// If there is no active scope, the result always cascades.
bool isActiveSourceCascading() const {
return getActiveSourceScope() == evaluator::DependencyScope::Cascading;
}

/// Returns the scope of the current active scope.
///
/// If there is no active scope, the result always cascades.
evaluator::DependencyScope getActiveSourceScope() const {
if (dependencySources.empty()) {
return evaluator::DependencyScope::Cascading;
}
return dependencySources.back().getInt();
}

/// Returns the active dependency's source file, or \c nullptr if no
/// dependency source is active.
///
/// The use of this accessor is strongly discouraged, as it implies that a
/// dependency sink is seeking to filter out names based on the files they
/// come from. Existing callers are being migrated to more reasonable ways
/// of judging the relevancy of a dependency.
SourceFile *getActiveDependencySourceOrNull() const {
if (dependencySources.empty())
return nullptr;
return dependencySources.back().getPointer();
r.writeDependencySink(collector, o);
}

public:
Expand Down
122 changes: 122 additions & 0 deletions include/swift/AST/EvaluatorDependencies.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ namespace swift {

namespace evaluator {

namespace detail {
// Remove this when the compiler bumps to C++17.
template <typename...> using void_t = void;
} // namespace detail

/// The "scope" of a dependency edge tracked by the evaluator.
///
/// Dependency scopes come in two flavors: cascading and private. A private
Expand Down Expand Up @@ -99,6 +104,123 @@ inline DependencyScope getScopeForAccessLevel(AccessLevel l) {
// edges in the incremental dependency graph invalidate entire files instead
// of individual contexts.
using DependencySource = llvm::PointerIntPair<SourceFile *, 1, DependencyScope>;

/// A \c DependencyCollector is an aggregator of named references discovered in a
/// particular \c DependencyScope during the course of request evaluation.
struct DependencyCollector {
private:
/// A stack of dependency sources in the order they were evaluated.
llvm::SmallVector<evaluator::DependencySource, 8> dependencySources;

public:
DependencyCollector() = default;

public:
/// Registers a named reference from the current dependency scope to a member
/// defined in the given \p subject type.
///
/// Used member constraints are typically the by-product of direct lookups,
/// where the name being looked up and the target of the lookup are known
/// up front. A used member dependency causes the file to be rebuilt if the
/// definition of that member changes in any way - via
/// deletion, addition, or mutation of a member with that same name.
void addUsedMember(NominalTypeDecl *subject, DeclBaseName name);
/// Registers a reference from the current dependency scope to a
/// "potential member" of the given \p subject type.
///
/// A single potential member dependency can be thought of as many used member
/// dependencies - one for each current member of the subject type, but also
/// one for every member that will be added or removed from the type in the
/// future. As such, these dependencies cause rebuilds when any members are
/// added, removed, or changed in the \p subject type. It also indicates a
/// dependency on the \p subject type's existence, so deleting the \p subject
/// type will also cause a rebuild.
///
/// These dependencies are most appropriate for protocol conformances,
/// superclass constraints, and other requirements involving entire types.
void addPotentialMember(NominalTypeDecl *subject);
/// Registers a reference from the current dependency scope to a given
/// top-level \p name.
///
/// A top level dependency causes a rebuild when another top-level entity with
/// that name is added, removed, or modified.
void addTopLevelName(DeclBaseName name);
/// Registers a reference from the current dependency scope to a given
/// dynamic member \p name.
///
/// A dynamic lookup dependency is a special kind of member dependency on
/// a name that is found by \c AnyObject lookup.
void addDynamicLookupName(DeclBaseName name);

public:
/// Returns the scope of the current active scope.
///
/// If there is no active scope, the result always cascades.
evaluator::DependencyScope getActiveSourceScope() const {
if (dependencySources.empty()) {
return evaluator::DependencyScope::Cascading;
}
return dependencySources.back().getInt();
}

/// Returns the active dependency's source file, or \c nullptr if no
/// dependency source is active.
///
/// The use of this accessor is strongly discouraged, as it implies that a
/// dependency sink is seeking to filter out names based on the files they
/// come from. Existing callers are being migrated to more reasonable ways
/// of judging the relevancy of a dependency.
SourceFile *getActiveDependencySourceOrNull() const {
if (dependencySources.empty())
return nullptr;
return dependencySources.back().getPointer();
}

public:
/// An RAII type that manages manipulating the evaluator's
/// dependency source stack. It is specialized to be zero-cost for
/// requests that are not dependency sources.
template <typename Request, typename = detail::void_t<>> struct StackRAII {
StackRAII(DependencyCollector &DC, const Request &Req) {}
};

template <typename Request>
struct StackRAII<Request,
typename std::enable_if<Request::isDependencySource>::type> {
NullablePtr<DependencyCollector> Coll;
StackRAII(DependencyCollector &coll, const Request &Req) {
auto Source = Req.readDependencySource(coll);
// If there is no source to introduce, bail. This can occur if
// a request originates in the context of a module.
if (!Source.getPointer()) {
return;
}
coll.dependencySources.emplace_back(Source);
Coll = &coll;
}

~StackRAII() {
if (Coll.isNonNull())
Coll.get()->dependencySources.pop_back();
}
};

private:
/// If there is an active dependency source, returns its
/// \c ReferencedNameTracker. Else, returns \c nullptr.
ReferencedNameTracker *getActiveDependencyTracker() const {
if (auto *source = getActiveDependencySourceOrNull())
return source->getRequestBasedReferencedNameTracker();
return nullptr;
}

/// Returns \c true if the scope of the current active source cascades.
///
/// If there is no active scope, the result always cascades.
bool isActiveSourceCascading() const {
return getActiveSourceScope() == evaluator::DependencyScope::Cascading;
}
};
} // end namespace evaluator

} // end namespace swift
Expand Down
3 changes: 2 additions & 1 deletion include/swift/AST/IRGenRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ class IRGenSourceFileRequest

public:
// Incremental dependencies.
evaluator::DependencySource readDependencySource(Evaluator &) const;
evaluator::DependencySource
readDependencySource(const evaluator::DependencyCollector &) const;
};

class IRGenWholeModuleRequest
Expand Down
44 changes: 32 additions & 12 deletions include/swift/AST/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,26 +209,46 @@ class ModuleDecl : public DeclContext, public TypeDecl {

public:
typedef ArrayRef<Located<Identifier>> AccessPathTy;
typedef std::pair<ModuleDecl::AccessPathTy, ModuleDecl*> ImportedModule;

/// Convenience struct to keep track of a module along with its access path.
struct ImportedModule {
/// The access path from an import: `import Foo.Bar` -> `Foo.Bar`.
ModuleDecl::AccessPathTy accessPath;
/// The actual module corresponding to the import.
///
/// Invariant: The pointer is non-null.
ModuleDecl *importedModule;

ImportedModule(ModuleDecl::AccessPathTy accessPath,
ModuleDecl *importedModule)
: accessPath(accessPath), importedModule(importedModule) {
assert(this->importedModule);
}

bool operator==(const ModuleDecl::ImportedModule &other) const {
return (this->importedModule == other.importedModule) &&
(this->accessPath == other.accessPath);
}
};

static bool matchesAccessPath(AccessPathTy AccessPath, DeclName Name) {
assert(AccessPath.size() <= 1 && "can only refer to top-level decls");

return AccessPath.empty()
|| DeclName(AccessPath.front().Item).matchesRef(Name);
}

/// Arbitrarily orders ImportedModule records, for inclusion in sets and such.
class OrderImportedModules {
public:
bool operator()(const ImportedModule &lhs,
const ImportedModule &rhs) const {
if (lhs.second != rhs.second)
return std::less<const ModuleDecl *>()(lhs.second, rhs.second);
if (lhs.first.data() != rhs.first.data())
return std::less<AccessPathTy::iterator>()(lhs.first.begin(),
rhs.first.begin());
return lhs.first.size() < rhs.first.size();
if (lhs.importedModule != rhs.importedModule)
return std::less<const ModuleDecl *>()(lhs.importedModule,
rhs.importedModule);
if (lhs.accessPath.data() != rhs.accessPath.data())
return std::less<AccessPathTy::iterator>()(lhs.accessPath.begin(),
rhs.accessPath.begin());
return lhs.accessPath.size() < rhs.accessPath.size();
}
};

Expand Down Expand Up @@ -860,14 +880,14 @@ namespace llvm {
}

static unsigned getHashValue(const ModuleDecl::ImportedModule &val) {
auto pair = std::make_pair(val.first.size(), val.second);
auto pair = std::make_pair(val.accessPath.size(), val.importedModule);
return llvm::DenseMapInfo<decltype(pair)>::getHashValue(pair);
}

static bool isEqual(const ModuleDecl::ImportedModule &lhs,
const ModuleDecl::ImportedModule &rhs) {
return lhs.second == rhs.second &&
ModuleDecl::isSameAccessPath(lhs.first, rhs.first);
return lhs.importedModule == rhs.importedModule &&
ModuleDecl::isSameAccessPath(lhs.accessPath, rhs.accessPath);
}
};
}
Expand Down
Loading

0 comments on commit da9e60e

Please sign in to comment.