Skip to content

[Dependency Scanning] Diagnose an error when only finding incompatible Swift binary modules #82460

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 18 additions & 14 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -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'|"
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/ModuleDependencies.h
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
64 changes: 49 additions & 15 deletions include/swift/DependencyScan/ModuleDependencyScanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -122,27 +122,67 @@ class SwiftDependencyTracker {
SwiftDependencyTracker(std::shared_ptr<llvm::cas::ObjectStore> CAS,
llvm::PrefixMapper *Mapper,
const CompilerInvocation &CI);

void startTracking(bool includeCommonDeps = true);
void trackFile(const Twine &path);
llvm::Expected<llvm::cas::ObjectProxy> createTreeFromDependencies();

private:
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
std::shared_ptr<llvm::cas::ObjectStore> 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<FileEntry> CommonFiles;
std::map<std::string, FileEntry> 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<ModuleDependencyID> dependencyOf,
std::optional<std::pair<ModuleDependencyID, std::string>>
resolvingSerializedSearchPath,
std::optional<
std::vector<SwiftModuleScannerQueryResult::IncompatibleCandidate>>
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<SwiftModuleScannerQueryResult::IncompatibleCandidate>
&candidates,
const ModuleDependenciesCache &cache,
std::optional<ModuleDependencyID> 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<SwiftModuleScannerQueryResult::IncompatibleCandidate>
&candidates);

DiagnosticEngine &Diagnostics;
std::unordered_set<std::string> ReportedMissing;
// Restrict access to the parent scanner class.
friend class ModuleDependencyScanner;
};

class ModuleDependencyScanner {
public:
ModuleDependencyScanner(SwiftDependencyScanningService &ScanningService,
Expand Down Expand Up @@ -246,7 +286,7 @@ class ModuleDependencyScanner {
StringRef mainModuleName, ModuleDependenciesCache &cache,
llvm::function_ref<void(ModuleDependencyID)> action);

/// Performance BridgingHeader Chaining.
/// Perform Bridging Header Chaining.
llvm::Error
performBridgingHeaderChaining(const ModuleDependencyID &rootModuleID,
ModuleDependenciesCache &cache,
Expand All @@ -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<ModuleDependencyID> 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
Expand All @@ -275,12 +309,12 @@ class ModuleDependencyScanner {
std::optional<std::pair<ModuleDependencyID, std::string>>
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;
Expand Down
48 changes: 37 additions & 11 deletions include/swift/Serialization/ScanningLoaders.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<ModuleDependencyInfo> &&dependencyInfo,
std::vector<IncompatibleCandidate> &&candidates)
: foundDependencyInfo(dependencyInfo),
incompatibleCandidates(candidates) {}

std::optional<ModuleDependencyInfo> foundDependencyInfo;
std::vector<IncompatibleCandidate> 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.
Expand Down Expand Up @@ -59,23 +81,27 @@ class SwiftModuleScanner : public SerializedModuleLoaderBase {
/// Swift module compilation commands
std::vector<std::string> swiftModuleClangCC1CommandLineArgs;

/// Constituents of a result of a given Swift module query,
/// reset at the end of every query.
std::optional<ModuleDependencyInfo> foundDependencyInfo;
std::vector<SwiftModuleScannerQueryResult::IncompatibleCandidate>
incompatibleCandidates;
public:
std::optional<ModuleDependencyInfo> dependencies;

SwiftModuleScanner(ASTContext &ctx, ModuleLoadingMode LoadMode,
InterfaceSubContextDelegate &astDelegate,
StringRef moduleOutputPath, StringRef sdkModuleOutputPath,
std::vector<std::string> swiftModuleClangCC1CommandLineArgs)
SwiftModuleScanner(
ASTContext &ctx, ModuleLoadingMode LoadMode,
InterfaceSubContextDelegate &astDelegate, StringRef moduleOutputPath,
StringRef sdkModuleOutputPath,
std::vector<std::string> 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<std::pair<ModuleDependencyID, ModuleDependencyInfo>, 1>
lookupSwiftModule(Identifier moduleName, bool isTestableImport);
SwiftModuleScannerQueryResult lookupSwiftModule(Identifier moduleName,
bool isTestableImport);
};
} // namespace swift

Expand Down
Loading