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
This commit is contained in:
Doug Gregor
2015-10-09 17:18:41 +00:00
parent f247447f03
commit b49964e39e
3 changed files with 65 additions and 97 deletions

View File

@@ -43,15 +43,17 @@ class IterativeTypeChecker {
// enumerateDependenciesOf<request kind> functions, and
// satisfy<request kind> functions.
#define TYPE_CHECK_REQUEST(Request,PayloadName) \
bool is##Request##Satisfied( \
TypeCheckRequest::PayloadName##PayloadType payload); \
void enumerateDependenciesOf##Request( \
TypeCheckRequest::PayloadName##PayloadType payload, \
llvm::function_ref<void(TypeCheckRequest)> fn); \
void satisfy##Request(TypeCheckRequest::PayloadName##PayloadType payload);
bool is##Request##Satisfied( \
TypeCheckRequest::PayloadName##PayloadType payload); \
void process##Request( \
TypeCheckRequest::PayloadName##PayloadType payload, \
llvm::function_ref<void(TypeCheckRequest)> recordDependency);
#include "swift/Sema/TypeCheckRequestKinds.def"
void process(TypeCheckRequest request,
llvm::function_ref<void(TypeCheckRequest)> recordDependency);
public:
IterativeTypeChecker(TypeChecker &tc) : TC(tc) { }

View File

