Files
swift-mirror/lib/Sema/SourceLoader.cpp
Robert Widmann dfa41d625b Optimize Condition Resolution (#6279)
* Pack the bits for IfConfigDecls into Decl

* Don't open symbols into a module when evaluating canImport statements

The module loaders now have API to check whether a given module can be
imported without importing the referenced module.  This provides a
significant speed boost to condition resolution and no longer
introduces symbols from the referenced module into the current context
without the user explicitly requesting it.

The definition of ‘canImport’ does not necessarily mean that a full
import without error is possible, merely that the path to the import is
visible to the compiler and the module is loadable in some form or
another.

Note that this means this check is insufficient to guarantee that you
are on one platform or another.  For those kinds of checks, use
‘os(OSNAME)’.
2017-01-05 12:08:54 -07:00

165 lines
5.7 KiB
C++

//===--- SourceLoader.cpp - Import .swift files as modules ----------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief A simple module loader that loads .swift source files.
///
//===----------------------------------------------------------------------===//
#include "swift/Sema/SourceLoader.h"
#include "swift/Subsystems.h"
#include "swift/AST/AST.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/Parse/DelayedParsingCallbacks.h"
#include "swift/Parse/PersistentParserState.h"
#include "swift/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SaveAndRestore.h"
#include <system_error>
using namespace swift;
// FIXME: Basically the same as SerializedModuleLoader.
using FileOrError = llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>;
static FileOrError findModule(ASTContext &ctx, StringRef moduleID,
SourceLoc importLoc) {
llvm::SmallString<128> inputFilename;
for (auto Path : ctx.SearchPathOpts.ImportSearchPaths) {
inputFilename = Path;
llvm::sys::path::append(inputFilename, moduleID);
inputFilename.append(".swift");
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr =
llvm::MemoryBuffer::getFile(inputFilename.str());
// Return if we loaded a file
if (FileBufOrErr)
return FileBufOrErr;
// Or if we get any error other than the file not existing
auto err = FileBufOrErr.getError();
if (err != std::errc::no_such_file_or_directory)
return FileBufOrErr;
}
return make_error_code(std::errc::no_such_file_or_directory);
}
namespace {
/// Don't parse any function bodies except those that are transparent.
class SkipNonTransparentFunctions : public DelayedParsingCallbacks {
bool shouldDelayFunctionBodyParsing(Parser &TheParser,
AbstractFunctionDecl *AFD,
const DeclAttributes &Attrs,
SourceRange BodyRange) override {
return Attrs.hasAttribute<TransparentAttr>();
}
};
} // unnamed namespace
bool SourceLoader::canImportModule(std::pair<Identifier, SourceLoc> ID) {
// Search the memory buffers to see if we can find this file on disk.
FileOrError inputFileOrError = findModule(Ctx, ID.first.str(),
ID.second);
if (!inputFileOrError) {
auto err = inputFileOrError.getError();
if (err != std::errc::no_such_file_or_directory) {
Ctx.Diags.diagnose(ID.second, diag::sema_opening_import,
ID.first, err.message());
}
return false;
}
return true;
}
Module *SourceLoader::loadModule(SourceLoc importLoc,
ArrayRef<std::pair<Identifier, SourceLoc>> path) {
// FIXME: Swift submodules?
if (path.size() > 1)
return nullptr;
auto moduleID = path[0];
FileOrError inputFileOrError = findModule(Ctx, moduleID.first.str(),
moduleID.second);
if (!inputFileOrError) {
auto err = inputFileOrError.getError();
if (err != std::errc::no_such_file_or_directory) {
Ctx.Diags.diagnose(moduleID.second, diag::sema_opening_import,
moduleID.first, err.message());
}
return nullptr;
}
std::unique_ptr<llvm::MemoryBuffer> inputFile =
std::move(inputFileOrError.get());
addDependency(inputFile->getBufferIdentifier());
// Turn off debugging while parsing other modules.
llvm::SaveAndRestore<bool> turnOffDebug(Ctx.LangOpts.DebugConstraintSolver,
false);
unsigned bufferID;
if (auto BufID =
Ctx.SourceMgr.getIDForBufferIdentifier(inputFile->getBufferIdentifier()))
bufferID = BufID.getValue();
else
bufferID = Ctx.SourceMgr.addNewSourceBuffer(std::move(inputFile));
auto *importMod = Module::create(moduleID.first, Ctx);
if (EnableResilience)
importMod->setResilienceStrategy(ResilienceStrategy::Resilient);
Ctx.LoadedModules[moduleID.first] = importMod;
auto implicitImportKind = SourceFile::ImplicitModuleImportKind::Stdlib;
if (!Ctx.getStdlibModule())
implicitImportKind = SourceFile::ImplicitModuleImportKind::None;
auto *importFile = new (Ctx) SourceFile(*importMod, SourceFileKind::Library,
bufferID, implicitImportKind);
importMod->addFile(*importFile);
bool done;
PersistentParserState persistentState;
SkipNonTransparentFunctions delayCallbacks;
parseIntoSourceFile(*importFile, bufferID, &done, nullptr, &persistentState,
SkipBodies ? &delayCallbacks : nullptr);
assert(done && "Parser returned early?");
(void)done;
performConditionResolution(*importFile);
if (SkipBodies)
performDelayedParsing(importMod, persistentState, nullptr);
// FIXME: Support recursive definitions in immediate modes by making type
// checking even lazier.
if (SkipBodies)
performNameBinding(*importFile);
else
performTypeChecking(*importFile, persistentState.getTopLevelContext(),
None);
return importMod;
}
void SourceLoader::loadExtensions(NominalTypeDecl *nominal,
unsigned previousGeneration) {
// Type-checking the source automatically loads all extensions; there's
// nothing to do here.
}