diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 2fb3d000e0f3f..680d95ba467a5 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1290,15 +1290,6 @@ REMARK(module_api_import_aliases,none, "%select{, which reexports definition from %2|}3", (const Decl *, ModuleDecl *, ModuleDecl *, bool)) -REMARK(dependency_scan_skip_module_invalid,none, - "module file '%0' skipped by the dependency scan because it is " - "incompatible with this Swift compiler: %1", (StringRef, StringRef)) -WARNING(skip_module_not_testable,none, - "ignore swiftmodule built without '-enable-testing': %0", (StringRef)) -WARNING(dependency_scan_module_incompatible, none, - "module file '%0' is incompatible with this Swift compiler: %1", - (StringRef, StringRef)) - REMARK(macro_loaded,none, "loaded macro implementation module %0 from " "%select{shared library '%2'|executable '%2'|" @@ -2380,9 +2371,11 @@ ERROR(alignment_not_power_of_two,none, "alignment value must be a power of two", ()) // Dependency Scanning -ERROR(dependency_scan_module_not_found, none, "Unable to find module dependency: '%0'", (StringRef)) +ERROR(dependency_scan_module_not_found, none, "unable to resolve module dependency: '%0'", (StringRef)) + GROUPED_ERROR(dependency_scan_module_not_found_on_specified_search_paths, MissingModuleOnKnownPaths, none, - "Compilation search paths unable to resolve module dependency: '%0'", (StringRef)) + "compilation search paths unable to resolve module dependency: '%0'", (StringRef)) + NOTE(unresolved_import_location,none, "also imported here", ()) NOTE(dependency_as_imported_by_main_module,none, @@ -2391,10 +2384,21 @@ NOTE(dependency_as_imported_by, none, "a dependency of %select{Swift|Clang}2 module '%0': '%1'", (StringRef, StringRef, bool)) NOTE(inherited_search_path_resolves_module,none, "'%0' can be found using a search path that was specified when building module '%1' ('%2'). " - "This search path was not explicitly specified on the current compilation.", (StringRef, StringRef, StringRef)) + "This search path was not explicitly specified on the current compilation", (StringRef, StringRef, StringRef)) + +ERROR(dependency_scan_compatible_swift_module_not_found, none, + "unable to resolve Swift module dependency to a compatible module: '%0'", + (StringRef)) +NOTE(dependency_scan_incompatible_module_found,none, + "found incompatible module '%0': %1", (StringRef, StringRef)) + +WARNING(dependency_scan_module_incompatible, none, + "module file '%0' is incompatible with this Swift compiler: %1", + (StringRef, StringRef)) + +ERROR(clang_dependency_scan_error, none, "clang dependency scanning failure: %0", (StringRef)) -ERROR(clang_dependency_scan_error, none, "Clang dependency scanner failure: %0", (StringRef)) -ERROR(clang_header_dependency_scan_error, none, "Bridging header dependency scan failure: %0", (StringRef)) +ERROR(clang_header_dependency_scan_error, none, "bridging header dependency scanning failure: %0", (StringRef)) // Enum annotations ERROR(indirect_case_without_payload,none, diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index 1427845bc760a..dc11457bdc837 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -124,6 +124,10 @@ struct ScannerImportStatementInfo { uint32_t columnNumber; }; + ScannerImportStatementInfo(std::string importIdentifier) + : importIdentifier(importIdentifier), importLocations(), + isExported(false), accessLevel(AccessLevel::Public) {} + ScannerImportStatementInfo(std::string importIdentifier, bool isExported, AccessLevel accessLevel) : importIdentifier(importIdentifier), importLocations(), diff --git a/include/swift/DependencyScan/ModuleDependencyScanner.h b/include/swift/DependencyScan/ModuleDependencyScanner.h index 416fd8f46ed13..6d64b53c68876 100644 --- a/include/swift/DependencyScan/ModuleDependencyScanner.h +++ b/include/swift/DependencyScan/ModuleDependencyScanner.h @@ -46,7 +46,7 @@ class ModuleDependencyScanningWorker { &alreadySeenModules); /// Retrieve the module dependencies for the Swift module with the given name. - ModuleDependencyVector scanFilesystemForSwiftModuleDependency( + SwiftModuleScannerQueryResult scanFilesystemForSwiftModuleDependency( Identifier moduleName, bool isTestableImport = false); /// Query dependency information for header dependencies @@ -122,27 +122,67 @@ class SwiftDependencyTracker { SwiftDependencyTracker(std::shared_ptr CAS, llvm::PrefixMapper *Mapper, const CompilerInvocation &CI); - + void startTracking(bool includeCommonDeps = true); void trackFile(const Twine &path); llvm::Expected createTreeFromDependencies(); - + private: llvm::IntrusiveRefCntPtr FS; std::shared_ptr CAS; llvm::PrefixMapper *Mapper; - + struct FileEntry { llvm::cas::ObjectRef FileRef; size_t Size; - + FileEntry(llvm::cas::ObjectRef FileRef, size_t Size) - : FileRef(FileRef), Size(Size) {} + : FileRef(FileRef), Size(Size) {} }; llvm::StringMap CommonFiles; std::map TrackedFiles; }; +class ModuleDependencyIssueReporter { +private: + ModuleDependencyIssueReporter(DiagnosticEngine &Diagnostics) + : Diagnostics(Diagnostics) {} + + /// Diagnose scanner failure and attempt to reconstruct the dependency + /// path from the main module to the missing dependency + void diagnoseModuleNotFoundFailure( + const ScannerImportStatementInfo &moduleImport, + const ModuleDependenciesCache &cache, + std::optional dependencyOf, + std::optional> + resolvingSerializedSearchPath, + std::optional< + std::vector> + foundIncompatibleCandidates = std::nullopt); + + /// Upon query failure, if incompatible binary module + /// candidates were found, emit a failure diagnostic + void diagnoseFailureOnOnlyIncompatibleCandidates( + const ScannerImportStatementInfo &moduleImport, + const std::vector + &candidates, + const ModuleDependenciesCache &cache, + std::optional dependencyOf); + + /// Emit warnings for each discovered binary Swift module + /// which was incompatible with the current compilation + /// when querying \c moduleName + void warnOnIncompatibleCandidates( + StringRef moduleName, + const std::vector + &candidates); + + DiagnosticEngine &Diagnostics; + std::unordered_set ReportedMissing; + // Restrict access to the parent scanner class. + friend class ModuleDependencyScanner; +}; + class ModuleDependencyScanner { public: ModuleDependencyScanner(SwiftDependencyScanningService &ScanningService, @@ -246,7 +286,7 @@ class ModuleDependencyScanner { StringRef mainModuleName, ModuleDependenciesCache &cache, llvm::function_ref action); - /// Performance BridgingHeader Chaining. + /// Perform Bridging Header Chaining. llvm::Error performBridgingHeaderChaining(const ModuleDependencyID &rootModuleID, ModuleDependenciesCache &cache, @@ -261,12 +301,6 @@ class ModuleDependencyScanner { /// for a given module name. Identifier getModuleImportIdentifier(StringRef moduleName); - /// Diagnose scanner failure and attempt to reconstruct the dependency - /// path from the main module to the missing dependency. - void diagnoseScannerFailure(const ScannerImportStatementInfo &moduleImport, - const ModuleDependenciesCache &cache, - std::optional dependencyOf); - /// Assuming the \c `moduleImport` failed to resolve, /// iterate over all binary Swift module dependencies with serialized /// search paths and attempt to diagnose if the failed-to-resolve module @@ -275,12 +309,12 @@ class ModuleDependencyScanner { std::optional> attemptToFindResolvingSerializedSearchPath( const ScannerImportStatementInfo &moduleImport, - const ModuleDependenciesCache &cache, const SourceLoc &importLoc); + const ModuleDependenciesCache &cache); private: const CompilerInvocation &ScanCompilerInvocation; ASTContext &ScanASTContext; - DiagnosticEngine &Diagnostics; + ModuleDependencyIssueReporter IssueReporter; /// The available pool of workers for filesystem module search unsigned NumThreads; diff --git a/include/swift/Serialization/ScanningLoaders.h b/include/swift/Serialization/ScanningLoaders.h index d37a16a30fd6d..f5f503c14ebd4 100644 --- a/include/swift/Serialization/ScanningLoaders.h +++ b/include/swift/Serialization/ScanningLoaders.h @@ -18,6 +18,28 @@ #include "swift/Serialization/SerializedModuleLoader.h" namespace swift { + +/// Result of looking up a Swift module on the current filesystem +/// search paths. +struct SwiftModuleScannerQueryResult { + struct IncompatibleCandidate { + std::string path; + std::string incompatibilityReason; + }; + + SwiftModuleScannerQueryResult() + : foundDependencyInfo(std::nullopt), incompatibleCandidates() {} + + SwiftModuleScannerQueryResult( + std::optional &&dependencyInfo, + std::vector &&candidates) + : foundDependencyInfo(dependencyInfo), + incompatibleCandidates(candidates) {} + + std::optional foundDependencyInfo; + std::vector incompatibleCandidates; +}; + /// A module "loader" that looks for .swiftinterface and .swiftmodule files /// for the purpose of determining dependencies, but does not attempt to /// load the module files. @@ -59,23 +81,27 @@ class SwiftModuleScanner : public SerializedModuleLoaderBase { /// Swift module compilation commands std::vector swiftModuleClangCC1CommandLineArgs; + /// Constituents of a result of a given Swift module query, + /// reset at the end of every query. + std::optional foundDependencyInfo; + std::vector + incompatibleCandidates; public: - std::optional dependencies; - - SwiftModuleScanner(ASTContext &ctx, ModuleLoadingMode LoadMode, - InterfaceSubContextDelegate &astDelegate, - StringRef moduleOutputPath, StringRef sdkModuleOutputPath, - std::vector swiftModuleClangCC1CommandLineArgs) + SwiftModuleScanner( + ASTContext &ctx, ModuleLoadingMode LoadMode, + InterfaceSubContextDelegate &astDelegate, StringRef moduleOutputPath, + StringRef sdkModuleOutputPath, + std::vector swiftModuleClangCC1CommandLineArgs) : SerializedModuleLoaderBase(ctx, nullptr, LoadMode, /*IgnoreSwiftSourceInfoFile=*/true), - astDelegate(astDelegate), - moduleOutputPath(moduleOutputPath), + astDelegate(astDelegate), moduleOutputPath(moduleOutputPath), sdkModuleOutputPath(sdkModuleOutputPath), - swiftModuleClangCC1CommandLineArgs(swiftModuleClangCC1CommandLineArgs) {} + swiftModuleClangCC1CommandLineArgs(swiftModuleClangCC1CommandLineArgs) { + } /// Perform a filesystem search for a Swift module with a given name - llvm::SmallVector, 1> - lookupSwiftModule(Identifier moduleName, bool isTestableImport); + SwiftModuleScannerQueryResult lookupSwiftModule(Identifier moduleName, + bool isTestableImport); }; } // namespace swift diff --git a/lib/DependencyScan/ModuleDependencyScanner.cpp b/lib/DependencyScan/ModuleDependencyScanner.cpp index 68cf6784152ec..238217c83ca7d 100644 --- a/lib/DependencyScan/ModuleDependencyScanner.cpp +++ b/lib/DependencyScan/ModuleDependencyScanner.cpp @@ -297,7 +297,7 @@ ModuleDependencyScanningWorker::ModuleDependencyScanningWorker( swiftModuleClangCC1CommandLineArgs); } -ModuleDependencyVector +SwiftModuleScannerQueryResult ModuleDependencyScanningWorker::scanFilesystemForSwiftModuleDependency( Identifier moduleName, bool isTestableImport) { return swiftModuleScannerLoader->lookupSwiftModule(moduleName, @@ -576,7 +576,7 @@ ModuleDependencyScanner::ModuleDependencyScanner( std::shared_ptr ActionCache, DiagnosticEngine &Diagnostics, bool ParallelScan) : ScanCompilerInvocation(ScanCompilerInvocation), - ScanASTContext(ScanASTContext), Diagnostics(Diagnostics), + ScanASTContext(ScanASTContext), IssueReporter(Diagnostics), NumThreads(ParallelScan ? llvm::hardware_concurrency().compute_thread_count() : 1), @@ -944,8 +944,9 @@ ModuleDependencyScanner::performDependencyScan(ModuleDependencyID rootModuleID, if (ScanCompilerInvocation.getSearchPathOptions().BridgingHeaderChaining) { auto err = performBridgingHeaderChaining(rootModuleID, cache, allModules); if (err) - Diagnostics.diagnose(SourceLoc(), diag::error_scanner_extra, - toString(std::move(err))); + IssueReporter.Diagnostics.diagnose(SourceLoc(), + diag::error_scanner_extra, + toString(std::move(err))); } return allModules.takeVector(); @@ -1145,7 +1146,8 @@ void ModuleDependencyScanner::resolveAllClangModuleDependencies( std::lock_guard guard(cacheAccessLock); moduleLookupResult.insert_or_assign(moduleName, moduleDependencies); if (!moduleDependencies.empty()) - cache.recordDependencies(moduleDependencies, Diagnostics); + cache.recordDependencies(moduleDependencies, + IssueReporter.Diagnostics); } }; @@ -1228,8 +1230,13 @@ void ModuleDependencyScanner::resolveAllClangModuleDependencies( auto optionalCachedModuleInfo = cache.findDependency(unresolvedModuleID); if (optionalCachedModuleInfo.has_value()) importedClangDependencies.insert(unresolvedModuleID); - else - diagnoseScannerFailure(unresolvedImport, cache, moduleID); + else { + // Failed to resolve module dependency. + IssueReporter.diagnoseModuleNotFoundFailure( + unresolvedImport, cache, moduleID, + attemptToFindResolvingSerializedSearchPath(unresolvedImport, + cache)); + } } if (!importedClangDependencies.empty()) @@ -1303,10 +1310,7 @@ void ModuleDependencyScanner::resolveSwiftImportsForModule( return; auto moduleDependencyInfo = cache.findKnownDependency(moduleID); - llvm::StringMap> moduleLookupResult; - for (const auto &dependsOn : moduleDependencyInfo.getModuleImports()) - moduleLookupResult.insert( - std::make_pair(dependsOn.importIdentifier, std::nullopt)); + llvm::StringMap moduleLookupResult; std::mutex lookupResultLock; // A scanning task to query a module by-name. If the module already exists @@ -1362,22 +1366,26 @@ void ModuleDependencyScanner::resolveSwiftImportsForModule( if (moduleID.ModuleName == moduleImport.importIdentifier) return; auto lookupResult = moduleLookupResult[moduleImport.importIdentifier]; - // The imported module was found in the cache - if (lookupResult == std::nullopt) { - auto cachedInfo = - cache.findSwiftDependency(moduleImport.importIdentifier); - if (cachedInfo.has_value()) - importedSwiftDependencies.insert( - {moduleImport.importIdentifier, cachedInfo.value()->getKind()}); - } else { - // Cache discovered module dependencies. - if (!lookupResult.value().empty()) { - cache.recordDependencies(lookupResult.value(), Diagnostics); - importedSwiftDependencies.insert( - {moduleImport.importIdentifier, - lookupResult.value()[0].first.Kind}); - } - } + + // Query found module + if (lookupResult.foundDependencyInfo) { + cache.recordDependency(moduleImport.importIdentifier, + *(lookupResult.foundDependencyInfo)); + importedSwiftDependencies.insert( + {moduleImport.importIdentifier, + lookupResult.foundDependencyInfo->getKind()}); + IssueReporter.warnOnIncompatibleCandidates( + moduleImport.importIdentifier, + lookupResult.incompatibleCandidates); + // Module was resolved from a cache + } else if (auto cachedInfo = cache.findSwiftDependency( + moduleImport.importIdentifier)) + importedSwiftDependencies.insert( + {moduleImport.importIdentifier, cachedInfo.value()->getKind()}); + else + IssueReporter.diagnoseFailureOnOnlyIncompatibleCandidates( + moduleImport, lookupResult.incompatibleCandidates, cache, + std::nullopt); }; for (const auto &importInfo : moduleDependencyInfo.getModuleImports()) @@ -1489,26 +1497,32 @@ void ModuleDependencyScanner::resolveSwiftOverlayDependenciesForModule( findAllImportedClangModules(dep.ModuleName, cache, allClangDependencies, knownModules); - llvm::StringMap> - swiftOverlayLookupResult; - for (const auto &clangDep : allClangDependencies) - swiftOverlayLookupResult.insert(std::make_pair(clangDep, std::nullopt)); - + llvm::StringMap swiftOverlayLookupResult; + std::mutex lookupResultLock; + // A scanning task to query a Swift module by-name. If the module already // exists in the cache, do nothing and return. - auto scanForSwiftDependency = [this, &cache, &swiftOverlayLookupResult]( + auto scanForSwiftDependency = [this, &cache, &lookupResultLock, + &swiftOverlayLookupResult]( Identifier moduleIdentifier) { auto moduleName = moduleIdentifier.str(); - if (cache.hasDependency(moduleName, ModuleDependencyKind::SwiftInterface) || - cache.hasDependency(moduleName, ModuleDependencyKind::SwiftBinary)) - return; + { + std::lock_guard guard(lookupResultLock); + if (cache.hasDependency(moduleName, ModuleDependencyKind::SwiftInterface) || + cache.hasDependency(moduleName, ModuleDependencyKind::SwiftBinary)) + return; + } auto moduleDependencies = withDependencyScanningWorker( [moduleIdentifier](ModuleDependencyScanningWorker *ScanningWorker) { return ScanningWorker->scanFilesystemForSwiftModuleDependency( moduleIdentifier, /* isTestableImport */ false); }); - swiftOverlayLookupResult.insert_or_assign(moduleName, moduleDependencies); + + { + std::lock_guard guard(lookupResultLock); + swiftOverlayLookupResult.insert_or_assign(moduleName, moduleDependencies); + } }; // Enque asynchronous lookup tasks @@ -1523,18 +1537,22 @@ void ModuleDependencyScanner::resolveSwiftOverlayDependenciesForModule( moduleID](const std::string &moduleName) { auto lookupResult = swiftOverlayLookupResult[moduleName]; if (moduleName != moduleID.ModuleName) { - if (lookupResult == std::nullopt) { - auto cachedInfo = cache.findSwiftDependency(moduleName); - if (cachedInfo.has_value()) - swiftOverlayDependencies.insert( - {moduleName, cachedInfo.value()->getKind()}); - } else { - // Cache discovered module dependencies. - cache.recordDependencies(lookupResult.value(), Diagnostics); - if (!lookupResult.value().empty()) - swiftOverlayDependencies.insert( - {moduleName, lookupResult.value()[0].first.Kind}); - } + + // Query found module + if (lookupResult.foundDependencyInfo) { + cache.recordDependency(moduleName, *(lookupResult.foundDependencyInfo)); + swiftOverlayDependencies.insert( + {moduleName, lookupResult.foundDependencyInfo->getKind()}); + IssueReporter.warnOnIncompatibleCandidates( + moduleName, lookupResult.incompatibleCandidates); + // Module was resolved from a cache + } else if (auto cachedInfo = cache.findSwiftDependency(moduleName)) + swiftOverlayDependencies.insert( + {moduleName, cachedInfo.value()->getKind()}); + else + IssueReporter.diagnoseFailureOnOnlyIncompatibleCandidates( + ScannerImportStatementInfo(moduleName), + lookupResult.incompatibleCandidates, cache, std::nullopt); } }; for (const auto &clangDep : allClangDependencies) @@ -1783,10 +1801,23 @@ llvm::Error ModuleDependencyScanner::performBridgingHeaderChaining( return llvm::Error::success(); } -void ModuleDependencyScanner::diagnoseScannerFailure( +void ModuleDependencyIssueReporter::diagnoseModuleNotFoundFailure( const ScannerImportStatementInfo &moduleImport, const ModuleDependenciesCache &cache, - std::optional dependencyOf) { + std::optional dependencyOf, + std::optional> + resolvingSerializedSearchPath, + std::optional< + std::vector> + foundIncompatibleCandidates) { + // Do not report the same failure multiple times. This can + // happen, for example, when we first report that a valid Swift module is + // missing and then look it up again as a Swift overlay of its underlying + // Clang module. + if (ReportedMissing.find(moduleImport.importIdentifier) != + ReportedMissing.end()) + return; + SourceLoc importLoc = SourceLoc(); if (!moduleImport.importLocations.empty()) { auto locInfo = moduleImport.importLocations[0]; @@ -1794,21 +1825,32 @@ void ModuleDependencyScanner::diagnoseScannerFailure( locInfo.bufferIdentifier, locInfo.lineNumber, locInfo.columnNumber); } - // Attempt to determine if any of the binary Swift module dependencies contain - // serialized search paths where the missing module may be found. If yes, - // emit a specialized diagnostic letting the user know which search path - // is missing in current compilation. - auto resolvedModuleDefiningPath = attemptToFindResolvingSerializedSearchPath( - moduleImport, cache, importLoc); - if (resolvedModuleDefiningPath) { + // Emit the top-level error diagnostic, which is one of 3 possibilities: + // 1. Module dependency can not be found but could be resolved if using search + // paths serialized into some binary Swift module dependency + // + // 2. Swift Module dependency can not be found but we did find binary Swift + // module candidates for this module which are not compatible with current + // compilation + // + // 3. All other generic "module not found" cases + if (resolvingSerializedSearchPath) { Diagnostics.diagnose( importLoc, diag::dependency_scan_module_not_found_on_specified_search_paths, moduleImport.importIdentifier); Diagnostics.diagnose(importLoc, diag::inherited_search_path_resolves_module, moduleImport.importIdentifier, - resolvedModuleDefiningPath->first.ModuleName, - resolvedModuleDefiningPath->second); + resolvingSerializedSearchPath->first.ModuleName, + resolvingSerializedSearchPath->second); + } else if (foundIncompatibleCandidates) { + Diagnostics.diagnose( + importLoc, diag::dependency_scan_compatible_swift_module_not_found, + moduleImport.importIdentifier); + for (const auto &candidate : *foundIncompatibleCandidates) + Diagnostics.diagnose(importLoc, + diag::dependency_scan_incompatible_module_found, + candidate.path, candidate.incompatibilityReason); } else Diagnostics.diagnose(importLoc, diag::dependency_scan_module_not_found, moduleImport.importIdentifier); @@ -1856,7 +1898,7 @@ void ModuleDependencyScanner::diagnoseScannerFailure( } } - // Emit notes for every other location where the failed-to-resolve + // Emit notes for every other known location where the failed-to-resolve // module is imported. if (moduleImport.importLocations.size() > 1) { for (size_t i = 1; i < moduleImport.importLocations.size(); ++i) { @@ -1866,12 +1908,42 @@ void ModuleDependencyScanner::diagnoseScannerFailure( Diagnostics.diagnose(importLoc, diag::unresolved_import_location); } } + + ReportedMissing.insert(moduleImport.importIdentifier); +} + +void ModuleDependencyIssueReporter::diagnoseFailureOnOnlyIncompatibleCandidates( + const ScannerImportStatementInfo &moduleImport, + const std::vector + &candidates, + const ModuleDependenciesCache &cache, + std::optional dependencyOf) { + // If no incompatible candidates were discovered, + // the dependency scanning failure will be caught downstream. + if (candidates.empty()) + return; + + diagnoseModuleNotFoundFailure(moduleImport, cache, dependencyOf, + /* resolvingSerializedSearchPath */ std::nullopt, + candidates); +} + +void ModuleDependencyIssueReporter::warnOnIncompatibleCandidates( + StringRef moduleName, + const std::vector + &candidates) { + // If the dependency was ultimately resolved to a different + // binary module or a textual module, emit warnings about + // having encountered incompatible binary modules. + for (const auto &candidate : candidates) + Diagnostics.diagnose(SourceLoc(), diag::dependency_scan_module_incompatible, + candidate.path, candidate.incompatibilityReason); } std::optional> ModuleDependencyScanner::attemptToFindResolvingSerializedSearchPath( const ScannerImportStatementInfo &moduleImport, - const ModuleDependenciesCache &cache, const SourceLoc &importLoc) { + const ModuleDependenciesCache &cache) { std::set binarySwiftModuleDepIDs = collectBinarySwiftDeps(cache); @@ -1890,23 +1962,26 @@ ModuleDependencyScanner::attemptToFindResolvingSerializedSearchPath( [this, &binaryModInfo, &moduleImport, &binaryDepID](ModuleDependencyScanningWorker *ScanningWorker) -> std::optional> { - ModuleDependencyVector result; for (const auto &sp : binaryModInfo->serializedSearchPaths) ScanningWorker->workerASTContext->addSearchPath( sp.Path, sp.IsFramework, sp.IsSystem); - result = ScanningWorker->scanFilesystemForSwiftModuleDependency( - getModuleImportIdentifier(moduleImport.importIdentifier), - /* isTestableImport */ false); - if (!result.empty()) - return std::make_pair(binaryDepID, - result[0].second.getModuleDefiningPath()); + auto importIdentifier = + getModuleImportIdentifier(moduleImport.importIdentifier); + SwiftModuleScannerQueryResult swiftResult = + ScanningWorker->scanFilesystemForSwiftModuleDependency( + importIdentifier, /* isTestableImport */ false); + if (swiftResult.foundDependencyInfo) + return std::make_pair( + binaryDepID, + swiftResult.foundDependencyInfo->getModuleDefiningPath()); - result = ScanningWorker->scanFilesystemForClangModuleDependency( - getModuleImportIdentifier(moduleImport.importIdentifier), {}); - if (!result.empty()) + ModuleDependencyVector clangResult = + ScanningWorker->scanFilesystemForClangModuleDependency( + importIdentifier, {}); + if (!clangResult.empty()) return std::make_pair( - binaryDepID, result[0].second.getModuleDefiningPath()); + binaryDepID, clangResult[0].second.getModuleDefiningPath()); return std::nullopt; }); if (result) diff --git a/lib/Serialization/ScanningLoaders.cpp b/lib/Serialization/ScanningLoaders.cpp index bd691d8218476..1fc077f433b76 100644 --- a/lib/Serialization/ScanningLoaders.cpp +++ b/lib/Serialization/ScanningLoaders.cpp @@ -61,26 +61,26 @@ std::error_code SwiftModuleScanner::findModuleFilesInDirectory( isTestableDependencyLookup || !InPath) { if (fs.exists(ModPath)) { // The module file will be loaded directly. - auto dependencies = scanBinaryModuleFile( + auto dependencyInfo = scanBinaryModuleFile( ModuleID.Item, ModPath, IsFramework, isTestableDependencyLookup, /* isCandidateForTextualModule */ false); - if (dependencies) { - this->dependencies = std::move(dependencies.get()); + if (dependencyInfo) { + this->foundDependencyInfo = std::move(dependencyInfo.get()); return std::error_code(); } - return dependencies.getError(); + return dependencyInfo.getError(); } return std::make_error_code(std::errc::no_such_file_or_directory); } assert(InPath); - auto dependencies = scanInterfaceFile(ModuleID.Item, *InPath, IsFramework, - isTestableDependencyLookup); - if (dependencies) { - this->dependencies = std::move(dependencies.get()); + auto dependencyInfo = scanInterfaceFile(ModuleID.Item, *InPath, IsFramework, + isTestableDependencyLookup); + if (dependencyInfo) { + this->foundDependencyInfo = std::move(dependencyInfo.get()); return std::error_code(); } - return dependencies.getError(); + return dependencyInfo.getError(); } static std::vector getCompiledCandidates(ASTContext &ctx, @@ -266,21 +266,14 @@ llvm::ErrorOr SwiftModuleScanner::scanBinaryModuleFile( // it would be helpful to let the user know why the scanner // was not able to use it because the scan will ultimately fail to // resolve this dependency due to this incompatibility. - if (!isCandidateForTextualModule) - Ctx.Diags.diagnose(SourceLoc(), - diag::dependency_scan_module_incompatible, - binaryModulePath.str(), loadFailureReason.value()); - - if (Ctx.LangOpts.EnableModuleLoadingRemarks) - Ctx.Diags.diagnose(SourceLoc(), - diag::dependency_scan_skip_module_invalid, - binaryModulePath.str(), loadFailureReason.value()); + incompatibleCandidates.push_back({binaryModulePath.str(), + loadFailureReason.value()}); return std::make_error_code(std::errc::no_such_file_or_directory); } if (isTestableImport && !loadedModuleFile->isTestable()) { - Ctx.Diags.diagnose(SourceLoc(), diag::skip_module_not_testable, - binaryModulePath.str()); + incompatibleCandidates.push_back({binaryModulePath.str(), + "module built without '-enable-testing'"}); return std::make_error_code(std::errc::no_such_file_or_directory); } } @@ -337,22 +330,21 @@ llvm::ErrorOr SwiftModuleScanner::scanBinaryModuleFile( return std::move(dependencies); } -ModuleDependencyVector +SwiftModuleScannerQueryResult SwiftModuleScanner::lookupSwiftModule(Identifier moduleName, bool isTestableImport) { // When we exit, ensure we clear dependencies discovered on this query - SWIFT_DEFER { dependencies = std::nullopt; }; + SWIFT_DEFER { + foundDependencyInfo = std::nullopt; + incompatibleCandidates = {}; + }; ImportPath::Module::Builder builder(moduleName); auto modulePath = builder.get(); - // Check whether there is a module with this name that we can import. - if (canImportModule(modulePath, SourceLoc(), nullptr, isTestableImport)) { - ModuleDependencyVector moduleDependnecies; - moduleDependnecies.push_back(std::make_pair( - ModuleDependencyID{moduleName.str().str(), dependencies->getKind()}, - *(dependencies))); - return moduleDependnecies; - } - - return {}; + // Execute the check to determine whether there is a module with this name + // that we can import. This check will populate the result fields if one is + // found. + canImportModule(modulePath, SourceLoc(), nullptr, isTestableImport); + return SwiftModuleScannerQueryResult( + std::move(foundDependencyInfo), std::move(incompatibleCandidates)); } diff --git a/test/ScanDependencies/bridging_header_error.swift b/test/ScanDependencies/bridging_header_error.swift index 6aa471f6f6cd3..8a948e239a60c 100644 --- a/test/ScanDependencies/bridging_header_error.swift +++ b/test/ScanDependencies/bridging_header_error.swift @@ -4,4 +4,4 @@ // RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/module-cache %s -o %t/deps.json -import-objc-header %t/does-this-header-even-exist.h &> %t/diagnostic_output.txt // RUN: cat %t/diagnostic_output.txt | %FileCheck %s -// CHECK: error: Bridging header dependency scan failure: error: no such file or directory: '{{.*}}does-this-header-even-exist.h' +// CHECK: error: bridging header dependency scanning failure: error: no such file or directory: '{{.*}}does-this-header-even-exist.h' diff --git a/test/ScanDependencies/cached-missing-module-found-in-serialized-paths.swift b/test/ScanDependencies/cached-missing-module-found-in-serialized-paths.swift index 8d0e0467c4d07..c078691e1ecd2 100644 --- a/test/ScanDependencies/cached-missing-module-found-in-serialized-paths.swift +++ b/test/ScanDependencies/cached-missing-module-found-in-serialized-paths.swift @@ -21,8 +21,8 @@ // CHECK: remark: Incremental module scan: Re-using serialized module scanning dependency cache from: '{{.*}}cache.moddepcache'. // CHECK: remark: Incremental module scan: Dependency info for module 'C' invalidated due to a modified input since last scan: '{{.*}}deps{{/|\\}}C.swiftinterface'. // CHECK: remark: Incremental module scan: Dependency info for module 'deps' invalidated due to an out-of-date dependency. -// CHECK: error: Compilation search paths unable to resolve module dependency: 'C' -// CHECK: note: 'C' can be found using a search path that was specified when building module 'B' ('{{.*}}moreDeps'). This search path was not explicitly specified on the current compilation. +// CHECK: error: compilation search paths unable to resolve module dependency: 'C' +// CHECK: note: 'C' can be found using a search path that was specified when building module 'B' ('{{.*}}moreDeps'). This search path was not explicitly specified on the current compilation // CHECK: note: a dependency of main module 'deps' //--- moreDeps/C.swiftinterface diff --git a/test/ScanDependencies/candidate_binary_module_diagnostics.swift b/test/ScanDependencies/candidate_binary_module_diagnostics.swift new file mode 100644 index 0000000000000..59c5a6fdf1026 --- /dev/null +++ b/test/ScanDependencies/candidate_binary_module_diagnostics.swift @@ -0,0 +1,22 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/module-cache) +// RUN: %empty-directory(%t/moduleInputs) +// RUN: %empty-directory(%t/moduleInputs2) +// RUN: split-file %s %t + +// RUN: echo "Not Really a module" >> %t/moduleInputs/FooBar.swiftmodule +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %t/main.swift -o %t/deps.json -I %t/moduleInputs -diagnostic-style llvm -scanner-module-validation 2>&1 | %FileCheck %s -check-prefix=ERROR + +// ERROR: error: unable to resolve Swift module dependency to a compatible module: 'FooBar' +// ERROR: note: found incompatible module '{{.*}}{{/|\\}}moduleInputs{{/|\\}}FooBar.swiftmodule': malformed + +// RUN: %target-swift-frontend -emit-module %t/FooBar.swift -emit-module-path %t/moduleInputs2/FooBar.swiftmodule -module-name FooBar +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %t/main.swift -o %t/deps.json -I %t/moduleInputs -I %t/moduleInputs2 -diagnostic-style llvm -scanner-module-validation 2>&1 | %FileCheck %s -check-prefix=WARNING + +// WARNING: warning: module file '{{.*}}{{/|\\}}moduleInputs{{/|\\}}FooBar.swiftmodule' is incompatible with this Swift compiler: malformed + +//--- main.swift +import FooBar + +//--- FooBar.swift +public func fooBar() {} diff --git a/test/ScanDependencies/clang_scan_error.swift b/test/ScanDependencies/clang_scan_error.swift index 3ecc0b6d6b5cb..f26f4150e5b9b 100644 --- a/test/ScanDependencies/clang_scan_error.swift +++ b/test/ScanDependencies/clang_scan_error.swift @@ -6,7 +6,7 @@ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ // RUN: -o %t/deps.json -I %t -swift-version 5 2>&1 | %FileCheck %s -// CHECK: error: Bridging header dependency scan failure: {{.*}}bridging.h:1:10: fatal error: 'do-not-exist.h' file not found +// CHECK: error: bridging header dependency scanning failure: {{.*}}bridging.h:1:10: fatal error: 'do-not-exist.h' file not found //--- bridging.h #include "do-not-exist.h" diff --git a/test/ScanDependencies/diagnose-missing-module-found-in-serialized-paths.swift b/test/ScanDependencies/diagnose-missing-module-found-in-serialized-paths.swift index 453fc951ec790..f08ce6f5bb6c2 100644 --- a/test/ScanDependencies/diagnose-missing-module-found-in-serialized-paths.swift +++ b/test/ScanDependencies/diagnose-missing-module-found-in-serialized-paths.swift @@ -9,8 +9,8 @@ // RUN: %target-swift-frontend -scan-dependencies -o %t/deps.json %t/client.swift -I %t/deps -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import &> %t/output.txt // RUN: cat %t/output.txt | %FileCheck %s -// CHECK: error: Compilation search paths unable to resolve module dependency: 'C' -// CHECK: note: 'C' can be found using a search path that was specified when building module 'B' ('{{.*}}moreDeps'). This search path was not explicitly specified on the current compilation. +// CHECK: error: compilation search paths unable to resolve module dependency: 'C' +// CHECK: note: 'C' can be found using a search path that was specified when building module 'B' ('{{.*}}moreDeps'). This search path was not explicitly specified on the current compilation // CHECK: note: a dependency of Swift module 'B': '{{.*}}B.swiftmodule' // CHECK: note: a dependency of main module 'deps' diff --git a/test/ScanDependencies/error_path.swift b/test/ScanDependencies/error_path.swift index 0e128e2cea40b..6a659d5c6af56 100644 --- a/test/ScanDependencies/error_path.swift +++ b/test/ScanDependencies/error_path.swift @@ -5,11 +5,11 @@ import P -// CHECK: {{.*}}{{/|\\}}Z.swiftinterface:3:8: error: Unable to find module dependency: 'missing_module' +// CHECK: {{.*}}{{/|\\}}Z.swiftinterface:3:8: error: unable to resolve module dependency: 'missing_module' // CHECK-NEXT: 1 | // swift-interface-format-version: 1.0 // CHECK-NEXT: 2 | // swift-module-flags: -module-name Z // CHECK-NEXT: 3 | import missing_module -// CHECK-NEXT: | |- error: Unable to find module dependency: 'missing_module' +// CHECK-NEXT: | |- error: unable to resolve module dependency: 'missing_module' // CHECK-NEXT: | |- note: a dependency of Swift module 'Z': '{{.*}}{{/|\\}}Z.swiftinterface' // CHECK-NEXT: | |- note: a dependency of Swift module 'Y': '{{.*}}{{/|\\}}Y.swiftinterface' // CHECK-NEXT: | |- note: a dependency of Swift module 'P': '{{.*}}{{/|\\}}P.swiftinterface' diff --git a/test/ScanDependencies/error_source_locations.swift b/test/ScanDependencies/error_source_locations.swift index 599864ae4bb2c..2a57a2e51bba6 100644 --- a/test/ScanDependencies/error_source_locations.swift +++ b/test/ScanDependencies/error_source_locations.swift @@ -7,20 +7,20 @@ import P import FooBar -// CHECK: {{.*}}{{/|\\}}error_source_locations.swift:7:8: error: Unable to find module dependency: 'FooBar' +// CHECK: {{.*}}{{/|\\}}error_source_locations.swift:7:8: error: unable to resolve module dependency: 'FooBar' // CHECK-NEXT: 5 | // CHECK-NEXT: 6 | import P // CHECK-NEXT: 7 | import FooBar -// CHECK-NEXT: | |- error: Unable to find module dependency: 'FooBar' +// CHECK-NEXT: | |- error: unable to resolve module dependency: 'FooBar' // CHECK-NEXT: | `- note: a dependency of main module 'deps' // CHECK-NEXT: 8 | // CHECK-NEXT: 9 | -// CHECK: {{.*}}{{/|\\}}Z.swiftinterface:3:8: error: Unable to find module dependency: 'missing_module' +// CHECK: {{.*}}{{/|\\}}Z.swiftinterface:3:8: error: unable to resolve module dependency: 'missing_module' // CHECK-NEXT: 1 | // swift-interface-format-version: 1.0 // CHECK-NEXT: 2 | // swift-module-flags: -module-name Z // CHECK-NEXT: 3 | import missing_module -// CHECK-NEXT: | |- error: Unable to find module dependency: 'missing_module' +// CHECK-NEXT: | |- error: unable to resolve module dependency: 'missing_module' // CHECK-NEXT: | |- note: a dependency of Swift module 'Z': '{{.*}}{{/|\\}}Z.swiftinterface' // CHECK-NEXT: | |- note: a dependency of Swift module 'Y': '{{.*}}{{/|\\}}Y.swiftinterface' // CHECK-NEXT: | |- note: a dependency of Swift module 'P': '{{.*}}{{/|\\}}P.swiftinterface' diff --git a/test/ScanDependencies/invalid_binary_module_only.swift b/test/ScanDependencies/invalid_binary_module_only.swift index a53a7c164d77c..f96d1c7e7bba5 100644 --- a/test/ScanDependencies/invalid_binary_module_only.swift +++ b/test/ScanDependencies/invalid_binary_module_only.swift @@ -8,6 +8,5 @@ import FooBar -// CHECK: warning: module file '{{.*}}{{/|\\}}moduleInputs{{/|\\}}FooBar.swiftmodule' is incompatible with this Swift compiler: malformed -// CHECK: error: Unable to find module dependency: 'FooBar' - +// CHECK: error: unable to resolve Swift module dependency to a compatible module: 'FooBar' +// CHECK: note: found incompatible module '{{.*}}{{/|\\}}moduleInputs{{/|\\}}FooBar.swiftmodule': malformed diff --git a/test/ScanDependencies/testable-dependencies.swift b/test/ScanDependencies/testable-dependencies.swift index b43f2c8ac9359..d575287da8793 100644 --- a/test/ScanDependencies/testable-dependencies.swift +++ b/test/ScanDependencies/testable-dependencies.swift @@ -50,13 +50,14 @@ // TEST4: "swiftPrebuiltExternal": "A" // RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps4.json swiftPrebuiltExternal:A directDependencies | %FileCheck %s --check-prefix TEST4-A // TEST4-A: "swift": "B" +// WARN: warning: module file '{{.*}}{{/|\\}}A.swiftmodule' is incompatible with this Swift compiler: module built without '-enable-testing' /// Testable import non-testable build enable testing, warning about the finding then error out. // RUN: %target-swift-frontend -scan-dependencies -scanner-module-validation -module-load-mode prefer-interface -module-name Test %t/testable.swift \ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -enable-testing \ -// RUN: -o %t/deps5.json -I %t/regular -swift-version 5 -Rmodule-loading 2>&1 | %FileCheck %s --check-prefix WARN --check-prefix ERROR -// WARN: warning: ignore swiftmodule built without '-enable-testing' -// ERROR: error: Unable to find module dependency: 'A' +// RUN: -o %t/deps5.json -I %t/regular -swift-version 5 -Rmodule-loading 2>&1 | %FileCheck %s --check-prefix ERROR +// ERROR: error: unable to resolve Swift module dependency to a compatible module: 'A' +// ERROR: note: found incompatible module '{{.*}}{{/|\\}}A.swiftmodule': module built without '-enable-testing' /// Regular import a testable module with no interface, don't load optional dependencies. // RUN: rm %t/testable/A.swiftinterface