@@ -85,15 +85,9 @@ bool IterativeTypeChecker::isTypeCheckInheritedClauseEntrySatisfied(
return !inherited.getType().isNull();
}
void IterativeTypeChecker::enumerateDependenciesOfTypeCheckInheritedClauseEntry(
void IterativeTypeChecker::processTypeCheckInheritedClauseEntry(
TypeCheckRequest::InheritedClauseEntryPayloadType payload,
llvm::function_ref<void(TypeCheckRequest)>) {
// FIXME: depends on type checking the TypeRepr for this inheritance
// clause entry.
}
void IterativeTypeChecker::satisfyTypeCheckInheritedClauseEntry(
TypeCheckRequest::InheritedClauseEntryPayloadType payload) {
llvm::function_ref<void(TypeCheckRequest)> recordDependency) {
TypeResolutionOptions options;
DeclContext *dc;
TypeLoc *inherited;
@@ -122,36 +116,31 @@ bool IterativeTypeChecker::isTypeCheckSuperclassSatisfied(ClassDecl *payload) {
return payload->LazySemanticInfo.Superclass.getInt();
}
void IterativeTypeChecker::enumerateDependenciesOfTypeCheckSuperclass(
ClassDecl *payload,
llvm::function_ref<void(TypeCheckRequest)> fn) {
void IterativeTypeChecker::processTypeCheckSuperclass(
ClassDecl *classDecl,
llvm::function_ref<void(TypeCheckRequest)> recordDependency) {
// The superclass should be the first inherited type. However, so
// long as we see already-resolved types that refer to protocols,
// skip over them to keep looking for a misplaced superclass. The
// actual error will be diagnosed when we perform full semantic
// analysis on the class itself.
auto inheritedClause = payload->getInherited();
Type superclassType;
auto inheritedClause = classDecl->getInherited();
for (unsigned i = 0, n = inheritedClause.size(); i != n; ++i) {
TypeLoc &inherited = inheritedClause[i];
// If this inherited type has not been resolved, we depend on it.
if (!inherited.getType()) {
fn(TypeCheckRequest(TypeCheckRequest::TypeCheckInheritedClauseEntry,
{ payload, i }));
recordDependency(
TypeCheckRequest(TypeCheckRequest::TypeCheckInheritedClauseEntry,
{ classDecl, i }));
return;
}
// If this resolved inherited type is existential, keep going.
if (inherited.getType()->isExistentialType()) continue;
break;
}
}
void IterativeTypeChecker::satisfyTypeCheckSuperclass(ClassDecl *classDecl) {
// Loop through the inheritance clause looking for a class type.
Type superclassType;
for (const auto &inherited : classDecl->getInherited()) {
// If this resolved type is a class, we're done.
if (inherited.getType()->getClassOrBoundGenericClass()) {
superclassType = inherited.getType();
break;
@@ -169,42 +158,30 @@ bool IterativeTypeChecker::isTypeCheckRawTypeSatisfied(EnumDecl *payload) {
return payload->LazySemanticInfo.RawType.getInt();
}
void IterativeTypeChecker::enumerateDependenciesOfTypeCheckRawType(
EnumDecl *payload,
llvm::function_ref<void(TypeCheckRequest)> fn) {
void IterativeTypeChecker::processTypeCheckRawType(
EnumDecl *enumDecl,
llvm::function_ref<void(TypeCheckRequest)> recordDependency) {
// The raw type should be the first inherited type. However, so
// long as we see already-resolved types that refer to protocols,
// skip over them to keep looking for a misplaced raw type. The
// actual error will be diagnosed when we perform full semantic
// analysis on the enum itself.
auto inheritedClause = payload->getInherited();
Type rawType;
auto inheritedClause = enumDecl->getInherited();
for (unsigned i = 0, n = inheritedClause.size(); i != n; ++i) {
TypeLoc &inherited = inheritedClause[i];
// If this inherited type has not been resolved, we depend on it.
if (!inherited.getType()) {
fn(TypeCheckRequest(TypeCheckRequest::TypeCheckInheritedClauseEntry,
{ payload, i }));
recordDependency(
TypeCheckRequest(TypeCheckRequest::TypeCheckInheritedClauseEntry,
{ enumDecl, i }));
return;
}
// If this resolved inherited type is existential, keep going.
if (inherited.getType()->isExistentialType()) continue;
break;
}
}
void IterativeTypeChecker::satisfyTypeCheckRawType(EnumDecl *enumDecl) {
// Loop through the inheritance clause looking for a non-existential
// nominal type.
Type rawType;
for (const auto &inherited : enumDecl->getInherited()) {
if (!inherited.getType()) break;
// Skip existential types.
if (inherited.getType()->isExistentialType()) continue;
// Record this raw type.
rawType = inherited.getType();
break;
@@ -221,40 +198,40 @@ bool IterativeTypeChecker::isInheritedProtocolsSatisfied(ProtocolDecl *payload){
return payload->isInheritedProtocolsValid();
}
void IterativeTypeChecker::enumerateDependenciesOfInheritedProtocols(
ProtocolDecl *payload,
llvm::function_ref<void(TypeCheckRequest)> fn) {
void IterativeTypeChecker::processInheritedProtocols(
ProtocolDecl *protocol,
llvm::function_ref<void(TypeCheckRequest)> recordDependency) {
// Computing the set of inherited protocols depends on the complete
// inheritance clause.
// FIXME: Technically, we only need very basic name binding.
auto inheritedClause = payload->getInherited();
auto inheritedClause = protocol->getInherited();
bool anyDependencies = false;
llvm::SmallSetVector<ProtocolDecl *, 4> allProtocols;
for (unsigned i = 0, n = inheritedClause.size(); i != n; ++i) {
TypeLoc &inherited = inheritedClause[i];
// If this inherited type has not been resolved, we depend on it.
if (!inherited.getType()) {
fn(TypeCheckRequest(TypeCheckRequest::TypeCheckInheritedClauseEntry,
{ payload, i }));
recordDependency(
TypeCheckRequest(TypeCheckRequest::TypeCheckInheritedClauseEntry,
{ protocol, i }));
anyDependencies = true;
continue;
}
}
}
void IterativeTypeChecker::satisfyInheritedProtocols(ProtocolDecl *protocol) {
// Gather all of the existential types in the inherited list.
// Loop through the inheritance clause looking for a non-existential
// nominal type.
llvm::SmallSetVector<ProtocolDecl *, 4> allProtocols;
for (const auto &inherited : protocol->getInherited()) {
if (!inherited.getType()) continue;
// Collect existential types.
// FIXME: We'd prefer to keep what the user wrote here.
SmallVector<ProtocolDecl *, 4> protocols;
if (inherited.getType()->isExistentialType(protocols)) {
allProtocols.insert(protocols.begin(), protocols.end());
continue;
}
}
// If we enumerated any dependencies, we can't complete this request.
if (anyDependencies)
return;
// FIXME: Hack to deal with recursion elsewhere.
if (protocol->isInheritedProtocolsValid())
return;

View File

@@ -29,6 +29,19 @@ DiagnosticEngine &IterativeTypeChecker::getDiags() const {
return getASTContext().Diags;
}
void IterativeTypeChecker::process(
TypeCheckRequest request,
llvm::function_ref<void(TypeCheckRequest)> recordDependency) {
switch (request.getKind()) {
#define TYPE_CHECK_REQUEST(Request,PayloadName) \
case TypeCheckRequest::Request: \
return process##Request(request.get##PayloadName##Payload(), \
recordDependency);
#include "swift/Sema/TypeCheckRequestKinds.def"
}
}
/// Determine whether the given request has already been satisfied.
bool IterativeTypeChecker::isSatisfied(TypeCheckRequest request) {
switch (request.getKind()) {
@@ -40,53 +53,29 @@ bool IterativeTypeChecker::isSatisfied(TypeCheckRequest request) {
}
}
void IterativeTypeChecker::enumerateDependenciesOf(
TypeCheckRequest request,
llvm::function_ref<void(TypeCheckRequest)> fn) {
switch (request.getKind()) {
#define TYPE_CHECK_REQUEST(Request,PayloadName) \
case TypeCheckRequest::Request: \
return enumerateDependenciesOf##Request( \
request.get##PayloadName##Payload(), \
fn);
#include "swift/Sema/TypeCheckRequestKinds.def"
}
}
void IterativeTypeChecker::satisfy(TypeCheckRequest request) {
// If the request has already been satisfied, we're done.
if (isSatisfied(request)) return;
// Make sure all of the dependencies have been satisfied before continuing.
while (true) {
// Enumerate all of the dependencies of this request and capture
// those that have not been satisfied.
// Process this requirement, enumerating dependencies if anything else needs
// to be handled first.
SmallVector<TypeCheckRequest, 4> unsatisfied;
enumerateDependenciesOf(request, [&](TypeCheckRequest dependency) {
// If the dependency has already been satisfied, there's nothing to do.
if (isSatisfied(dependency)) return;
process(request, [&](TypeCheckRequest dependency) {
// Record the unsatisfied dependency.
unsatisfied.push_back(dependency);
});
// If all dependencies were satisfied, we're done.
if (unsatisfied.empty()) break;
// If there were no unsatisfied dependencies, we're done.
if (unsatisfied.empty()) {
assert(isSatisfied(request));
break;
}
// Recurse to satisfy any unsatisfied dependencies.
// FIXME: Don't recurse in the iterative type checker, silly!
for (auto dependency: unsatisfied) {
for (auto dependency : unsatisfied) {
satisfy(dependency);
}
}
// Satisfy this request.
switch (request.getKind()) {
#define TYPE_CHECK_REQUEST(Request,PayloadName) \
case TypeCheckRequest::Request: \
return satisfy##Request(request.get##PayloadName##Payload());
#include "swift/Sema/TypeCheckRequestKinds.def"
}
}