Skip to content

Commit b49964e

Browse files
committed
Iterative type checker: collapse "enumerate dependencies" and "satisfy".
The separate "enumerate dependencies" and "satisfy" phases didn't make sense, because one often needs to process part of a request to enumerate additional dependencies. Collapse these two phases into a single "process" operation that makes what progress it can, and enumerates additional dependencies that need to be satisfied before it can progress further. Swift SVN r32563
1 parent f247447 commit b49964e

File tree

3 files changed

+64
-96
lines changed

3 files changed

+64
-96
lines changed

include/swift/Sema/IterativeTypeChecker.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,17 @@ class IterativeTypeChecker {
4343
// enumerateDependenciesOf<request kind> functions, and
4444
// satisfy<request kind> functions.
4545
#define TYPE_CHECK_REQUEST(Request,PayloadName) \
46-
bool is##Request##Satisfied( \
47-
TypeCheckRequest::PayloadName##PayloadType payload); \
48-
void enumerateDependenciesOf##Request( \
49-
TypeCheckRequest::PayloadName##PayloadType payload, \
50-
llvm::function_ref<void(TypeCheckRequest)> fn); \
51-
void satisfy##Request(TypeCheckRequest::PayloadName##PayloadType payload);
46+
bool is##Request##Satisfied( \
47+
TypeCheckRequest::PayloadName##PayloadType payload); \
48+
void process##Request( \
49+
TypeCheckRequest::PayloadName##PayloadType payload, \
50+
llvm::function_ref<void(TypeCheckRequest)> recordDependency);
5251

5352
#include "swift/Sema/TypeCheckRequestKinds.def"
5453

54+
void process(TypeCheckRequest request,
55+
llvm::function_ref<void(TypeCheckRequest)> recordDependency);
56+
5557
public:
5658
IterativeTypeChecker(TypeChecker &tc) : TC(tc) { }
5759

lib/Sema/ITCDecl.cpp

Lines changed: 35 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,9 @@ bool IterativeTypeChecker::isTypeCheckInheritedClauseEntrySatisfied(
8585
return !inherited.getType().isNull();
8686
}
8787

