Skip to content

Commit c4c27f6

Browse files
authored
Merge pull request swiftlang#35205 from slavapestov/nfc-evaluator-cleanup
Small NFC request evaluator cleanup
2 parents ad2873d + e675bee commit c4c27f6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+244
-134
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
//===--- DependencyCollector.h -------------------------------- -*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines a class for recording incremental dependencies.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_AST_DEPENDENCY_COLLECTOR_H
18+
#define SWIFT_AST_DEPENDENCY_COLLECTOR_H
19+
20+
#include "swift/AST/Identifier.h"
21+
#include "llvm/ADT/DenseMap.h"
22+
#include "llvm/ADT/DenseSet.h"
23+
24+
namespace swift {
25+
26+
class NominalTypeDecl;
27+
28+
namespace evaluator {
29+
30+
struct DependencyRecorder;
31+
32+
/// A \c DependencyCollector defines an abstract write-only buffer of
33+
/// \c Reference objects. References are added to a collector during the write
34+
/// phase of request evaluation (in \c writeDependencySink) with the various
35+
/// \c add* functions below.
36+
///
37+
/// A \c DependencyCollector should not be created directly; instances are
38+
/// vended by the request evaluator infrastructure itself.
39+
struct DependencyCollector {
40+
friend DependencyRecorder;
41+
42+
struct Reference {
43+
public:
44+
enum class Kind {
45+
Empty,
46+
Tombstone,
47+
UsedMember,
48+
PotentialMember,
49+
TopLevel,
50+
Dynamic,
51+
} kind;
52+
53+
NominalTypeDecl *subject;
54+
DeclBaseName name;
55+
56+
private:
57+
Reference(Kind kind, NominalTypeDecl *subject, DeclBaseName name)
58+
: kind(kind), subject(subject), name(name) {}
59+
60+
public:
61+
static Reference empty() {
62+
return {Kind::Empty, llvm::DenseMapInfo<NominalTypeDecl *>::getEmptyKey(),
63+
llvm::DenseMapInfo<DeclBaseName>::getEmptyKey()};
64+
}
65+
66+
static Reference tombstone() {
67+
return {Kind::Tombstone,
68+
llvm::DenseMapInfo<NominalTypeDecl *>::getTombstoneKey(),
69+
llvm::DenseMapInfo<DeclBaseName>::getTombstoneKey()};
70+
}
71+
72+
public:
73+
static Reference usedMember(NominalTypeDecl *subject, DeclBaseName name) {
74+
return {Kind::UsedMember, subject, name};
75+
}
76+
77+
static Reference potentialMember(NominalTypeDecl *subject) {
78+
return {Kind::PotentialMember, subject, DeclBaseName()};
79+
}
80+
81+
static Reference topLevel(DeclBaseName name) {
82+
return {Kind::TopLevel, nullptr, name};
83+
}
84+
85+
static Reference dynamic(DeclBaseName name) {
86+
return {Kind::Dynamic, nullptr, name};
87+
}
88+
89+
public:
90+
struct Info {
91+
static inline Reference getEmptyKey() { return Reference::empty(); }
92+
static inline Reference getTombstoneKey() {
93+
return Reference::tombstone();
94+
}
95+
static inline unsigned getHashValue(const Reference &Val) {
96+
return llvm::hash_combine(Val.kind, Val.subject,
97+
Val.name.getAsOpaquePointer());
98+
}
99+
static bool isEqual(const Reference &LHS, const Reference &RHS) {
100+
return LHS.kind == RHS.kind && LHS.subject == RHS.subject &&
101+
LHS.name == RHS.name;
102+
}
103+
};
104+
};
105+
106+
private:
107+
DependencyRecorder &parent;
108+
109+
public:
110+
explicit DependencyCollector(DependencyRecorder &parent);
111+
~DependencyCollector();
112+
113+
public:
114+
/// Registers a named reference from the current dependency scope to a member
115+
/// defined in the given \p subject type.
116+
///
117+
/// Used member constraints are typically the by-product of direct lookups,
118+
/// where the name being looked up and the target of the lookup are known
119+
/// up front. A used member dependency causes the file to be rebuilt if the
120+
/// definition of that member changes in any way - via
121+
/// deletion, addition, or mutation of a member with that same name.
122+
void addUsedMember(NominalTypeDecl *subject, DeclBaseName name);
123+
/// Registers a reference from the current dependency scope to a
124+
/// "potential member" of the given \p subject type.
125+
///
126+
/// A single potential member dependency can be thought of as many used member
127+
/// dependencies - one for each current member of the subject type, but also
128+
/// one for every member that will be added or removed from the type in the
129+
/// future. As such, these dependencies cause rebuilds when any members are
130+
/// added, removed, or changed in the \p subject type. It also indicates a
131+
/// dependency on the \p subject type's existence, so deleting the \p subject
132+
/// type will also cause a rebuild.
133+
///
134+
/// These dependencies are most appropriate for protocol conformances,
135+
/// superclass constraints, and other requirements involving entire types.
136+
void addPotentialMember(NominalTypeDecl *subject);
137+
/// Registers a reference from the current dependency scope to a given
138+
/// top-level \p name.
139+
///
140+
/// A top level dependency causes a rebuild when another top-level entity with
141+
/// that name is added, removed, or modified.
142+
void addTopLevelName(DeclBaseName name);
143+
/// Registers a reference from the current dependency scope to a given
144+
/// dynamic member \p name.
145+
///
146+
/// A dynamic lookup dependency is a special kind of member dependency on
147+
/// a name that is found by \c AnyObject lookup.
148+
void addDynamicLookupName(DeclBaseName name);
149+
150+
public:
151+
/// Retrieves the dependency recorder that created this dependency collector.
152+
const DependencyRecorder &getRecorder() const { return parent; }
153+
};
154+
155+
} // end namespace evaluator
156+
157+
} // end namespace swift
158+
159+
#endif // SWIFT_AST_DEPENDENCY_COLLECTOR_H

