2121#include " swift/AST/AnyRequest.h"
2222#include " swift/AST/AttrKind.h"
2323#include " swift/AST/SourceFile.h"
24+ #include " swift/Basic/NullablePtr.h"
2425#include " llvm/ADT/PointerIntPair.h"
2526
2627namespace swift {
@@ -32,80 +33,13 @@ namespace detail {
3233template <typename ...> using void_t = void ;
3334} // namespace detail
3435
35- // / The "scope" of a dependency edge tracked by the evaluator.
36- // /
37- // / Dependency scopes come in two flavors: cascading and private. A private
38- // / edge captures dependencies discovered in contexts that are not visible to
39- // / to other files. For example, a conformance to a private protocol, or the use
40- // / of any names inside of a function body. A cascading edge, by contrast,
41- // / captures dependencies discovered in the remaining visible contexts. These
42- // / are types with at least \c internal visibility, names defined or used
43- // / outside of function bodies with at least \c internal visibility, etc. A
44- // / dependency that has cascading scope is so-named because upon traversing the
45- // / edge, a reader such as the driver should continue transitively evaluating
46- // / further dependency edges.
47- // /
48- // / A cascading edge is always conservatively correct to produce, but it comes
49- // / at the cost of increased resources spent (and possibly even wasted!) during
50- // / incremental compilation. A private edge, by contrast, is more efficient for
51- // / incremental compilation but it is harder to safely use.
52- // /
53- // / To ensure that these edges are registered consistently with the correct
54- // / scopes, requests that act as the source of dependency edges are required
55- // / to specify a \c DependencyScope under which all evaluated sub-requests will
56- // / register their dependency edges. In this way, \c DependencyScope values
57- // / form a stack-like structure and are pushed and popped by the evaluator
58- // / during the course of request evaluation.
59- // /
60- // / When determining the kind of scope a request should use, always err on the
61- // / side of a cascading scope unless there is absolute proof any discovered
62- // / dependencies will be private. Inner requests may also defensively choose to
63- // / flip the dependency scope from private to cascading in the name of safety.
64- enum class DependencyScope : bool {
65- Private = false ,
66- Cascading = true ,
67- };
68-
69- // / Returns a \c DependencyScope appropriate for the given (formal) access level.
70- // /
71- // / :warning: This function exists to bridge the old manual reference
72- // / dependencies code to the new evaluator-based reference dependencies code.
73- // / The manual code often made private/cascading scope judgements based on the
74- // / access level of a declaration. While this makes some sense intuitively, it
75- // / does not necessarily capture an accurate picture of where real incremental
76- // / dependencies lie. For example, references to formally private types can
77- // / "escape" to contexts that have no reference to the private name if, say,
78- // / the layout of that private type is taken into consideration by
79- // / SILGen or IRGen in a separate file that references the declaration
80- // / transitively. However, due to the density of the current dependency
81- // / graph, redundancy in registered dependency edges, and the liberal use of
82- // / cascading edges, we may be saved from the worst consequences of this
83- // / modelling choice.
84- // /
85- // / The use of access-levels for dependency decisions is an anti-pattern that
86- // / should be revisited once finer-grained dependencies are explored more
87- // / thoroughly.
88- inline DependencyScope getScopeForAccessLevel (AccessLevel l) {
89- switch (l) {
90- case AccessLevel::Private:
91- case AccessLevel::FilePrivate:
92- return DependencyScope::Private;
93- case AccessLevel::Internal:
94- case AccessLevel::Public:
95- case AccessLevel::Open:
96- return DependencyScope::Cascading;
97- }
98- llvm_unreachable (" invalid access level kind" );
99- }
100-
101- // A \c DependencySource is currently defined to be a parent source file and
102- // an associated dependency scope.
36+ // A \c DependencySource is currently defined to be a primary source file.
10337//
10438// The \c SourceFile instance is an artifact of the current dependency system,
10539// and should be scrapped if possible. It currently encodes the idea that
10640// edges in the incremental dependency graph invalidate entire files instead
10741// of individual contexts.
108- using DependencySource = llvm::PointerIntPair <SourceFile *, 1 , DependencyScope >;
42+ using DependencySource = swift::NullablePtr <SourceFile>;
10943
11044struct DependencyRecorder ;
11145
@@ -133,41 +67,38 @@ struct DependencyCollector {
13367
13468 NominalTypeDecl *subject;
13569 DeclBaseName name;
136- bool cascades;
13770
13871 private:
139- Reference (Kind kind, NominalTypeDecl *subject, DeclBaseName name,
140- bool cascades)
141- : kind(kind), subject(subject), name(name), cascades(cascades) {}
72+ Reference (Kind kind, NominalTypeDecl *subject, DeclBaseName name)
73+ : kind(kind), subject(subject), name(name) {}
14274
14375 public:
14476 static Reference empty () {
14577 return {Kind::Empty, llvm::DenseMapInfo<NominalTypeDecl *>::getEmptyKey (),
146- llvm::DenseMapInfo<DeclBaseName>::getEmptyKey (), false };
78+ llvm::DenseMapInfo<DeclBaseName>::getEmptyKey ()};
14779 }
14880
14981 static Reference tombstone () {
15082 return {Kind::Tombstone,
15183 llvm::DenseMapInfo<NominalTypeDecl *>::getTombstoneKey (),
152- llvm::DenseMapInfo<DeclBaseName>::getTombstoneKey (), false };
84+ llvm::DenseMapInfo<DeclBaseName>::getTombstoneKey ()};
15385 }
15486
15587 public:
156- static Reference usedMember (NominalTypeDecl *subject, DeclBaseName name,
157- bool cascades) {
158- return {Kind::UsedMember, subject, name, cascades};
88+ static Reference usedMember (NominalTypeDecl *subject, DeclBaseName name) {
89+ return {Kind::UsedMember, subject, name};
15990 }
16091
161- static Reference potentialMember (NominalTypeDecl *subject, bool cascades ) {
162- return {Kind::PotentialMember, subject, DeclBaseName (), cascades };
92+ static Reference potentialMember (NominalTypeDecl *subject) {
93+ return {Kind::PotentialMember, subject, DeclBaseName ()};
16394 }
16495
165- static Reference topLevel (DeclBaseName name, bool cascades ) {
166- return {Kind::TopLevel, nullptr , name, cascades };
96+ static Reference topLevel (DeclBaseName name) {
97+ return {Kind::TopLevel, nullptr , name};
16798 }
16899
169- static Reference dynamic (DeclBaseName name, bool cascades ) {
170- return {Kind::Dynamic, nullptr , name, cascades };
100+ static Reference dynamic (DeclBaseName name) {
101+ return {Kind::Dynamic, nullptr , name};
171102 }
172103
173104 public:
@@ -248,34 +179,17 @@ struct DependencyCollector {
248179struct DependencyRecorder {
249180 friend DependencyCollector;
250181
251- enum class Mode {
252- // Enables the status quo of recording direct dependencies.
253- //
254- // This mode restricts the dependency collector to ignore changes of
255- // scope. This has practical effect of charging all unqualified lookups to
256- // the primary file being acted upon instead of to the destination file.
257- DirectDependencies,
258- // Enables a legacy mode of dependency tracking that makes a distinction
259- // between private and cascading edges, and does not directly capture
260- // transitive dependencies.
261- //
262- // By default, the dependency collector moves to register dependencies in
263- // the referenced name trackers at the top of the active dependency stack.
264- LegacyCascadingDependencies,
265- };
266-
267182private:
268183 // / A stack of dependency sources in the order they were evaluated.
269184 llvm::SmallVector<evaluator::DependencySource, 8 > dependencySources;
270185 llvm::DenseMap<SourceFile *, DependencyCollector::ReferenceSet>
271186 fileReferences;
272187 llvm::DenseMap<AnyRequest, DependencyCollector::ReferenceSet>
273188 requestReferences;
274- Mode mode;
275189 bool isRecording;
276190
277191public:
278- explicit DependencyRecorder (Mode mode ) : mode{mode}, isRecording{false } {};
192+ explicit DependencyRecorder () : isRecording{false } {};
279193
280194private:
281195 // / Records the given \c Reference as a dependency of the current dependency
@@ -338,32 +252,17 @@ struct DependencyRecorder {
338252 ReferenceEnumerator f) const ;
339253
340254public:
341- // / Returns the scope of the current active scope.
342- // /
343- // / If there is no active scope, the result always cascades.
344- evaluator::DependencyScope getActiveSourceScope () const {
345- if (dependencySources.empty ()) {
346- return evaluator::DependencyScope::Cascading;
347- }
348- return dependencySources.back ().getInt ();
349- }
350-
351255 // / Returns the active dependency's source file, or \c nullptr if no
352256 // / dependency source is active.
353257 // /
354258 // / The use of this accessor is strongly discouraged, as it implies that a
355259 // / dependency sink is seeking to filter out names based on the files they
356260 // / come from. Existing callers are being migrated to more reasonable ways
357261 // / of judging the relevancy of a dependency.
358- SourceFile * getActiveDependencySourceOrNull () const {
262+ evaluator::DependencySource getActiveDependencySourceOrNull () const {
359263 if (dependencySources.empty ())
360264 return nullptr ;
361- switch (mode) {
362- case Mode::LegacyCascadingDependencies:
363- return dependencySources.back ().getPointer ();
364- case Mode::DirectDependencies:
365- return dependencySources.front ().getPointer ();
366- }
265+ return dependencySources.front ();
367266 }
368267
369268public:
@@ -382,7 +281,7 @@ struct DependencyRecorder {
382281 auto Source = Req.readDependencySource (coll);
383282 // If there is no source to introduce, bail. This can occur if
384283 // a request originates in the context of a module.
385- if (!Source.getPointer ()) {
284+ if (Source. isNull () || !Source.get ()-> isPrimary ()) {
386285 return ;
387286 }
388287 coll.dependencySources .emplace_back (Source);
@@ -394,20 +293,6 @@ struct DependencyRecorder {
394293 Coll.get ()->dependencySources .pop_back ();
395294 }
396295 };
397-
398- private:
399- // / Returns \c true if the scope of the current active source cascades.
400- // /
401- // / If there is no active scope, the result always cascades.
402- bool isActiveSourceCascading () const {
403- switch (mode) {
404- case Mode::LegacyCascadingDependencies:
405- return getActiveSourceScope () == evaluator::DependencyScope::Cascading;
406- case Mode::DirectDependencies:
407- return false ;
408- }
409- llvm_unreachable (" invalid mode" );
410- }
411296};
412297} // end namespace evaluator
413298
0 commit comments