19
19
#define SWIFT_AST_EVALUATOR_DEPENDENCIES_H
20
20
21
21
#include " swift/AST/AnyRequest.h"
22
- #include " swift/AST/AttrKind.h"
23
- #include " swift/AST/SourceFile.h"
22
+ #include " swift/AST/DependencyCollector.h"
24
23
#include " swift/Basic/NullablePtr.h"
25
- #include " llvm/ADT/PointerIntPair.h"
24
+ #include " llvm/ADT/DenseMap.h"
25
+ #include " llvm/ADT/DenseSet.h"
26
26
#include < vector>
27
27
28
28
namespace swift {
29
29
30
+ class SourceFile ;
31
+
30
32
namespace evaluator {
31
33
32
34
namespace detail {
@@ -42,160 +44,64 @@ template <typename...> using void_t = void;
42
44
// of individual contexts.
43
45
using DependencySource = swift::NullablePtr<SourceFile>;
44
46
45
- struct DependencyRecorder ;
46
-
47
- // / A \c DependencyCollector defines an abstract write-only buffer of
48
- // / \c Reference objects. References are added to a collector during the write
49
- // / phase of request evaluation (in \c writeDependencySink) with the various
50
- // / \c add* functions below..
51
- // /
52
- // / A \c DependencyCollector cannot be created directly. You must invoke
53
- // / \c DependencyRecorder::record, which will wire a dependency collector into
54
- // / the provided continuation block.
55
- struct DependencyCollector {
56
- friend DependencyRecorder;
57
-
58
- struct Reference {
59
- public:
60
- enum class Kind {
61
- Empty,
62
- Tombstone,
63
- UsedMember,
64
- PotentialMember,
65
- TopLevel,
66
- Dynamic,
67
- } kind;
68
-
69
- NominalTypeDecl *subject;
70
- DeclBaseName name;
71
-
72
- private:
73
- Reference (Kind kind, NominalTypeDecl *subject, DeclBaseName name)
74
- : kind(kind), subject(subject), name(name) {}
75
-
76
- public:
77
- static Reference empty () {
78
- return {Kind::Empty, llvm::DenseMapInfo<NominalTypeDecl *>::getEmptyKey (),
79
- llvm::DenseMapInfo<DeclBaseName>::getEmptyKey ()};
80
- }
81
-
82
- static Reference tombstone () {
83
- return {Kind::Tombstone,
84
- llvm::DenseMapInfo<NominalTypeDecl *>::getTombstoneKey (),
85
- llvm::DenseMapInfo<DeclBaseName>::getTombstoneKey ()};
86
- }
87
-
88
- public:
89
- static Reference usedMember (NominalTypeDecl *subject, DeclBaseName name) {
90
- return {Kind::UsedMember, subject, name};
91
- }
92
-
93
- static Reference potentialMember (NominalTypeDecl *subject) {
94
- return {Kind::PotentialMember, subject, DeclBaseName ()};
95
- }
96
-
97
- static Reference topLevel (DeclBaseName name) {
98
- return {Kind::TopLevel, nullptr , name};
99
- }
100
-
101
- static Reference dynamic (DeclBaseName name) {
102
- return {Kind::Dynamic, nullptr , name};
103
- }
104
-
105
- public:
106
- struct Info {
107
- static inline Reference getEmptyKey () { return Reference::empty (); }
108
- static inline Reference getTombstoneKey () {
109
- return Reference::tombstone ();
110
- }
111
- static inline unsigned getHashValue (const Reference &Val) {
112
- return llvm::hash_combine (Val.kind , Val.subject ,
113
- Val.name .getAsOpaquePointer ());
114
- }
115
- static bool isEqual (const Reference &LHS, const Reference &RHS) {
116
- return LHS.kind == RHS.kind && LHS.subject == RHS.subject &&
117
- LHS.name == RHS.name ;
118
- }
119
- };
120
- };
121
-
122
- private:
123
- DependencyRecorder &parent;
124
-
125
- public:
126
- explicit DependencyCollector (DependencyRecorder &parent);
127
- ~DependencyCollector ();
128
-
129
- public:
130
- // / Registers a named reference from the current dependency scope to a member
131
- // / defined in the given \p subject type.
132
- // /
133
- // / Used member constraints are typically the by-product of direct lookups,
134
- // / where the name being looked up and the target of the lookup are known
135
- // / up front. A used member dependency causes the file to be rebuilt if the
136
- // / definition of that member changes in any way - via
137
- // / deletion, addition, or mutation of a member with that same name.
138
- void addUsedMember (NominalTypeDecl *subject, DeclBaseName name);
139
- // / Registers a reference from the current dependency scope to a
140
- // / "potential member" of the given \p subject type.
141
- // /
142
- // / A single potential member dependency can be thought of as many used member
143
- // / dependencies - one for each current member of the subject type, but also
144
- // / one for every member that will be added or removed from the type in the
145
- // / future. As such, these dependencies cause rebuilds when any members are
146
- // / added, removed, or changed in the \p subject type. It also indicates a
147
- // / dependency on the \p subject type's existence, so deleting the \p subject
148
- // / type will also cause a rebuild.
149
- // /
150
- // / These dependencies are most appropriate for protocol conformances,
151
- // / superclass constraints, and other requirements involving entire types.
152
- void addPotentialMember (NominalTypeDecl *subject);
153
- // / Registers a reference from the current dependency scope to a given
154
- // / top-level \p name.
155
- // /
156
- // / A top level dependency causes a rebuild when another top-level entity with
157
- // / that name is added, removed, or modified.
158
- void addTopLevelName (DeclBaseName name);
159
- // / Registers a reference from the current dependency scope to a given
160
- // / dynamic member \p name.
161
- // /
162
- // / A dynamic lookup dependency is a special kind of member dependency on
163
- // / a name that is found by \c AnyObject lookup.
164
- void addDynamicLookupName (DeclBaseName name);
165
-
166
- public:
167
- // / Retrieves the dependency recorder that created this dependency collector.
168
- const DependencyRecorder &getRecorder () const { return parent; }
169
- };
170
-
171
47
// / A \c DependencyRecorder is an aggregator of named references discovered in a
172
48
// / particular \c DependencyScope during the course of request evaluation.
173
49
struct DependencyRecorder {
174
50
friend DependencyCollector;
175
51
176
52
private:
53
+ // / References recorded while evaluating a dependency source request for each
54
+ // / source file. This map is updated upon completion of a dependency source
55
+ // / request, and includes all references from each downstream request as well.
177
56
llvm::DenseMap<SourceFile *,
178
57
llvm::DenseSet<DependencyCollector::Reference,
179
58
DependencyCollector::Reference::Info>>
180
59
fileReferences;
60
+
61
+ // / References recorded while evaluating each request. This map is populated
62
+ // / upon completion of each request, and includes all references from each
63
+ // / downstream request as well. Note that uncached requests don't appear as
64
+ // / keys in this map; their references are charged to the innermost cached
65
+ // / active request.
181
66
llvm::DenseMap<AnyRequest, std::vector<DependencyCollector::Reference>>
182
67
requestReferences;
68
+
69
+ // / Stack of references from each cached active request. When evaluating a
70
+ // / dependency sink request, we update the innermost set of references.
71
+ // / Upon completion of a request, we union the completed request's references
72
+ // / with the next innermost active request.
183
73
std::vector<llvm::DenseSet<DependencyCollector::Reference,
184
74
DependencyCollector::Reference::Info>>
185
75
activeRequestReferences;
186
76
187
77
#ifndef NDEBUG
78
+ // / Used to catch places where a request's writeDependencySink() method
79
+ // / kicks off another request, which would break invariants, so we
80
+ // / disallow this from happening.
188
81
bool isRecording = false ;
189
82
#endif
190
83
191
84
public:
85
+ // / Push a new empty set onto the activeRequestReferences stack.
192
86
void beginRequest (const swift::ActiveRequest &req);
87
+
88
+ // / Pop the activeRequestReferences stack, and insert recorded references
89
+ // / into the requestReferences map, as well as the next innermost entry in
90
+ // / activeRequestReferences.
193
91
void endRequest (const swift::ActiveRequest &req);
92
+
93
+ // / When replaying a request whose value has already been cached, we need
94
+ // / to update the innermost set in the activeRequestReferences stack.
194
95
void replayCachedRequest (const swift::ActiveRequest &req);
96
+
97
+ // / Upon completion of a dependency source request, we update the
98
+ // / fileReferences map.
195
99
void handleDependencySourceRequest (const swift::ActiveRequest &req,
196
100
SourceFile *source);
197
101
198
102
private:
103
+ // / Add an entry to the innermost set on the activeRequestReferences stack.
104
+ // / Called from the DependencyCollector.
199
105
void recordDependency (const DependencyCollector::Reference &ref);
200
106
201
107
public:
@@ -205,6 +111,10 @@ struct DependencyRecorder {
205
111
// / Enumerates the set of references associated with a given source file,
206
112
// / passing them to the given enumeration callback.
207
113
// /
114
+ // / Only makes sense to call once all dependency sources associated with this
115
+ // / source file have already been evaluated, otherwise the map will obviously
116
+ // / be incomplete.
117
+ // /
208
118
// / The order of enumeration is completely undefined. It is the responsibility
209
119
// / of callers to ensure they are order-invariant or are sorting the result.
210
120
void enumerateReferencesInFile (const SourceFile *SF,
0 commit comments