include/swift/AST/Evaluator.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,9 @@
2222
#include "swift/AST/EvaluatorDependencies.h"
2323
#include "swift/Basic/AnyValue.h"
2424
#include "swift/Basic/Debug.h"
25-
#include "swift/Basic/Defer.h"
25+
#include "swift/Basic/LangOptions.h"
2626
#include "swift/Basic/Statistic.h"
2727
#include "llvm/ADT/DenseMap.h"
28-
#include "llvm/ADT/Optional.h"
2928
#include "llvm/ADT/SetVector.h"
3029
#include "llvm/Support/Error.h"
3130
#include "llvm/Support/PrettyStackTrace.h"

include/swift/AST/EvaluatorDependencies.h

Lines changed: 39 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@
1919
#define SWIFT_AST_EVALUATOR_DEPENDENCIES_H
2020

2121
#include "swift/AST/AnyRequest.h"
22-
#include "swift/AST/AttrKind.h"
23-
#include "swift/AST/SourceFile.h"
22+
#include "swift/AST/DependencyCollector.h"
2423
#include "swift/Basic/NullablePtr.h"
25-
#include "llvm/ADT/PointerIntPair.h"
24+
#include "llvm/ADT/DenseMap.h"
25+
#include "llvm/ADT/DenseSet.h"
2626
#include <vector>
2727

2828
namespace swift {
2929

30+
class SourceFile;
31+
3032
namespace evaluator {
3133

3234
namespace detail {
@@ -42,160 +44,64 @@ template <typename...> using void_t = void;
4244
// of individual contexts.
4345
using DependencySource = swift::NullablePtr<SourceFile>;
4446

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-
17147
/// A \c DependencyRecorder is an aggregator of named references discovered in a
17248
/// particular \c DependencyScope during the course of request evaluation.
17349
struct DependencyRecorder {
17450
friend DependencyCollector;
17551

17652
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.
17756
llvm::DenseMap<SourceFile *,
17857
llvm::DenseSet<DependencyCollector::Reference,
17958
DependencyCollector::Reference::Info>>
18059
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.
18166
llvm::DenseMap<AnyRequest, std::vector<DependencyCollector::Reference>>
18267
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.
18373
std::vector<llvm::DenseSet<DependencyCollector::Reference,
18474
DependencyCollector::Reference::Info>>
18575
activeRequestReferences;
18676

18777
#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.
18881
bool isRecording = false;
18982
#endif
19083

19184
public:
85+
/// Push a new empty set onto the activeRequestReferences stack.
19286
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.
19391
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.
19495
void replayCachedRequest(const swift::ActiveRequest &req);
96+
97+
/// Upon completion of a dependency source request, we update the
98+
/// fileReferences map.
19599
void handleDependencySourceRequest(const swift::ActiveRequest &req,
196100
SourceFile *source);
197101

198102
private:
103+
/// Add an entry to the innermost set on the activeRequestReferences stack.
104+
/// Called from the DependencyCollector.
199105
void recordDependency(const DependencyCollector::Reference &ref);
200106

201107
public:
@@ -205,6 +111,10 @@ struct DependencyRecorder {
205111
/// Enumerates the set of references associated with a given source file,
206112
/// passing them to the given enumeration callback.
207113
///
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+
///
208118
/// The order of enumeration is completely undefined. It is the responsibility
209119
/// of callers to ensure they are order-invariant or are sorting the result.
210120
void enumerateReferencesInFile(const SourceFile *SF,

0 commit comments

Comments
 (0)