Diagnose modules with circular dependencies (#16075)

This can't arise from a clean build, but it can happen if you have
products lingering in a search path and then either rebuild one of
the modules in the cycle, or change the search paths.

The way this is implemented is for each module to track whether its
imports have all been resolved. If, when loading a module, one of its
dependencies hasn't resolved all of its imports yet, then we know
there's a cycle.

This doesn't produce the best diagnostics, but it's hard to get into
this state in the first place, so that's probably okay.

https://bugs.swift.org/browse/SR-7483
This commit is contained in:
Jordan Rose
2018-05-02 15:01:09 -07:00
committed by GitHub
parent 99861785ca
commit df2e63d07d
17 changed files with 98 additions and 124 deletions

View File

@@ -15,6 +15,7 @@
#include "swift/Strings.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/STLExtras.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/Version.h"
@@ -316,6 +317,25 @@ FileUnit *SerializedModuleLoader::loadAST(
break;
}
case serialization::Status::CircularDependency: {
auto circularDependencyIter =
llvm::find_if(loadedModuleFile->getDependencies(),
[](const ModuleFile::Dependency &next) {
return !next.Import.second->hasResolvedImports();
});
assert(circularDependencyIter != loadedModuleFile->getDependencies().end()
&& "circular dependency reported, but no module with unresolved "
"imports found");
// FIXME: We should include the path of the circularity as well, but that's
// hard because we're discovering this /while/ resolving imports, which
// means the problematic modules haven't been recorded yet.
Ctx.Diags.diagnose(*diagLoc, diag::serialization_circular_dependency,
circularDependencyIter->getPrettyPrintedPath(),
M.getName());
break;
}
case serialization::Status::MissingShadowedModule: {
Ctx.Diags.diagnose(*diagLoc, diag::serialization_missing_shadowed_module,
M.getName());
@@ -434,6 +454,7 @@ ModuleDecl *SerializedModuleLoader::loadModule(SourceLoc importLoc,
auto M = ModuleDecl::create(moduleID.first, Ctx);
Ctx.LoadedModules[moduleID.first] = M;
SWIFT_DEFER { M->setHasResolvedImports(); };
if (!loadAST(*M, moduleID.second, std::move(moduleInputBuffer),
std::move(moduleDocInputBuffer), isFramework)) {