mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Use a list of module loaders instead of a single Clang importer.
This paves the way for having a Swift module importer. The eventual goal here is to eliminate all explicit uses of the Clang module loader, but I'm not going to push too hard on that for now. Swift SVN r5092
This commit is contained in:
@@ -305,14 +305,28 @@ public:
|
|||||||
const Type TheIEEE128Type; /// TheIEEE128Type - 128-bit IEEE floating point
|
const Type TheIEEE128Type; /// TheIEEE128Type - 128-bit IEEE floating point
|
||||||
const Type ThePPC128Type; /// ThePPC128Type - 128-bit PowerPC 2xDouble
|
const Type ThePPC128Type; /// ThePPC128Type - 128-bit PowerPC 2xDouble
|
||||||
|
|
||||||
/// \brief Determine whether this ASTContext has a module loader.
|
/// \brief Adds a module loader to this AST context.
|
||||||
bool hasModuleLoader() const;
|
///
|
||||||
|
/// \param loader The new module loader, which will be added after any
|
||||||
|
/// existing module loaders.
|
||||||
|
/// \param isClang \c true if this module loader is responsible for loading
|
||||||
|
/// Clang modules, which are special-cased in some parts of the
|
||||||
|
/// compiler.
|
||||||
|
void addModuleLoader(llvm::IntrusiveRefCntPtr<ModuleLoader> loader,
|
||||||
|
bool isClang = false);
|
||||||
|
|
||||||
/// \brief Set the module loader for this ASTContext.
|
/// \brief Retrieve the Clang module loader for this ASTContext.
|
||||||
void setModuleLoader(llvm::IntrusiveRefCntPtr<ModuleLoader> loader);
|
///
|
||||||
|
/// If there is no Clang module loader, returns a null smart pointer.
|
||||||
|
llvm::IntrusiveRefCntPtr<ModuleLoader> getClangModuleLoader() const;
|
||||||
|
|
||||||
/// \brief Retrieve the module loader for this ASTContext.
|
/// \brief Attempts to load a module into this ASTContext.
|
||||||
ModuleLoader &getModuleLoader() const;
|
///
|
||||||
|
/// If a module by this name has already been loaded, the existing module will
|
||||||
|
/// be returned.
|
||||||
|
///
|
||||||
|
/// \returns The requested module, or NULL if the module cannot be found.
|
||||||
|
Module *getModule(ArrayRef<std::pair<Identifier, SourceLoc>> modulePath);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Decl;
|
friend class Decl;
|
||||||
|
|||||||
@@ -729,6 +729,8 @@ ERROR(constraint_assign_type_check_fail,sema,none,
|
|||||||
// Name Binding
|
// Name Binding
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ERROR(sema_no_import,sema_nb,none,
|
||||||
|
"no such module '%0'", (StringRef))
|
||||||
ERROR(sema_opening_import,sema_nb,none,
|
ERROR(sema_opening_import,sema_nb,none,
|
||||||
"opening import file '%0.swift': %1", (StringRef, StringRef))
|
"opening import file '%0.swift': %1", (StringRef, StringRef))
|
||||||
ERROR(invalid_declaration_imported,sema_nb,none,
|
ERROR(invalid_declaration_imported,sema_nb,none,
|
||||||
|
|||||||
56
include/swift/Sema/SourceLoader.h
Normal file
56
include/swift/Sema/SourceLoader.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
//===--- SourceLoader.h - 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
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef SWIFT_SEMA_SOURCELOADER_H
|
||||||
|
#define SWIFT_SEMA_SOURCELOADER_H
|
||||||
|
|
||||||
|
#include "swift/AST/ModuleLoader.h"
|
||||||
|
|
||||||
|
namespace swift {
|
||||||
|
|
||||||
|
class ASTContext;
|
||||||
|
class Module;
|
||||||
|
|
||||||
|
/// \brief Imports serialized Swift modules into an ASTContext.
|
||||||
|
class SourceLoader : public ModuleLoader {
|
||||||
|
private:
|
||||||
|
ASTContext &Ctx;
|
||||||
|
|
||||||
|
explicit SourceLoader(ASTContext &ctx) : Ctx(ctx) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static SourceLoader *create(ASTContext &ctx) {
|
||||||
|
return new SourceLoader(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceLoader(const SourceLoader &) = delete;
|
||||||
|
SourceLoader(SourceLoader &&) = delete;
|
||||||
|
SourceLoader &operator=(const SourceLoader &) = delete;
|
||||||
|
SourceLoader &operator=(SourceLoader &&) = delete;
|
||||||
|
|
||||||
|
/// \brief Import a module with the given module path.
|
||||||
|
///
|
||||||
|
/// \param importLoc The location of the 'import' keyword.
|
||||||
|
///
|
||||||
|
/// \param path A sequence of (identifier, location) pairs that denote
|
||||||
|
/// the dotted module name to load, e.g., AppKit.NSWindow.
|
||||||
|
///
|
||||||
|
/// \returns the module referenced, if it could be loaded. Otherwise,
|
||||||
|
/// returns NULL.
|
||||||
|
virtual Module *
|
||||||
|
loadModule(SourceLoc importLoc,
|
||||||
|
ArrayRef<std::pair<Identifier, SourceLoc>> path) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -37,8 +37,13 @@ struct ASTContext::Implementation {
|
|||||||
llvm::BumpPtrAllocator Allocator; // used in later initializations
|
llvm::BumpPtrAllocator Allocator; // used in later initializations
|
||||||
llvm::StringMap<char, llvm::BumpPtrAllocator&> IdentifierTable;
|
llvm::StringMap<char, llvm::BumpPtrAllocator&> IdentifierTable;
|
||||||
|
|
||||||
/// \brief The module loader used to load modules.
|
/// \brief The various module loaders that import external modules into this
|
||||||
llvm::IntrusiveRefCntPtr<swift::ModuleLoader> ModuleLoader;
|
/// ASTContext.
|
||||||
|
SmallVector<llvm::IntrusiveRefCntPtr<swift::ModuleLoader>, 4> ModuleLoaders;
|
||||||
|
|
||||||
|
/// \brief The module loader used to load Clang modules.
|
||||||
|
// FIXME: We shouldn't be special-casing Clang.
|
||||||
|
llvm::IntrusiveRefCntPtr<swift::ModuleLoader> ClangModuleLoader;
|
||||||
|
|
||||||
/// \brief The set of AST mutation listeners.
|
/// \brief The set of AST mutation listeners.
|
||||||
SmallVector<ASTMutationListener *, 4> MutationListeners;
|
SmallVector<ASTMutationListener *, 4> MutationListeners;
|
||||||
@@ -229,21 +234,36 @@ void ASTContext::setSubstitutions(BoundGenericType* Bound,
|
|||||||
Impl.BoundGenericSubstitutions[Bound] = Subs;
|
Impl.BoundGenericSubstitutions[Bound] = Subs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Determine whether this ASTContext has a module loader.
|
void ASTContext::addModuleLoader(llvm::IntrusiveRefCntPtr<ModuleLoader> loader,
|
||||||
bool ASTContext::hasModuleLoader() const {
|
bool IsClang) {
|
||||||
return Impl.ModuleLoader;
|
Impl.ModuleLoaders.push_back(loader);
|
||||||
|
if (IsClang) {
|
||||||
|
assert(!Impl.ClangModuleLoader && "Already have a Clang module loader");
|
||||||
|
Impl.ClangModuleLoader = std::move(loader);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Set the module loader for this ASTContext.
|
llvm::IntrusiveRefCntPtr<ModuleLoader> ASTContext::getClangModuleLoader() const{
|
||||||
void ASTContext::setModuleLoader(llvm::IntrusiveRefCntPtr<ModuleLoader> loader){
|
return Impl.ClangModuleLoader;
|
||||||
assert(!hasModuleLoader() && "Already has a module loader");
|
|
||||||
Impl.ModuleLoader = loader;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Retrieve the module loader for this ASTContext.
|
Module *
|
||||||
ModuleLoader &ASTContext::getModuleLoader() const {
|
ASTContext::getModule(ArrayRef<std::pair<Identifier, SourceLoc>> modulePath) {
|
||||||
assert(hasModuleLoader() && "No module loader!");
|
assert(!modulePath.empty());
|
||||||
return *Impl.ModuleLoader;
|
auto moduleID = modulePath[0];
|
||||||
|
|
||||||
|
// TODO: Swift submodules.
|
||||||
|
if (modulePath.size() == 1) {
|
||||||
|
if (Module *M = LoadedModules.lookup(moduleID.first.str()))
|
||||||
|
return M;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto importer : Impl.ModuleLoaders) {
|
||||||
|
if (Module *M = importer->loadModule(moduleID.second, modulePath))
|
||||||
|
return M;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClangNode ASTContext::getClangNode(Decl *decl) {
|
ClangNode ASTContext::getClangNode(Decl *decl) {
|
||||||
|
|||||||
@@ -234,7 +234,8 @@ ArrayRef<ExtensionDecl*> Module::lookupExtensions(Type T) {
|
|||||||
return Cache.getExtensions(T->getCanonicalType());
|
return Cache.getExtensions(T->getCanonicalType());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ctx.getModuleLoader().lookupExtensions(cast<ClangModule>(this), T);
|
assert(isa<ClangModule>(this));
|
||||||
|
return Ctx.getClangModuleLoader()->lookupExtensions(this, T);
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@@ -260,8 +261,9 @@ void Module::lookupValue(AccessPathTy AccessPath, Identifier Name,
|
|||||||
.lookupValue(AccessPath, Name, LookupKind, *TU, Result);
|
.lookupValue(AccessPath, Name, LookupKind, *TU, Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ctx.getModuleLoader().lookupValue(cast<ClangModule>(this), AccessPath,
|
assert(isa<ClangModule>(this));
|
||||||
Name, LookupKind, Result);
|
return Ctx.getClangModuleLoader()->lookupValue(this, AccessPath,
|
||||||
|
Name, LookupKind, Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// lookupVisibleDecls - Find ValueDecls in the module and pass them to the
|
/// lookupVisibleDecls - Find ValueDecls in the module and pass them to the
|
||||||
|
|||||||
@@ -90,6 +90,11 @@ ClangImporter *ClangImporter::create(ASTContext &ctx, StringRef sdkroot,
|
|||||||
auto clangDiags(CompilerInstance::createDiagnostics(
|
auto clangDiags(CompilerInstance::createDiagnostics(
|
||||||
new clang::DiagnosticOptions, 0, nullptr));
|
new clang::DiagnosticOptions, 0, nullptr));
|
||||||
|
|
||||||
|
// Don't stop emitting messages if we ever can't find a file.
|
||||||
|
// FIXME: This is actually a general problem: any "fatal" error could mess up
|
||||||
|
// the CompilerInvocation.
|
||||||
|
clangDiags->setDiagnosticErrorAsFatal(clang::diag::err_module_not_found,
|
||||||
|
false);
|
||||||
|
|
||||||
// Construct the invocation arguments for Objective-C ARC with the current
|
// Construct the invocation arguments for Objective-C ARC with the current
|
||||||
// target.
|
// target.
|
||||||
@@ -245,6 +250,9 @@ Module *ClangImporter::loadModule(
|
|||||||
// FIXME: The source location here is completely bogus. It can't be
|
// FIXME: The source location here is completely bogus. It can't be
|
||||||
// invalid, and it can't be the same thing twice in a row, so we just use
|
// invalid, and it can't be the same thing twice in a row, so we just use
|
||||||
// a counter. Having real source locations would be far, far better.
|
// a counter. Having real source locations would be far, far better.
|
||||||
|
// FIXME: This should not print a message if we just can't find a Clang
|
||||||
|
// module -- that's Swift's responsibility, since there could in theory be a
|
||||||
|
// later module loader.
|
||||||
auto &srcMgr = clangContext.getSourceManager();
|
auto &srcMgr = clangContext.getSourceManager();
|
||||||
clang::SourceLocation clangImportLoc
|
clang::SourceLocation clangImportLoc
|
||||||
= srcMgr.getLocForStartOfFile(srcMgr.getMainFileID())
|
= srcMgr.getLocForStartOfFile(srcMgr.getMainFileID())
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ add_swift_library(swiftSema
|
|||||||
ArchetypeBuilder.cpp
|
ArchetypeBuilder.cpp
|
||||||
CaptureAnalysis.cpp
|
CaptureAnalysis.cpp
|
||||||
NameBinding.cpp
|
NameBinding.cpp
|
||||||
|
SourceLoader.cpp
|
||||||
TypeChecker.cpp
|
TypeChecker.cpp
|
||||||
TypeCheckCoercion.cpp
|
TypeCheckCoercion.cpp
|
||||||
TypeCheckConstraints.cpp
|
TypeCheckConstraints.cpp
|
||||||
|
|||||||
@@ -77,72 +77,24 @@ namespace {
|
|||||||
/// fills in the Components.
|
/// fills in the Components.
|
||||||
bool resolveIdentifierType(IdentifierType *DNT, DeclContext *DC);
|
bool resolveIdentifierType(IdentifierType *DNT, DeclContext *DC);
|
||||||
|
|
||||||
llvm::error_code findModule(StringRef Module,
|
/// Load a module referenced by an import statement.
|
||||||
SourceLoc ImportLoc,
|
///
|
||||||
llvm::OwningPtr<llvm::MemoryBuffer> &Buffer);
|
/// Returns null if no module can be loaded.
|
||||||
|
|
||||||
private:
|
|
||||||
/// getModule - Load a module referenced by an import statement,
|
|
||||||
/// emitting an error at the specified location and returning null on
|
|
||||||
/// failure.
|
|
||||||
Module *getModule(llvm::ArrayRef<std::pair<Identifier,SourceLoc>> ModuleID);
|
Module *getModule(llvm::ArrayRef<std::pair<Identifier,SourceLoc>> ModuleID);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::error_code NameBinder::findModule(StringRef Module,
|
Module *
|
||||||
SourceLoc ImportLoc,
|
NameBinder::getModule(ArrayRef<std::pair<Identifier, SourceLoc>> modulePath) {
|
||||||
llvm::OwningPtr<llvm::MemoryBuffer> &Buffer) {
|
assert(!modulePath.empty());
|
||||||
std::string ModuleFilename = Module.str() + std::string(".swift");
|
auto moduleID = modulePath[0];
|
||||||
|
|
||||||
llvm::SmallString<128> InputFilename;
|
|
||||||
|
|
||||||
// First, search in the directory corresponding to the import location.
|
|
||||||
// FIXME: This screams for a proper FileManager abstraction.
|
|
||||||
llvm::SourceMgr &SourceMgr = Context.SourceMgr;
|
|
||||||
int CurrentBufferID = SourceMgr.FindBufferContainingLoc(ImportLoc.Value);
|
|
||||||
if (CurrentBufferID >= 0) {
|
|
||||||
const llvm::MemoryBuffer *ImportingBuffer
|
|
||||||
= SourceMgr.getBufferInfo(CurrentBufferID).Buffer;
|
|
||||||
StringRef CurrentDirectory
|
|
||||||
= llvm::sys::path::parent_path(ImportingBuffer->getBufferIdentifier());
|
|
||||||
if (!CurrentDirectory.empty()) {
|
|
||||||
InputFilename = CurrentDirectory;
|
|
||||||
llvm::sys::path::append(InputFilename, ModuleFilename);
|
|
||||||
llvm::error_code Err = llvm::MemoryBuffer::getFile(InputFilename, Buffer);
|
|
||||||
if (!Err)
|
|
||||||
return Err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Second, search in the current directory.
|
|
||||||
llvm::error_code Err = llvm::MemoryBuffer::getFile(ModuleFilename, Buffer);
|
|
||||||
if (!Err)
|
|
||||||
return Err;
|
|
||||||
|
|
||||||
// If we fail, search each import search path.
|
|
||||||
for (auto Path : Context.ImportSearchPaths) {
|
|
||||||
InputFilename = Path;
|
|
||||||
llvm::sys::path::append(InputFilename, ModuleFilename);
|
|
||||||
Err = llvm::MemoryBuffer::getFile(InputFilename, Buffer);
|
|
||||||
if (!Err)
|
|
||||||
return Err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Err;
|
|
||||||
}
|
|
||||||
|
|
||||||
Module *NameBinder::getModule(
|
|
||||||
ArrayRef<std::pair<Identifier, SourceLoc>> ModulePath) {
|
|
||||||
// TODO: Swift submodules.
|
|
||||||
assert(ModulePath.size() >= 1 && "empty import path");
|
|
||||||
auto ModuleID = ModulePath[0];
|
|
||||||
|
|
||||||
// TODO: We currently just recursively parse referenced modules. This works
|
// TODO: We currently just recursively parse referenced modules. This works
|
||||||
// fine for now since they are each a single file. Ultimately we'll want a
|
// fine for now since they are each a single file. Ultimately we'll want a
|
||||||
// compiled form of AST's like clang's that support lazy deserialization.
|
// compiled form of AST's like clang's that support lazy deserialization.
|
||||||
|
|
||||||
// FIXME: We shouldn't really allow arbitrary modules to import Builtin.
|
// FIXME: We shouldn't really allow arbitrary modules to import Builtin.
|
||||||
if (ModuleID.first.str() == "Builtin") {
|
if (moduleID.first.str() == "Builtin") {
|
||||||
ImportedBuiltinModule = true;
|
ImportedBuiltinModule = true;
|
||||||
return TU->Ctx.TheBuiltinModule;
|
return TU->Ctx.TheBuiltinModule;
|
||||||
}
|
}
|
||||||
@@ -150,84 +102,32 @@ Module *NameBinder::getModule(
|
|||||||
// If the imported module name is the same as the current translation unit,
|
// If the imported module name is the same as the current translation unit,
|
||||||
// skip the Swift module loader and use the Clang module loader instead.
|
// skip the Swift module loader and use the Clang module loader instead.
|
||||||
// This allows a Swift module to extend a Clang module of the same name.
|
// This allows a Swift module to extend a Clang module of the same name.
|
||||||
bool useClangModule = false;
|
if (moduleID.first == TU->Name && modulePath.size() == 1) {
|
||||||
if (ModuleID.first == TU->Name && Context.hasModuleLoader())
|
if (auto importer = Context.getClangModuleLoader())
|
||||||
useClangModule = true;
|
return importer->loadModule(moduleID.second, modulePath);
|
||||||
|
return nullptr;
|
||||||
Module *M = nullptr;
|
}
|
||||||
|
|
||||||
// FIXME: For now, ignore submodule paths except for Clang modules.
|
return Context.getModule(modulePath);
|
||||||
if (ModulePath.size() > 1 && Context.hasModuleLoader()) {
|
|
||||||
useClangModule = true;
|
|
||||||
} else {
|
|
||||||
M = Context.LoadedModules.lookup(ModuleID.first.str());
|
|
||||||
if (M && !(useClangModule && !isa<ClangModule>(M)))
|
|
||||||
return M;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the input file.
|
|
||||||
llvm::OwningPtr<llvm::MemoryBuffer> InputFile;
|
|
||||||
if (!useClangModule) {
|
|
||||||
if (llvm::error_code Err = findModule(ModuleID.first.str(), ModuleID.second,
|
|
||||||
InputFile)) {
|
|
||||||
if (Err.value() != llvm::errc::no_such_file_or_directory ||
|
|
||||||
!Context.hasModuleLoader()) {
|
|
||||||
diagnose(ModuleID.second, diag::sema_opening_import,
|
|
||||||
ModuleID.first.str(), Err.message());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There was no Swift module with this name, so try a Clang module.
|
|
||||||
useClangModule = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useClangModule) {
|
|
||||||
// FIXME: We're assuming that 'externally loaded module' == 'clang module',
|
|
||||||
// which is clearly nonsense. We almost certainy want to have a chain
|
|
||||||
// of external module loaders, with the Swift one first and the Clang one
|
|
||||||
// as a fallback.
|
|
||||||
// FIXME: Bad location info?
|
|
||||||
return Context.getModuleLoader().loadModule(ModuleID.second,
|
|
||||||
ModulePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned BufferID =
|
|
||||||
Context.SourceMgr.AddNewSourceBuffer(InputFile.take(),
|
|
||||||
ModuleID.second.Value);
|
|
||||||
|
|
||||||
// FIXME: Turn off the constraint-based type checker for the imported 'swift'
|
|
||||||
// module.
|
|
||||||
llvm::SaveAndRestore<bool> saveUseCS(Context.LangOpts.UseConstraintSolver,
|
|
||||||
(Context.LangOpts.UseConstraintSolver &&
|
|
||||||
ModuleID.first.str() != "swift"));
|
|
||||||
|
|
||||||
// For now, treat all separate modules as unique components.
|
|
||||||
Component *Comp = new (Context.Allocate<Component>(1)) Component();
|
|
||||||
TranslationUnit *ImportedTU;
|
|
||||||
ImportedTU = new (Context) TranslationUnit(ModuleID.first, Comp, Context,
|
|
||||||
/*IsMainModule*/false,
|
|
||||||
/*IsReplModule*/false);
|
|
||||||
|
|
||||||
Context.LoadedModules[ModuleID.first.str()] = ImportedTU;
|
|
||||||
parseIntoTranslationUnit(ImportedTU, BufferID);
|
|
||||||
|
|
||||||
// We have to do name binding on it to ensure that types are fully resolved.
|
|
||||||
// This should eventually be eliminated by having actual fully resolved binary
|
|
||||||
// dumps of the code instead of reparsing though.
|
|
||||||
// FIXME: We also need to deal with circular imports!
|
|
||||||
performNameBinding(ImportedTU);
|
|
||||||
performTypeChecking(ImportedTU);
|
|
||||||
|
|
||||||
return ImportedTU;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NameBinder::addImport(ImportDecl *ID,
|
void NameBinder::addImport(ImportDecl *ID,
|
||||||
SmallVectorImpl<ImportedModule> &Result) {
|
SmallVectorImpl<ImportedModule> &Result) {
|
||||||
ArrayRef<ImportDecl::AccessPathElement> Path = ID->getAccessPath();
|
ArrayRef<ImportDecl::AccessPathElement> Path = ID->getAccessPath();
|
||||||
Module *M = getModule(Path);
|
|
||||||
if (M == 0) return;
|
// FIXME: This is a hack to allow /either/ Clang submodules /or/ importing
|
||||||
|
// declarations from within Swift translation units...but not both. We may
|
||||||
|
// need to design this carefully: what does "Foundation.NSString" refer to?
|
||||||
|
auto importPath = Path;
|
||||||
|
if (!Context.getClangModuleLoader())
|
||||||
|
importPath = importPath.slice(0, 1);
|
||||||
|
|
||||||
|
Module *M = getModule(importPath);
|
||||||
|
if (M == 0) {
|
||||||
|
diagnose(Path[0].second, diag::sema_no_import, Path[0].first.str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: Validate the access path against the module. Reject things like
|
// FIXME: Validate the access path against the module. Reject things like
|
||||||
// import swift.aslkdfja
|
// import swift.aslkdfja
|
||||||
@@ -242,7 +142,7 @@ void NameBinder::addImport(ImportDecl *ID,
|
|||||||
// module with the same name, add that Clang module to our own set of imports.
|
// module with the same name, add that Clang module to our own set of imports.
|
||||||
// FIXME: This is a horrible, horrible way to provide transitive inclusion.
|
// FIXME: This is a horrible, horrible way to provide transitive inclusion.
|
||||||
// We really need a re-export syntax.
|
// We really need a re-export syntax.
|
||||||
if (Context.hasModuleLoader()) {
|
if (Context.getClangModuleLoader()) {
|
||||||
if (auto tu = dyn_cast<TranslationUnit>(M)) {
|
if (auto tu = dyn_cast<TranslationUnit>(M)) {
|
||||||
for (auto imported : tu->getImportedModules()) {
|
for (auto imported : tu->getImportedModules()) {
|
||||||
// Only check for Clang modules.
|
// Only check for Clang modules.
|
||||||
@@ -570,6 +470,7 @@ void swift::performNameBinding(TranslationUnit *TU, unsigned StartElem) {
|
|||||||
visited);
|
visited);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASTContext &ctx = TU->getASTContext();
|
||||||
llvm::DenseMap<clang::Module *, bool> topModules;
|
llvm::DenseMap<clang::Module *, bool> topModules;
|
||||||
for (auto clangImport : importedClangModules) {
|
for (auto clangImport : importedClangModules) {
|
||||||
// Look at the top-level module.
|
// Look at the top-level module.
|
||||||
@@ -579,13 +480,15 @@ void swift::performNameBinding(TranslationUnit *TU, unsigned StartElem) {
|
|||||||
if (knownTop == topModules.end()) {
|
if (knownTop == topModules.end()) {
|
||||||
// If we haven't looked for a Swift module corresponding to the
|
// If we haven't looked for a Swift module corresponding to the
|
||||||
// top-level module yet, do so now.
|
// top-level module yet, do so now.
|
||||||
llvm::OwningPtr<llvm::MemoryBuffer> buffer; // FIXME: wasteful!
|
|
||||||
if (Binder.findModule(topClangMod->Name, clangImport.second, buffer)) {
|
|
||||||
hasSwiftModule = false;
|
|
||||||
} else {
|
|
||||||
hasSwiftModule = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ImportDecl::AccessPathElement importPair =
|
||||||
|
{ ctx.getIdentifier(topClangMod->Name), clangImport.second };
|
||||||
|
|
||||||
|
// It's a little wasteful to load the module here and then again below,
|
||||||
|
// but the one below should pick up the same (already-loaded) module.
|
||||||
|
auto module = ctx.getModule(importPair);
|
||||||
|
|
||||||
|
hasSwiftModule = !isa<ClangModule>(module);
|
||||||
topModules[topClangMod] = hasSwiftModule;
|
topModules[topClangMod] = hasSwiftModule;
|
||||||
} else {
|
} else {
|
||||||
hasSwiftModule = knownTop->second;
|
hasSwiftModule = knownTop->second;
|
||||||
@@ -596,9 +499,8 @@ void swift::performNameBinding(TranslationUnit *TU, unsigned StartElem) {
|
|||||||
|
|
||||||
// Form an implicit import of the Swift module.
|
// Form an implicit import of the Swift module.
|
||||||
SmallVector<ImportDecl::AccessPathElement, 4> accessPath;
|
SmallVector<ImportDecl::AccessPathElement, 4> accessPath;
|
||||||
ASTContext &context = TU->getASTContext();
|
|
||||||
for (auto mod = clangImport.first; mod; mod = mod->Parent) {
|
for (auto mod = clangImport.first; mod; mod = mod->Parent) {
|
||||||
accessPath.push_back({ context.getIdentifier(mod->Name),
|
accessPath.push_back({ ctx.getIdentifier(mod->Name),
|
||||||
clangImport.second });
|
clangImport.second });
|
||||||
}
|
}
|
||||||
std::reverse(accessPath.begin(), accessPath.end());
|
std::reverse(accessPath.begin(), accessPath.end());
|
||||||
@@ -606,7 +508,7 @@ void swift::performNameBinding(TranslationUnit *TU, unsigned StartElem) {
|
|||||||
// Create an implicit import declaration and import it.
|
// Create an implicit import declaration and import it.
|
||||||
// FIXME: Mark as implicit!
|
// FIXME: Mark as implicit!
|
||||||
// FIXME: Actually pass through the whole access path.
|
// FIXME: Actually pass through the whole access path.
|
||||||
auto import = ImportDecl::create(context, TU, clangImport.second,
|
auto import = ImportDecl::create(ctx, TU, clangImport.second,
|
||||||
accessPath[0]);
|
accessPath[0]);
|
||||||
TU->Decls.push_back(import);
|
TU->Decls.push_back(import);
|
||||||
Binder.addImport(import, ImportedModules);
|
Binder.addImport(import, ImportedModules);
|
||||||
|
|||||||
123
lib/Sema/SourceLoader.cpp
Normal file
123
lib/Sema/SourceLoader.cpp
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
//===--- 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 A simple module loader that loads .swift source files as
|
||||||
|
/// TranslationUnit modules.
|
||||||
|
///
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "swift/Sema/SourceLoader.h"
|
||||||
|
#include "swift/Subsystems.h"
|
||||||
|
#include "swift/AST/AST.h"
|
||||||
|
#include "swift/AST/Component.h"
|
||||||
|
#include "swift/AST/Diagnostics.h"
|
||||||
|
#include "llvm/ADT/OwningPtr.h"
|
||||||
|
#include "llvm/ADT/SmallString.h"
|
||||||
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
|
#include "llvm/Support/Path.h"
|
||||||
|
#include "llvm/Support/SaveAndRestore.h"
|
||||||
|
#include "llvm/Support/SourceMgr.h"
|
||||||
|
#include "llvm/Support/system_error.h"
|
||||||
|
|
||||||
|
using namespace swift;
|
||||||
|
|
||||||
|
static llvm::error_code findModule(ASTContext &ctx, StringRef moduleID,
|
||||||
|
SourceLoc importLoc,
|
||||||
|
llvm::OwningPtr<llvm::MemoryBuffer> &buffer){
|
||||||
|
llvm::SmallString<64> moduleFilename(moduleID);
|
||||||
|
moduleFilename += ".swift";
|
||||||
|
|
||||||
|
llvm::SmallString<128> inputFilename;
|
||||||
|
|
||||||
|
// First, search in the directory corresponding to the import location.
|
||||||
|
// FIXME: This screams for a proper FileManager abstraction.
|
||||||
|
int currentBufferID = ctx.SourceMgr.FindBufferContainingLoc(importLoc.Value);
|
||||||
|
if (currentBufferID >= 0) {
|
||||||
|
const llvm::MemoryBuffer *importingBuffer
|
||||||
|
= ctx.SourceMgr.getBufferInfo(currentBufferID).Buffer;
|
||||||
|
StringRef currentDirectory
|
||||||
|
= llvm::sys::path::parent_path(importingBuffer->getBufferIdentifier());
|
||||||
|
if (!currentDirectory.empty()) {
|
||||||
|
inputFilename = currentDirectory;
|
||||||
|
llvm::sys::path::append(inputFilename, moduleFilename.str());
|
||||||
|
llvm::error_code err = llvm::MemoryBuffer::getFile(inputFilename, buffer);
|
||||||
|
if (!err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second, search in the current directory.
|
||||||
|
llvm::error_code err = llvm::MemoryBuffer::getFile(moduleFilename, buffer);
|
||||||
|
if (!err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// If we fail, search each import search path.
|
||||||
|
for (auto Path : ctx.ImportSearchPaths) {
|
||||||
|
inputFilename = Path;
|
||||||
|
llvm::sys::path::append(inputFilename, moduleFilename.str());
|
||||||
|
err = llvm::MemoryBuffer::getFile(inputFilename, buffer);
|
||||||
|
if (!err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Module *SourceLoader::loadModule(
|
||||||
|
SourceLoc importLoc,
|
||||||
|
ArrayRef<std::pair<Identifier, SourceLoc>> path) {
|
||||||
|
// FIXME: Swift submodules?
|
||||||
|
if (path.size() > 1)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto moduleID = path[0];
|
||||||
|
|
||||||
|
llvm::OwningPtr<llvm::MemoryBuffer> inputFile;
|
||||||
|
if (llvm::error_code err = findModule(Ctx, moduleID.first.str(),
|
||||||
|
moduleID.second, inputFile)) {
|
||||||
|
if (err.value() != llvm::errc::no_such_file_or_directory) {
|
||||||
|
Ctx.Diags.diagnose(moduleID.second, diag::sema_opening_import,
|
||||||
|
moduleID.first.str(), err.message());
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned bufferID = Ctx.SourceMgr.AddNewSourceBuffer(inputFile.take(),
|
||||||
|
moduleID.second.Value);
|
||||||
|
|
||||||
|
// FIXME: Turn off the constraint-based type checker for the imported 'swift'
|
||||||
|
// module.
|
||||||
|
llvm::SaveAndRestore<bool> saveUseCS(Ctx.LangOpts.UseConstraintSolver,
|
||||||
|
(Ctx.LangOpts.UseConstraintSolver &&
|
||||||
|
moduleID.first.str() != "swift"));
|
||||||
|
|
||||||
|
// For now, treat all separate modules as unique components.
|
||||||
|
Component *comp = new (Ctx.Allocate<Component>(1)) Component();
|
||||||
|
TranslationUnit *importTU = new (Ctx) TranslationUnit(moduleID.first, comp,
|
||||||
|
Ctx,
|
||||||
|
/*IsMainModule*/false,
|
||||||
|
/*IsReplModule*/false);
|
||||||
|
|
||||||
|
Ctx.LoadedModules[moduleID.first.str()] = importTU;
|
||||||
|
parseIntoTranslationUnit(importTU, bufferID);
|
||||||
|
|
||||||
|
// We have to do name binding on it to ensure that types are fully resolved.
|
||||||
|
// This should eventually be eliminated by having actual fully resolved binary
|
||||||
|
// dumps of the code instead of reparsing though.
|
||||||
|
// FIXME: We also need to deal with circular imports!
|
||||||
|
performNameBinding(importTU);
|
||||||
|
performTypeChecking(importTU);
|
||||||
|
|
||||||
|
return importTU;
|
||||||
|
}
|
||||||
@@ -337,13 +337,10 @@ public:
|
|||||||
|
|
||||||
// TODO: Integrate Clang LookupVisibleDecls with Swift LookupVisibleDecls.
|
// TODO: Integrate Clang LookupVisibleDecls with Swift LookupVisibleDecls.
|
||||||
// Doing so now makes REPL interaction too slow.
|
// Doing so now makes REPL interaction too slow.
|
||||||
if (!context.getDeclContext()->getASTContext().hasModuleLoader())
|
ASTContext &ast = context.getDeclContext()->getASTContext();
|
||||||
return;
|
if (auto clangImporter = ast.getClangModuleLoader())
|
||||||
|
static_cast<ClangImporter&>(*clangImporter).lookupVisibleDecls(*this);
|
||||||
ClangImporter &clangImporter
|
|
||||||
= static_cast<ClangImporter&>(
|
|
||||||
context.getDeclContext()->getASTContext().getModuleLoader());
|
|
||||||
clangImporter.lookupVisibleDecls(*this);
|
|
||||||
} else {
|
} else {
|
||||||
lookupVisibleDecls(*this, context.getBaseType());
|
lookupVisibleDecls(*this, context.getBaseType());
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user