Skip to content

Commit 1f5dcf0

Browse files
authored
Merge pull request swiftlang#31229 from CodaFi/collect-a-mundo
[NFC] Extract Dependency Registration to DependencyCollector
2 parents 62e5780 + 7a724b1 commit 1f5dcf0

15 files changed

+259
-196
lines changed

include/swift/AST/Evaluator.h

Lines changed: 6 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,6 @@ class DiagnosticEngine;
4848
class Evaluator;
4949
class UnifiedStatsReporter;
5050

51-
namespace detail {
52-
// Remove this when the compiler bumps to C++17.
53-
template <typename...>
54-
using void_t = void;
55-
}
56-
5751
/// An "abstract" request function pointer, which is the storage type
5852
/// used for each of the
5953
using AbstractRequestFunction = void(void);
@@ -231,37 +225,7 @@ class Evaluator {
231225
/// so all clients must cope with cycles.
232226
llvm::DenseMap<AnyRequest, std::vector<AnyRequest>> dependencies;
233227

234-
/// A stack of dependency sources in the order they were evaluated.
235-
llvm::SmallVector<evaluator::DependencySource, 8> dependencySources;
236-
237-
/// An RAII type that manages manipulating the evaluator's
238-
/// dependency source stack. It is specialized to be zero-cost for
239-
/// requests that are not dependency sources.
240-
template <typename Request, typename = detail::void_t<>>
241-
struct IncrementalDependencyStackRAII {
242-
IncrementalDependencyStackRAII(Evaluator &E, const Request &Req) {}
243-
};
244-
245-
template <typename Request>
246-
struct IncrementalDependencyStackRAII<
247-
Request, typename std::enable_if<Request::isDependencySource>::type> {
248-
NullablePtr<Evaluator> Eval;
249-
IncrementalDependencyStackRAII(Evaluator &E, const Request &Req) {
250-
auto Source = Req.readDependencySource(E);
251-
// If there is no source to introduce, bail. This can occur if
252-
// a request originates in the context of a module.
253-
if (!Source.getPointer()) {
254-
return;
255-
}
256-
E.dependencySources.emplace_back(Source);
257-
Eval = &E;
258-
}
259-
260-
~IncrementalDependencyStackRAII() {
261-
if (Eval.isNonNull())
262-
Eval.get()->dependencySources.pop_back();
263-
}
264-
};
228+
evaluator::DependencyCollector collector;
265229

266230
/// Retrieve the request function for the given zone and request IDs.
267231
AbstractRequestFunction *getAbstractRequestFunction(uint8_t zoneID,
@@ -303,7 +267,8 @@ class Evaluator {
303267
typename std::enable_if<Request::isEverCached>::type * = nullptr>
304268
llvm::Expected<typename Request::OutputType>
305269
operator()(const Request &request) {
306-
IncrementalDependencyStackRAII<Request> incDeps{*this, request};
270+
evaluator::DependencyCollector::StackRAII<Request> incDeps{collector,
271+
request};
307272
// The request can be cached, but check a predicate to determine
308273
// whether this particular instance is cached. This allows more
309274
// fine-grained control over which instances get cache.
@@ -319,7 +284,8 @@ class Evaluator {
319284
typename std::enable_if<!Request::isEverCached>::type * = nullptr>
320285
llvm::Expected<typename Request::OutputType>
321286
operator()(const Request &request) {
322-
IncrementalDependencyStackRAII<Request> incDeps{*this, request};
287+
evaluator::DependencyCollector::StackRAII<Request> incDeps{collector,
288+
request};
323289
return getResultUncached(request);
324290
}
325291

@@ -476,47 +442,7 @@ class Evaluator {
476442
typename std::enable_if<Request::isDependencySink>::type * = nullptr>
477443
void reportEvaluatedResult(const Request &r,
478444
const typename Request::OutputType &o) {
479-
if (auto *tracker = getActiveDependencyTracker())
480-
r.writeDependencySink(*this, *tracker, o);
481-
}
482-
483-
/// If there is an active dependency source, returns its
484-
/// \c ReferencedNameTracker. Else, returns \c nullptr.
485-
ReferencedNameTracker *getActiveDependencyTracker() const {
486-
if (auto *source = getActiveDependencySourceOrNull())
487-
return source->getRequestBasedReferencedNameTracker();
488-
return nullptr;
489-
}
490-
491-
public:
492-
/// Returns \c true if the scope of the current active source cascades.
493-
///
494-
/// If there is no active scope, the result always cascades.
495-
bool isActiveSourceCascading() const {
496-
return getActiveSourceScope() == evaluator::DependencyScope::Cascading;
497-
}
498-
499-
/// Returns the scope of the current active scope.
500-
///
501-
/// If there is no active scope, the result always cascades.
502-
evaluator::DependencyScope getActiveSourceScope() const {
503-
if (dependencySources.empty()) {
504-
return evaluator::DependencyScope::Cascading;
505-
}
506-
return dependencySources.back().getInt();
507-
}
508-
509-
/// Returns the active dependency's source file, or \c nullptr if no
510-
/// dependency source is active.
511-
///
512-
/// The use of this accessor is strongly discouraged, as it implies that a
513-
/// dependency sink is seeking to filter out names based on the files they
514-
/// come from. Existing callers are being migrated to more reasonable ways
515-
/// of judging the relevancy of a dependency.
516-
SourceFile *getActiveDependencySourceOrNull() const {
517-
if (dependencySources.empty())
518-
return nullptr;
519-
return dependencySources.back().getPointer();
445+
r.writeDependencySink(collector, o);
520446
}
521447

522448
public:

include/swift/AST/EvaluatorDependencies.h

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ namespace swift {
2626

2727
namespace evaluator {
2828

29+
namespace detail {
30+
// Remove this when the compiler bumps to C++17.
31+
template <typename...> using void_t = void;
32+
} // namespace detail
33+
2934
/// The "scope" of a dependency edge tracked by the evaluator.
3035
///
3136
/// Dependency scopes come in two flavors: cascading and private. A private
@@ -99,6 +104,123 @@ inline DependencyScope getScopeForAccessLevel(AccessLevel l) {
99104
// edges in the incremental dependency graph invalidate entire files instead
100105
// of individual contexts.
101106
using DependencySource = llvm::PointerIntPair<SourceFile *, 1, DependencyScope>;
107+
108+
/// A \c DependencyCollector is an aggregator of named references discovered in a
109+
/// particular \c DependencyScope during the course of request evaluation.
110+
struct DependencyCollector {
111+
private:
112+
/// A stack of dependency sources in the order they were evaluated.
113+
llvm::SmallVector<evaluator::DependencySource, 8> dependencySources;
114+
115+
public:
116+
DependencyCollector() = default;
117+
118+
public:
119+
/// Registers a named reference from the current dependency scope to a member
120+
/// defined in the given \p subject type.
121+
///
122+
/// Used member constraints are typically the by-product of direct lookups,
123+
/// where the name being looked up and the target of the lookup are known
124+
/// up front. A used member dependency causes the file to be rebuilt if the
125+
/// definition of that member changes in any way - via
126+
/// deletion, addition, or mutation of a member with that same name.
127+
void addUsedMember(NominalTypeDecl *subject, DeclBaseName name);
128+
/// Registers a reference from the current dependency scope to a
129+
/// "potential member" of the given \p subject type.
130+
///
131+
/// A single potential member dependency can be thought of as many used member
132+
/// dependencies - one for each current member of the subject type, but also
133+
/// one for every member that will be added or removed from the type in the
134+
/// future. As such, these dependencies cause rebuilds when any members are
135+
/// added, removed, or changed in the \p subject type. It also indicates a
136+
/// dependency on the \p subject type's existence, so deleting the \p subject
137+
/// type will also cause a rebuild.
138+
///
139+
/// These dependencies are most appropriate for protocol conformances,
140+
/// superclass constraints, and other requirements involving entire types.
141+
void addPotentialMember(NominalTypeDecl *subject);
142+
/// Registers a reference from the current dependency scope to a given
143+
/// top-level \p name.
144+
///
145+
/// A top level dependency causes a rebuild when another top-level entity with
146+
/// that name is added, removed, or modified.
147+
void addTopLevelName(DeclBaseName name);
148+
/// Registers a reference from the current dependency scope to a given
149+
/// dynamic member \p name.
150+
///
151+
/// A dynamic lookup dependency is a special kind of member dependency on
152+
/// a name that is found by \c AnyObject lookup.
153+
void addDynamicLookupName(DeclBaseName name);
154+
155+
public:
156+
/// Returns the scope of the current active scope.
157+
///
158+
/// If there is no active scope, the result always cascades.
159+
evaluator::DependencyScope getActiveSourceScope() const {
160+
if (dependencySources.empty()) {
161+
return evaluator::DependencyScope::Cascading;
162+
}
163+
return dependencySources.back().getInt();
164+
}
165+
166+
/// Returns the active dependency's source file, or \c nullptr if no
167+
/// dependency source is active.
168+
///
169+
/// The use of this accessor is strongly discouraged, as it implies that a
170+
/// dependency sink is seeking to filter out names based on the files they
171+
/// come from. Existing callers are being migrated to more reasonable ways
172+
/// of judging the relevancy of a dependency.
173+
SourceFile *getActiveDependencySourceOrNull() const {
174+
if (dependencySources.empty())
175+
return nullptr;
176+
return dependencySources.back().getPointer();
177+
}
178+
179+
public:
180+
/// An RAII type that manages manipulating the evaluator's
181+
/// dependency source stack. It is specialized to be zero-cost for
182+
/// requests that are not dependency sources.
183+
template <typename Request, typename = detail::void_t<>> struct StackRAII {
184+
StackRAII(DependencyCollector &DC, const Request &Req) {}
185+
};
186+
187+
template <typename Request>
188+
struct StackRAII<Request,
189+
typename std::enable_if<Request::isDependencySource>::type> {
190+
NullablePtr<DependencyCollector> Coll;
191+
StackRAII(DependencyCollector &coll, const Request &Req) {
192+
auto Source = Req.readDependencySource(coll);
193+
// If there is no source to introduce, bail. This can occur if
194+
// a request originates in the context of a module.
195+
if (!Source.getPointer()) {
196+
return;
197+
}
198+
coll.dependencySources.emplace_back(Source);
199+
Coll = &coll;
200+
}
201+
202+
~StackRAII() {
203+
if (Coll.isNonNull())
204+
Coll.get()->dependencySources.pop_back();
205+
}
206+
};
207+
208+
private:
209+
/// If there is an active dependency source, returns its
210+
/// \c ReferencedNameTracker. Else, returns \c nullptr.
211+
ReferencedNameTracker *getActiveDependencyTracker() const {
212+
if (auto *source = getActiveDependencySourceOrNull())
213+
return source->getRequestBasedReferencedNameTracker();
214+
return nullptr;
215+
}
216+
217+
/// Returns \c true if the scope of the current active source cascades.
218+
///
219+
/// If there is no active scope, the result always cascades.
220+
bool isActiveSourceCascading() const {
221+
return getActiveSourceScope() == evaluator::DependencyScope::Cascading;
222+
}
223+
};
102224
} // end namespace evaluator
103225

104226
} // end namespace swift

include/swift/AST/IRGenRequests.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ class IRGenSourceFileRequest
199199

200200
public:
201201
// Incremental dependencies.
202-
evaluator::DependencySource readDependencySource(Evaluator &) const;
202+
evaluator::DependencySource
203+
readDependencySource(const evaluator::DependencyCollector &) const;
203204
};
204205

205206
class IRGenWholeModuleRequest

include/swift/AST/NameLookupRequests.h

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,9 @@ class InheritedProtocolsRequest
188188

189189
public:
190190
// Incremental dependencies
191-
evaluator::DependencySource readDependencySource(Evaluator &e) const;
192-
void writeDependencySink(Evaluator &evaluator, ReferencedNameTracker &tracker,
191+
evaluator::DependencySource
192+
readDependencySource(const evaluator::DependencyCollector &e) const;
193+
void writeDependencySink(evaluator::DependencyCollector &tracker,
193194
ArrayRef<ProtocolDecl *> result) const;
194195
};
195196

@@ -239,7 +240,7 @@ class ExtendedNominalRequest
239240

240241
public:
241242
// Incremental dependencies
242-
void writeDependencySink(Evaluator &evaluator, ReferencedNameTracker &tracker,
243+
void writeDependencySink(evaluator::DependencyCollector &tracker,
243244
NominalTypeDecl *result) const;
244245
};
245246

@@ -328,7 +329,8 @@ class GetDestructorRequest
328329

329330
public:
330331
// Incremental dependencies.
331-
evaluator::DependencySource readDependencySource(Evaluator &) const;
332+
evaluator::DependencySource
333+
readDependencySource(const evaluator::DependencyCollector &) const;
332334
};
333335

334336
class GenericParamListRequest :
@@ -431,8 +433,9 @@ class UnqualifiedLookupRequest
431433

432434
public:
433435
// Incremental dependencies
434-
evaluator::DependencySource readDependencySource(Evaluator &) const;
435-
void writeDependencySink(Evaluator &eval, ReferencedNameTracker &tracker,
436+
evaluator::DependencySource
437+
readDependencySource(const evaluator::DependencyCollector &) const;
438+
void writeDependencySink(evaluator::DependencyCollector &tracker,
436439
LookupResult res) const;
437440
};
438441

@@ -477,7 +480,7 @@ class AnyObjectLookupRequest
477480

478481
public:
479482
// Incremental dependencies
480-
void writeDependencySink(Evaluator &eval, ReferencedNameTracker &tracker,
483+
void writeDependencySink(evaluator::DependencyCollector &tracker,
481484
QualifiedLookupResult l) const;
482485
};
483486

@@ -502,8 +505,9 @@ class ModuleQualifiedLookupRequest
502505

503506
public:
504507
// Incremental dependencies
505-
evaluator::DependencySource readDependencySource(Evaluator &) const;
506-
void writeDependencySink(Evaluator &eval, ReferencedNameTracker &tracker,
508+
evaluator::DependencySource
509+
readDependencySource(const evaluator::DependencyCollector &) const;
510+
void writeDependencySink(evaluator::DependencyCollector &tracker,
507511
QualifiedLookupResult lookupResult) const;
508512
};
509513

@@ -528,7 +532,8 @@ class QualifiedLookupRequest
528532

529533
public:
530534
// Incremental dependencies.
531-
evaluator::DependencySource readDependencySource(Evaluator &) const;
535+
evaluator::DependencySource
536+
readDependencySource(const evaluator::DependencyCollector &) const;
532537
};
533538

534539
/// The input type for a direct lookup request.
@@ -580,7 +585,7 @@ class DirectLookupRequest
580585

581586
public:
582587
// Incremental dependencies
583-
void writeDependencySink(Evaluator &evaluator, ReferencedNameTracker &tracker,
588+
void writeDependencySink(evaluator::DependencyCollector &tracker,
584589
TinyPtrVector<ValueDecl *> result) const;
585590
};
586591

@@ -665,7 +670,7 @@ class LookupOperatorRequest
665670

666671
public:
667672
// Incremental dependencies
668-
void writeDependencySink(Evaluator &evaluator, ReferencedNameTracker &tracker,
673+
void writeDependencySink(evaluator::DependencyCollector &tracker,
669674
OperatorType *o) const;
670675
};
671676

@@ -755,7 +760,7 @@ class LookupConformanceInModuleRequest
755760

756761
public:
757762
// Incremental dependencies
758-
void writeDependencySink(Evaluator &evaluator, ReferencedNameTracker &tracker,
763+
void writeDependencySink(evaluator::DependencyCollector &tracker,
759764
ProtocolConformanceRef result) const;
760765
};
761766

include/swift/AST/ParseRequests.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ class ParseSourceFileRequest
102102
void cacheResult(ArrayRef<Decl *> decls) const;
103103

104104
public:
105-
evaluator::DependencySource readDependencySource(Evaluator &) const;
105+
evaluator::DependencySource
106+
readDependencySource(const evaluator::DependencyCollector &) const;
106107
};
107108

108109
void simple_display(llvm::raw_ostream &out,
@@ -123,7 +124,8 @@ class CodeCompletionSecondPassRequest
123124
CodeCompletionCallbacksFactory *Factory) const;
124125

125126
public:
126-
evaluator::DependencySource readDependencySource(Evaluator &) const;
127+
evaluator::DependencySource
128+
readDependencySource(const evaluator::DependencyCollector &) const;
127129
};
128130

129131
/// The zone number for the parser.

include/swift/AST/SILGenRequests.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ class SILGenSourceFileRequest :
9898

9999
public:
100100
// Incremental dependencies.
101-
evaluator::DependencySource readDependencySource(Evaluator &) const;
101+
evaluator::DependencySource
102+
readDependencySource(const evaluator::DependencyCollector &) const;
102103
};
103104

104105
class SILGenWholeModuleRequest :

0 commit comments

Comments
 (0)