88-
void IterativeTypeChecker::enumerateDependenciesOfTypeCheckInheritedClauseEntry(
88+
void IterativeTypeChecker::processTypeCheckInheritedClauseEntry(
8989
TypeCheckRequest::InheritedClauseEntryPayloadType payload,
90-
llvm::function_ref<void(TypeCheckRequest)>) {
91-
// FIXME: depends on type checking the TypeRepr for this inheritance
92-
// clause entry.
93-
}
94-
95-
void IterativeTypeChecker::satisfyTypeCheckInheritedClauseEntry(
96-
TypeCheckRequest::InheritedClauseEntryPayloadType payload) {
90+
llvm::function_ref<void(TypeCheckRequest)> recordDependency) {
9791
TypeResolutionOptions options;
9892
DeclContext *dc;
9993
TypeLoc *inherited;
@@ -122,36 +116,31 @@ bool IterativeTypeChecker::isTypeCheckSuperclassSatisfied(ClassDecl *payload) {
122116
return payload->LazySemanticInfo.Superclass.getInt();
123117
}
124118

125-
void IterativeTypeChecker::enumerateDependenciesOfTypeCheckSuperclass(
126-
ClassDecl *payload,
127-
llvm::function_ref<void(TypeCheckRequest)> fn) {
119+
void IterativeTypeChecker::processTypeCheckSuperclass(
120+
ClassDecl *classDecl,
121+
llvm::function_ref<void(TypeCheckRequest)> recordDependency) {
128122
// The superclass should be the first inherited type. However, so
129123
// long as we see already-resolved types that refer to protocols,
130124
// skip over them to keep looking for a misplaced superclass. The
131125
// actual error will be diagnosed when we perform full semantic
132126
// analysis on the class itself.
133-
auto inheritedClause = payload->getInherited();
127+
Type superclassType;
128+
auto inheritedClause = classDecl->getInherited();
134129
for (unsigned i = 0, n = inheritedClause.size(); i != n; ++i) {
135130
TypeLoc &inherited = inheritedClause[i];
136131

137132
// If this inherited type has not been resolved, we depend on it.
138133
if (!inherited.getType()) {
139-
fn(TypeCheckRequest(TypeCheckRequest::TypeCheckInheritedClauseEntry,
140-
{ payload, i }));
134+
recordDependency(
135+
TypeCheckRequest(TypeCheckRequest::TypeCheckInheritedClauseEntry,
136+
{ classDecl, i }));
141137
return;
142138
}
143139

144140
// If this resolved inherited type is existential, keep going.
145141
if (inherited.getType()->isExistentialType()) continue;
146142

147-
break;
148-
}
149-
}
150-
151-
void IterativeTypeChecker::satisfyTypeCheckSuperclass(ClassDecl *classDecl) {
152-
// Loop through the inheritance clause looking for a class type.
153-
Type superclassType;
154-
for (const auto &inherited : classDecl->getInherited()) {
143+
// If this resolved type is a class, we're done.
155144
if (inherited.getType()->getClassOrBoundGenericClass()) {
156145
superclassType = inherited.getType();
157146
break;
@@ -169,42 +158,30 @@ bool IterativeTypeChecker::isTypeCheckRawTypeSatisfied(EnumDecl *payload) {
169158
return payload->LazySemanticInfo.RawType.getInt();
170159
}
171160

172-
void IterativeTypeChecker::enumerateDependenciesOfTypeCheckRawType(
173-
EnumDecl *payload,
174-
llvm::function_ref<void(TypeCheckRequest)> fn) {
161+
void IterativeTypeChecker::processTypeCheckRawType(
162+
EnumDecl *enumDecl,
163+
llvm::function_ref<void(TypeCheckRequest)> recordDependency) {
175164
// The raw type should be the first inherited type. However, so
176165
// long as we see already-resolved types that refer to protocols,
177166
// skip over them to keep looking for a misplaced raw type. The
178167
// actual error will be diagnosed when we perform full semantic
179168
// analysis on the enum itself.
180-
auto inheritedClause = payload->getInherited();
169+
Type rawType;
170+
auto inheritedClause = enumDecl->getInherited();
181171
for (unsigned i = 0, n = inheritedClause.size(); i != n; ++i) {
182172
TypeLoc &inherited = inheritedClause[i];
183173

184174
// If this inherited type has not been resolved, we depend on it.
185175
if (!inherited.getType()) {
186-
fn(TypeCheckRequest(TypeCheckRequest::TypeCheckInheritedClauseEntry,
187-
{ payload, i }));
176+
recordDependency(
177+
TypeCheckRequest(TypeCheckRequest::TypeCheckInheritedClauseEntry,
178+
{ enumDecl, i }));
188179
return;
189180
}
190181

191182
// If this resolved inherited type is existential, keep going.
192183
if (inherited.getType()->isExistentialType()) continue;
193184

194-
break;
195-
}
196-
}
197-
198-
void IterativeTypeChecker::satisfyTypeCheckRawType(EnumDecl *enumDecl) {
199-
// Loop through the inheritance clause looking for a non-existential
200-
// nominal type.
201-
Type rawType;
202-
for (const auto &inherited : enumDecl->getInherited()) {
203-
if (!inherited.getType()) break;
204-
205-
// Skip existential types.
206-
if (inherited.getType()->isExistentialType()) continue;
207-
208185
// Record this raw type.
209186
rawType = inherited.getType();
210187
break;
@@ -221,40 +198,40 @@ bool IterativeTypeChecker::isInheritedProtocolsSatisfied(ProtocolDecl *payload){
221198
return payload->isInheritedProtocolsValid();
222199
}
223200

224-
void IterativeTypeChecker::enumerateDependenciesOfInheritedProtocols(
225-
ProtocolDecl *payload,
226-
llvm::function_ref<void(TypeCheckRequest)> fn) {
201+
void IterativeTypeChecker::processInheritedProtocols(
202+
ProtocolDecl *protocol,
203+
llvm::function_ref<void(TypeCheckRequest)> recordDependency) {
227204
// Computing the set of inherited protocols depends on the complete
228205
// inheritance clause.
229206
// FIXME: Technically, we only need very basic name binding.
230-
auto inheritedClause = payload->getInherited();
207+
auto inheritedClause = protocol->getInherited();
208+
bool anyDependencies = false;
209+
llvm::SmallSetVector<ProtocolDecl *, 4> allProtocols;
231210
for (unsigned i = 0, n = inheritedClause.size(); i != n; ++i) {
232211
TypeLoc &inherited = inheritedClause[i];
233212

234213
// If this inherited type has not been resolved, we depend on it.
235214
if (!inherited.getType()) {
236-
fn(TypeCheckRequest(TypeCheckRequest::TypeCheckInheritedClauseEntry,
237-
{ payload, i }));
215+
recordDependency(
216+
TypeCheckRequest(TypeCheckRequest::TypeCheckInheritedClauseEntry,
217+
{ protocol, i }));
218+
anyDependencies = true;
219+
continue;
238220
}
239-
}
240-
}
241-
242-
void IterativeTypeChecker::satisfyInheritedProtocols(ProtocolDecl *protocol) {
243-
// Gather all of the existential types in the inherited list.
244-
// Loop through the inheritance clause looking for a non-existential
245-
// nominal type.
246-
llvm::SmallSetVector<ProtocolDecl *, 4> allProtocols;
247-
for (const auto &inherited : protocol->getInherited()) {
248-
if (!inherited.getType()) continue;
249221

250222
// Collect existential types.
251223
// FIXME: We'd prefer to keep what the user wrote here.
252224
SmallVector<ProtocolDecl *, 4> protocols;
253225
if (inherited.getType()->isExistentialType(protocols)) {
254226
allProtocols.insert(protocols.begin(), protocols.end());
227+
continue;
255228
}
256229
}
257230

231+
// If we enumerated any dependencies, we can't complete this request.
232+
if (anyDependencies)
233+
return;
234+
258235
// FIXME: Hack to deal with recursion elsewhere.
259236
if (protocol->isInheritedProtocolsValid())
260237
return;

lib/Sema/IterativeTypeChecker.cpp

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -29,26 +29,25 @@ DiagnosticEngine &IterativeTypeChecker::getDiags() const {
2929
return getASTContext().Diags;
3030
}
3131

32-
/// Determine whether the given request has already been satisfied.
33-
bool IterativeTypeChecker::isSatisfied(TypeCheckRequest request) {
32+
void IterativeTypeChecker::process(
33+
TypeCheckRequest request,
34+
llvm::function_ref<void(TypeCheckRequest)> recordDependency) {
3435
switch (request.getKind()) {
35-
#define TYPE_CHECK_REQUEST(Request,PayloadName) \
36-
case TypeCheckRequest::Request: \
37-
return is##Request##Satisfied(request.get##PayloadName##Payload());
36+
#define TYPE_CHECK_REQUEST(Request,PayloadName) \
37+
case TypeCheckRequest::Request: \
38+
return process##Request(request.get##PayloadName##Payload(), \
39+
recordDependency);
3840

3941
#include "swift/Sema/TypeCheckRequestKinds.def"
4042
}
4143
}
4244

43-
void IterativeTypeChecker::enumerateDependenciesOf(
44-
TypeCheckRequest request,
45-
llvm::function_ref<void(TypeCheckRequest)> fn) {
45+
/// Determine whether the given request has already been satisfied.
46+
bool IterativeTypeChecker::isSatisfied(TypeCheckRequest request) {
4647
switch (request.getKind()) {
47-
#define TYPE_CHECK_REQUEST(Request,PayloadName) \
48-
case TypeCheckRequest::Request: \
49-
return enumerateDependenciesOf##Request( \
50-
request.get##PayloadName##Payload(), \
51-
fn);
48+
#define TYPE_CHECK_REQUEST(Request,PayloadName) \
49+
case TypeCheckRequest::Request: \
50+
return is##Request##Satisfied(request.get##PayloadName##Payload());
5251

5352
#include "swift/Sema/TypeCheckRequestKinds.def"
5453
}
@@ -58,35 +57,25 @@ void IterativeTypeChecker::satisfy(TypeCheckRequest request) {
5857
// If the request has already been satisfied, we're done.
5958
if (isSatisfied(request)) return;
6059

61-
// Make sure all of the dependencies have been satisfied before continuing.
6260
while (true) {
63-
// Enumerate all of the dependencies of this request and capture
64-
// those that have not been satisfied.
61+
// Process this requirement, enumerating dependencies if anything else needs
62+
// to be handled first.
6563
SmallVector<TypeCheckRequest, 4> unsatisfied;
66-
enumerateDependenciesOf(request, [&](TypeCheckRequest dependency) {
67-
// If the dependency has already been satisfied, there's nothing to do.
68-
if (isSatisfied(dependency)) return;
69-
64+
process(request, [&](TypeCheckRequest dependency) {
7065
// Record the unsatisfied dependency.
7166
unsatisfied.push_back(dependency);
7267
});
7368

74-
// If all dependencies were satisfied, we're done.
75-
if (unsatisfied.empty()) break;
69+
// If there were no unsatisfied dependencies, we're done.
70+
if (unsatisfied.empty()) {
71+
assert(isSatisfied(request));
72+
break;
73+
}
7674

7775
// Recurse to satisfy any unsatisfied dependencies.
7876
// FIXME: Don't recurse in the iterative type checker, silly!
79-
for (auto dependency: unsatisfied) {
77+
for (auto dependency : unsatisfied) {
8078
satisfy(dependency);
8179
}
8280
}
83-
84-
// Satisfy this request.
85-
switch (request.getKind()) {
86-
#define TYPE_CHECK_REQUEST(Request,PayloadName) \
87-
case TypeCheckRequest::Request: \
88-
return satisfy##Request(request.get##PayloadName##Payload());
89-
90-
#include "swift/Sema/TypeCheckRequestKinds.def"
91-
}
9281
}

0 commit comments

Comments
 (0)