mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
We don't want typos in import statements to take down the whole REPL, but we /do/ want the REPL to be honoring fatal errors that effectively take down the ASTContext. This doesn't (yet) apply to the real LLDB REPL, which does not use SourceFileKind::REPL for its input. The right option to test there is LangOpts.DebuggerSupport, but that's currently being set for Playgrounds as well. I've filed <rdar://problem/18090611> for LLDB to adjust their input. Part of <rdar://problem/17994094> Swift SVN r21383
145 lines
5.0 KiB
C++
145 lines
5.0 KiB
C++
//===--- SourceLoader.cpp - Import .swift files as modules ------*- c++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://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
|
|
|
|
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);
|
|
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;
|
|
|
|
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());
|
|
|
|
return importMod;
|
|
}
|
|
|
|
void SourceLoader::loadExtensions(NominalTypeDecl *nominal,
|
|
unsigned previousGeneration) {
|
|
// Type-checking the source automatically loads all extensions; there's
|
|
// nothing to do here.
|
|
}
|