21
21
#include " swift/AST/AnyRequest.h"
22
22
#include " swift/AST/AttrKind.h"
23
23
#include " swift/AST/SourceFile.h"
24
+ #include " swift/Basic/NullablePtr.h"
24
25
#include " llvm/ADT/PointerIntPair.h"
25
26
26
27
namespace swift {
@@ -32,80 +33,13 @@ namespace detail {
32
33
template <typename ...> using void_t = void ;
33
34
} // namespace detail
34
35
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.
103
37
//
104
38
// The \c SourceFile instance is an artifact of the current dependency system,
105
39
// and should be scrapped if possible. It currently encodes the idea that
106
40
// edges in the incremental dependency graph invalidate entire files instead
107
41
// of individual contexts.
108
- using DependencySource = llvm::PointerIntPair <SourceFile *, 1 , DependencyScope >;
42
+ using DependencySource = swift::NullablePtr <SourceFile>;
109
43
110
44
struct DependencyRecorder ;
111
45
@@ -133,41 +67,38 @@ struct DependencyCollector {
133
67
134
68
NominalTypeDecl *subject;
135
69
DeclBaseName name;
136
- bool cascades;
137
70
138
71
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) {}
142
74
143
75
public:
144
76
static Reference empty () {
145
77
return {Kind::Empty, llvm::DenseMapInfo<NominalTypeDecl *>::getEmptyKey (),
146
- llvm::DenseMapInfo<DeclBaseName>::getEmptyKey (), false };
78
+ llvm::DenseMapInfo<DeclBaseName>::getEmptyKey ()};
147
79
}
148
80
149
81
static Reference tombstone () {
150
82
return {Kind::Tombstone,
151
83
llvm::DenseMapInfo<NominalTypeDecl *>::getTombstoneKey (),
152
- llvm::DenseMapInfo<DeclBaseName>::getTombstoneKey (), false };
84
+ llvm::DenseMapInfo<DeclBaseName>::getTombstoneKey ()};
153
85
}
154
86
155
87
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};
159
90
}
160
91
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 ()};
163
94
}
164
95
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};
167
98
}
168
99
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};
171
102
}
172
103
173
104
public:
@@ -248,34 +179,17 @@ struct DependencyCollector {
248
179
struct DependencyRecorder {
249
180
friend DependencyCollector;
250
181
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
-
267
182
private:
268
183
// / A stack of dependency sources in the order they were evaluated.
269
184
llvm::SmallVector<evaluator::DependencySource, 8 > dependencySources;
270
185
llvm::DenseMap<SourceFile *, DependencyCollector::ReferenceSet>
271
186
fileReferences;
272
187
llvm::DenseMap<AnyRequest, DependencyCollector::ReferenceSet>
273
188
requestReferences;
274
- Mode mode;
275
189
bool isRecording;
276
190
277
191
public:
278
- explicit DependencyRecorder (Mode mode ) : mode{mode}, isRecording{false } {};
192
+ explicit DependencyRecorder () : isRecording{false } {};
279
193
280
194
private:
281
195
// / Records the given \c Reference as a dependency of the current dependency
@@ -338,32 +252,17 @@ struct DependencyRecorder {
338
252
ReferenceEnumerator f) const ;
339
253
340
254
public:
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
-
351
255
// / Returns the active dependency's source file, or \c nullptr if no
352
256
// / dependency source is active.
353
257
// /
354
258
// / The use of this accessor is strongly discouraged, as it implies that a
355
259
// / dependency sink is seeking to filter out names based on the files they
356
260
// / come from. Existing callers are being migrated to more reasonable ways
357
261
// / of judging the relevancy of a dependency.
358
- SourceFile * getActiveDependencySourceOrNull () const {
262
+ evaluator::DependencySource getActiveDependencySourceOrNull () const {
359
263
if (dependencySources.empty ())
360
264
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 ();
367
266
}
368
267
369
268
public:
@@ -382,7 +281,7 @@ struct DependencyRecorder {
382
281
auto Source = Req.readDependencySource (coll);
383
282
// If there is no source to introduce, bail. This can occur if
384
283
// a request originates in the context of a module.
385
- if (!Source.getPointer ()) {
284
+ if (Source. isNull () || !Source.get ()-> isPrimary ()) {
386
285
return ;
387
286
}
388
287
coll.dependencySources .emplace_back (Source);
@@ -394,20 +293,6 @@ struct DependencyRecorder {
394
293
Coll.get ()->dependencySources .pop_back ();
395
294
}
396
295
};
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
- }
411
296
};
412
297
} // end namespace evaluator
413
298
0 commit comments