diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 79a48b324e588..ff4cfafea73f0 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -762,6 +762,12 @@ class ASTContext final { bool isClang = false, bool isDWARF = false, bool IsInterface = false); + /// Add a module interface checker to use for this AST context. + void addModuleInterfaceChecker(std::unique_ptr checker); + + /// Retrieve the module interface checker associated with this AST context. + ModuleInterfaceChecker *getModuleInterfaceChecker() const; + /// Retrieve the module dependencies for the module with the given name. /// /// \param isUnderlyingClangModule When true, only look for a Clang module @@ -839,9 +845,6 @@ class ASTContext final { /// If there is no Clang module loader, returns a null pointer. /// The loader is owned by the AST context. ClangModuleLoader *getDWARFModuleLoader() const; - - /// Retrieve the module interface loader for this ASTContext. - ModuleLoader *getModuleInterfaceLoader() const; public: namelookup::ImportCache &getImportCache() const; diff --git a/include/swift/AST/ModuleLoader.h b/include/swift/AST/ModuleLoader.h index 9e5e836bac514..47d7682eca652 100644 --- a/include/swift/AST/ModuleLoader.h +++ b/include/swift/AST/ModuleLoader.h @@ -116,6 +116,23 @@ struct SubCompilerInstanceInfo { ArrayRef ExtraPCMArgs; }; +/// Abstract interface for a checker of module interfaces and prebuilt modules. +class ModuleInterfaceChecker { +public: + virtual std::vector + getCompiledModuleCandidatesForInterface(StringRef moduleName, + StringRef interfacePath) = 0; + + /// Given a list of potential ready-to-use compiled modules for \p interfacePath, + /// check if any one of them is up-to-date. If so, emit a forwarding module + /// to the candidate binary module to \p outPath. + virtual bool tryEmitForwardingModule(StringRef moduleName, + StringRef interfacePath, + ArrayRef candidates, + StringRef outPath) = 0; + virtual ~ModuleInterfaceChecker() = default; +}; + /// Abstract interface to run an action in a sub ASTContext. struct InterfaceSubContextDelegate { virtual std::error_code runInSubContext(StringRef moduleName, diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index 2e0cc1760e7a1..56c63173fb661 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -309,6 +309,35 @@ struct ModuleInterfaceLoaderOptions { ModuleInterfaceLoaderOptions() = default; }; +class ModuleInterfaceCheckerImpl: public ModuleInterfaceChecker { + friend class ModuleInterfaceLoader; + ASTContext &Ctx; + std::string CacheDir; + std::string PrebuiltCacheDir; + ModuleInterfaceLoaderOptions Opts; + +public: + explicit ModuleInterfaceCheckerImpl(ASTContext &Ctx, + StringRef cacheDir, + StringRef prebuiltCacheDir, + ModuleInterfaceLoaderOptions Opts) + : Ctx(Ctx), CacheDir(cacheDir), PrebuiltCacheDir(prebuiltCacheDir), + Opts(Opts) {} + + std::vector + getCompiledModuleCandidatesForInterface(StringRef moduleName, + StringRef interfacePath) override; + + /// Given a list of potential ready-to-use compiled modules for \p interfacePath, + /// check if any one of them is up-to-date. If so, emit a forwarding module + /// to the candidate binary module to \p outPath. + bool tryEmitForwardingModule(StringRef moduleName, + StringRef interfacePath, + ArrayRef candidates, + StringRef outPath) override; + bool isCached(StringRef DepPath); +}; + /// A ModuleLoader that runs a subordinate \c CompilerInvocation and /// \c CompilerInstance to convert .swiftinterface files to .swiftmodule /// files on the fly, caching the resulting .swiftmodules in the module cache @@ -316,20 +345,16 @@ struct ModuleInterfaceLoaderOptions { class ModuleInterfaceLoader : public SerializedModuleLoaderBase { friend class unittest::ModuleInterfaceLoaderTest; explicit ModuleInterfaceLoader( - ASTContext &ctx, StringRef cacheDir, StringRef prebuiltCacheDir, + ASTContext &ctx, ModuleInterfaceCheckerImpl &InterfaceChecker, DependencyTracker *tracker, ModuleLoadingMode loadMode, ArrayRef PreferInterfaceForModules, - bool IgnoreSwiftSourceInfoFile, ModuleInterfaceLoaderOptions Opts) - : SerializedModuleLoaderBase(ctx, tracker, loadMode, - IgnoreSwiftSourceInfoFile), - CacheDir(cacheDir), PrebuiltCacheDir(prebuiltCacheDir), - PreferInterfaceForModules(PreferInterfaceForModules), - Opts(Opts) {} + bool IgnoreSwiftSourceInfoFile) + : SerializedModuleLoaderBase(ctx, tracker, loadMode, IgnoreSwiftSourceInfoFile), + InterfaceChecker(InterfaceChecker), + PreferInterfaceForModules(PreferInterfaceForModules){} - std::string CacheDir; - std::string PrebuiltCacheDir; + ModuleInterfaceCheckerImpl &InterfaceChecker; ArrayRef PreferInterfaceForModules; - ModuleInterfaceLoaderOptions Opts; std::error_code findModuleFilesInDirectory( ImportPath::Element ModuleID, @@ -343,17 +368,14 @@ class ModuleInterfaceLoader : public SerializedModuleLoaderBase { bool isCached(StringRef DepPath) override; public: static std::unique_ptr - create(ASTContext &ctx, StringRef cacheDir, StringRef prebuiltCacheDir, + create(ASTContext &ctx, ModuleInterfaceCheckerImpl &InterfaceChecker, DependencyTracker *tracker, ModuleLoadingMode loadMode, ArrayRef PreferInterfaceForModules = {}, - ModuleInterfaceLoaderOptions Opts = ModuleInterfaceLoaderOptions(), bool IgnoreSwiftSourceInfoFile = false) { return std::unique_ptr( - new ModuleInterfaceLoader(ctx, cacheDir, prebuiltCacheDir, - tracker, loadMode, - PreferInterfaceForModules, - IgnoreSwiftSourceInfoFile, - Opts)); + new ModuleInterfaceLoader(ctx, InterfaceChecker, tracker, loadMode, + PreferInterfaceForModules, + IgnoreSwiftSourceInfoFile)); } /// Append visible module names to \p names. Note that names are possibly @@ -373,18 +395,6 @@ class ModuleInterfaceLoader : public SerializedModuleLoaderBase { StringRef ModuleName, StringRef InPath, StringRef OutPath, bool SerializeDependencyHashes, bool TrackSystemDependencies, ModuleInterfaceLoaderOptions Opts); - - std::vector - getCompiledModuleCandidatesForInterface(StringRef moduleName, - StringRef interfacePath) override; - - /// Given a list of potential ready-to-use compiled modules for \p interfacePath, - /// check if any one of them is up-to-date. If so, emit a forwarding module - /// to the candidate binary module to \p outPath. - bool tryEmitForwardingModule(StringRef moduleName, - StringRef interfacePath, - ArrayRef candidates, - StringRef outPath) override; }; struct InterfaceSubContextDelegateImpl: InterfaceSubContextDelegate { diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index f150c8481d1ef..e0aa714fd3914 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -201,18 +201,6 @@ class SerializedModuleLoaderBase : public ModuleLoader { virtual Optional getModuleDependencies( StringRef moduleName, ModuleDependenciesCache &cache, InterfaceSubContextDelegate &delegate) override; - - virtual std::vector - getCompiledModuleCandidatesForInterface(StringRef moduleName, - StringRef interfacePath) { - return std::vector(); - } - virtual bool tryEmitForwardingModule(StringRef moduleName, - StringRef interfacePath, - ArrayRef candidates, - StringRef outPath) { - return false; - } }; /// Imports serialized Swift modules into an ASTContext. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 4b8be5ff67243..f47353247d4e2 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -255,6 +255,9 @@ struct ASTContext::Implementation { /// The set of known protocols, lazily populated as needed. ProtocolDecl *KnownProtocols[NumKnownProtocols] = { }; + /// The module interface checker owned by the ASTContext. + std::unique_ptr InterfaceChecker; + /// The various module loaders that import external modules into this /// ASTContext. SmallVector, 4> ModuleLoaders; @@ -268,9 +271,6 @@ struct ASTContext::Implementation { /// The module loader used to load Clang modules from DWARF. ClangModuleLoader *TheDWARFModuleLoader = nullptr; - /// The module loader used to load Swift textual interface. - ModuleLoader *TheModuleInterfaceLoader = nullptr; - /// Map from Swift declarations to raw comments. llvm::DenseMap RawComments; @@ -1519,11 +1519,15 @@ void ASTContext::addModuleLoader(std::unique_ptr loader, if (IsClang && IsDwarf && !getImpl().TheDWARFModuleLoader) getImpl().TheDWARFModuleLoader = static_cast(loader.get()); - if (IsInterface && !getImpl().TheModuleInterfaceLoader) - getImpl().TheModuleInterfaceLoader = loader.get(); getImpl().ModuleLoaders.push_back(std::move(loader)); } +void ASTContext::addModuleInterfaceChecker( + std::unique_ptr checker) { + assert(!getImpl().InterfaceChecker && "Checker has been set already"); + getImpl().InterfaceChecker = std::move(checker); +} + Optional ASTContext::getModuleDependencies( StringRef moduleName, bool isUnderlyingClangModule, ModuleDependenciesCache &cache, InterfaceSubContextDelegate &delegate) { @@ -1610,8 +1614,10 @@ ClangModuleLoader *ASTContext::getDWARFModuleLoader() const { return getImpl().TheDWARFModuleLoader; } -ModuleLoader *ASTContext::getModuleInterfaceLoader() const { - return getImpl().TheModuleInterfaceLoader; +ModuleInterfaceChecker *ASTContext::getModuleInterfaceChecker() const { + auto *result = getImpl().InterfaceChecker.get(); + assert(result); + return result; } ModuleDecl *ASTContext::getLoadedModule( diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index a337d876eedc1..8ca60ba422374 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -493,6 +493,14 @@ bool CompilerInstance::setUpModuleLoaders() { return true; } + // Configure ModuleInterfaceChecker for the ASTContext. + auto const &Clang = clangImporter->getClangInstance(); + std::string ModuleCachePath = getModuleCachePathFromClang(Clang); + auto &FEOpts = Invocation.getFrontendOptions(); + ModuleInterfaceLoaderOptions LoaderOpts(FEOpts); + Context->addModuleInterfaceChecker( + std::make_unique(*Context, ModuleCachePath, + FEOpts.PrebuiltModuleCachePath, LoaderOpts)); // If implicit modules are disabled, we need to install an explicit module // loader. bool ExplicitModuleBuild = Invocation.getFrontendOptions().DisableImplicitModules; @@ -505,23 +513,15 @@ bool CompilerInstance::setUpModuleLoaders() { IgnoreSourceInfoFile); this->DefaultSerializedLoader = ESML.get(); Context->addModuleLoader(std::move(ESML)); - } - - if (MLM != ModuleLoadingMode::OnlySerialized) { - auto const &Clang = clangImporter->getClangInstance(); - std::string ModuleCachePath = getModuleCachePathFromClang(Clang); - auto &FEOpts = Invocation.getFrontendOptions(); - StringRef PrebuiltModuleCachePath = FEOpts.PrebuiltModuleCachePath; - ModuleInterfaceLoaderOptions LoaderOpts(FEOpts); - auto PIML = ModuleInterfaceLoader::create( - *Context, ModuleCachePath, PrebuiltModuleCachePath, - getDependencyTracker(), MLM, FEOpts.PreferInterfaceForModules, - LoaderOpts, - IgnoreSourceInfoFile); - Context->addModuleLoader(std::move(PIML), false, false, true); - } - - if (!ExplicitModuleBuild) { + } else { + if (MLM != ModuleLoadingMode::OnlySerialized) { + // We only need ModuleInterfaceLoader for implicit modules. + auto PIML = ModuleInterfaceLoader::create( + *Context, *static_cast(Context + ->getModuleInterfaceChecker()), getDependencyTracker(), MLM, + FEOpts.PreferInterfaceForModules, IgnoreSourceInfoFile); + Context->addModuleLoader(std::move(PIML), false, false, true); + } std::unique_ptr ISML = ImplicitSerializedModuleLoader::create(*Context, getDependencyTracker(), MLM, IgnoreSourceInfoFile); diff --git a/lib/Frontend/ModuleInterfaceBuilder.cpp b/lib/Frontend/ModuleInterfaceBuilder.cpp index 63ad78f6ecefd..45f9ea0867c55 100644 --- a/lib/Frontend/ModuleInterfaceBuilder.cpp +++ b/lib/Frontend/ModuleInterfaceBuilder.cpp @@ -170,10 +170,9 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( auto &SubInstance = *info.Instance; auto subInvocation = SubInstance.getInvocation(); // Try building forwarding module first. If succeed, return. - if (static_cast(SubInstance.getASTContext() - .getModuleInterfaceLoader())->tryEmitForwardingModule(moduleName, - interfacePath, - CompiledCandidates, OutPath)) { + if (SubInstance.getASTContext().getModuleInterfaceChecker() + ->tryEmitForwardingModule(moduleName, interfacePath, + CompiledCandidates, OutPath)) { return std::error_code(); } FrontendOptions &FEOpts = subInvocation.getFrontendOptions(); diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index ccbf279afcffa..ab054a3423ba8 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -335,6 +335,7 @@ struct ModuleRebuildInfo { /// a module that we'll build from a module interface. class ModuleInterfaceLoaderImpl { friend class swift::ModuleInterfaceLoader; + friend class swift::ModuleInterfaceCheckerImpl; ASTContext &ctx; llvm::vfs::FileSystem &fs; DiagnosticEngine &diags; @@ -907,10 +908,6 @@ class ModuleInterfaceLoaderImpl { return std::move(module.moduleBuffer); } - // If implicit module is disabled, we are done. - if (Opts.disableImplicitSwiftModule) { - return std::make_error_code(std::errc::not_supported); - } std::unique_ptr moduleBuffer; @@ -942,12 +939,16 @@ class ModuleInterfaceLoaderImpl { } // end anonymous namespace -bool ModuleInterfaceLoader::isCached(StringRef DepPath) { +bool ModuleInterfaceCheckerImpl::isCached(StringRef DepPath) { if (!CacheDir.empty() && DepPath.startswith(CacheDir)) return true; return !PrebuiltCacheDir.empty() && DepPath.startswith(PrebuiltCacheDir); } +bool ModuleInterfaceLoader::isCached(StringRef DepPath) { + return InterfaceChecker.isCached(DepPath); +} + /// Load a .swiftmodule associated with a .swiftinterface either from a /// cache or by converting it in a subordinate \c CompilerInstance, caching /// the results. @@ -990,8 +991,8 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory( auto ModuleName = ModuleID.Item.str(); ModuleInterfaceLoaderImpl Impl( Ctx, ModPath, InPath, ModuleName, - CacheDir, PrebuiltCacheDir, ModuleID.Loc, - Opts, + InterfaceChecker.CacheDir, InterfaceChecker.PrebuiltCacheDir, + ModuleID.Loc, InterfaceChecker.Opts, dependencyTracker, llvm::is_contained(PreferInterfaceForModules, ModuleName) ? @@ -1024,8 +1025,8 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory( } std::vector -ModuleInterfaceLoader::getCompiledModuleCandidatesForInterface(StringRef moduleName, - StringRef interfacePath) { +ModuleInterfaceCheckerImpl::getCompiledModuleCandidatesForInterface( + StringRef moduleName, StringRef interfacePath) { // Derive .swiftmodule path from the .swiftinterface path. auto newExt = file_types::getExtension(file_types::TY_SwiftModuleFile); llvm::SmallString<32> modulePath = interfacePath; @@ -1034,9 +1035,8 @@ ModuleInterfaceLoader::getCompiledModuleCandidatesForInterface(StringRef moduleN Ctx, modulePath, interfacePath, moduleName, CacheDir, PrebuiltCacheDir, SourceLoc(), Opts, - dependencyTracker, - llvm::is_contained(PreferInterfaceForModules, moduleName) ? - ModuleLoadingMode::PreferInterface : LoadMode); + nullptr, + ModuleLoadingMode::PreferSerialized); std::vector results; auto pair = Impl.getCompiledModuleCandidates(); // Add compiled module candidates only when they are non-empty. @@ -1047,7 +1047,7 @@ ModuleInterfaceLoader::getCompiledModuleCandidatesForInterface(StringRef moduleN return results; } -bool ModuleInterfaceLoader::tryEmitForwardingModule(StringRef moduleName, +bool ModuleInterfaceCheckerImpl::tryEmitForwardingModule(StringRef moduleName, StringRef interfacePath, ArrayRef candidates, StringRef outputPath) { @@ -1059,9 +1059,8 @@ bool ModuleInterfaceLoader::tryEmitForwardingModule(StringRef moduleName, Ctx, modulePath, interfacePath, moduleName, CacheDir, PrebuiltCacheDir, SourceLoc(), Opts, - dependencyTracker, - llvm::is_contained(PreferInterfaceForModules, moduleName) ? - ModuleLoadingMode::PreferInterface : LoadMode); + nullptr, + ModuleLoadingMode::PreferSerialized); SmallVector deps; std::unique_ptr moduleBuffer; for (auto mod: candidates) { diff --git a/lib/Serialization/ModuleDependencyScanner.cpp b/lib/Serialization/ModuleDependencyScanner.cpp index 6e4f82b6178ed..600744840648e 100644 --- a/lib/Serialization/ModuleDependencyScanner.cpp +++ b/lib/Serialization/ModuleDependencyScanner.cpp @@ -98,8 +98,7 @@ std::error_code PlaceholderSwiftModuleScanner::findModuleFilesInDirectory( static std::vector getCompiledCandidates(ASTContext &ctx, StringRef moduleName, StringRef interfacePath) { - return static_cast(ctx - .getModuleInterfaceLoader())->getCompiledModuleCandidatesForInterface( + return ctx.getModuleInterfaceChecker()->getCompiledModuleCandidatesForInterface( moduleName.str(), interfacePath); } diff --git a/unittests/FrontendTool/ModuleLoadingTests.cpp b/unittests/FrontendTool/ModuleLoadingTests.cpp index 0d80267cd90a9..30dd8553d16bb 100644 --- a/unittests/FrontendTool/ModuleLoadingTests.cpp +++ b/unittests/FrontendTool/ModuleLoadingTests.cpp @@ -103,8 +103,13 @@ class ModuleInterfaceLoaderTest : public testing::Test { ASTContext::get(langOpts, typeckOpts, searchPathOpts, clangImpOpts, sourceMgr, diags); + ctx->addModuleInterfaceChecker( + std::make_unique(*ctx, cacheDir, + prebuiltCacheDir, ModuleInterfaceLoaderOptions())); + auto loader = ModuleInterfaceLoader::create( - *ctx, cacheDir, prebuiltCacheDir, + *ctx, *static_cast( + ctx->getModuleInterfaceChecker()), /*dependencyTracker*/nullptr, ModuleLoadingMode::PreferSerialized);