Skip to content

Commit 8961d8d

Browse files
committed
[Dependency Scanning] Diagnose an error when only finding incompatible Swift binary modules
When querying a Swift module, the scanner now also keeps track of all discovered candidate binary modules which are not compatible with current compilation. - If a Swift dependency is successfully resolved to a compatible binary module or a textual interface, a warning is emitted for every incompatible binary Swift module discovered along the way. - If a Swift dependency is not resolved, but incompatible module candidates were found, an error is emitted - while it is likely that the scan would fail downstream, it is also possible that an underlying Clang module dependency (with the same name) is successfuly resolved and the Swift lookup failure is ignored, which is still going to lead to failures most of the time if the client code assumes the presence of the Swift overlay module in this scenario. This change refactors common error reporting by the scanner into a 'ModuleDependencyIssueReporter' class, which also keeps track of all diagnosed failed lookups to avoid repeating diagnostics.
1 parent d499b14 commit 8961d8d

15 files changed

+320
-163
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,15 +1290,6 @@ REMARK(module_api_import_aliases,none,
12901290
"%select{, which reexports definition from %2|}3",
12911291
(const Decl *, ModuleDecl *, ModuleDecl *, bool))
12921292

1293-
REMARK(dependency_scan_skip_module_invalid,none,
1294-
"module file '%0' skipped by the dependency scan because it is "
1295-
"incompatible with this Swift compiler: %1", (StringRef, StringRef))
1296-
WARNING(skip_module_not_testable,none,
1297-
"ignore swiftmodule built without '-enable-testing': %0", (StringRef))
1298-
WARNING(dependency_scan_module_incompatible, none,
1299-
"module file '%0' is incompatible with this Swift compiler: %1",
1300-
(StringRef, StringRef))
1301-
13021293
REMARK(macro_loaded,none,
13031294
"loaded macro implementation module %0 from "
13041295
"%select{shared library '%2'|executable '%2'|"
@@ -2380,9 +2371,11 @@ ERROR(alignment_not_power_of_two,none,
23802371
"alignment value must be a power of two", ())
23812372

23822373
// Dependency Scanning
2383-
ERROR(dependency_scan_module_not_found, none, "Unable to find module dependency: '%0'", (StringRef))
2374+
ERROR(dependency_scan_module_not_found, none, "unable to resolve module dependency: '%0'", (StringRef))
2375+
23842376
GROUPED_ERROR(dependency_scan_module_not_found_on_specified_search_paths, MissingModuleOnKnownPaths, none,
2385-
"Compilation search paths unable to resolve module dependency: '%0'", (StringRef))
2377+
"compilation search paths unable to resolve module dependency: '%0'", (StringRef))
2378+
23862379
NOTE(unresolved_import_location,none,
23872380
"also imported here", ())
23882381
NOTE(dependency_as_imported_by_main_module,none,
@@ -2391,10 +2384,21 @@ NOTE(dependency_as_imported_by, none,
23912384
"a dependency of %select{Swift|Clang}2 module '%0': '%1'", (StringRef, StringRef, bool))
23922385
NOTE(inherited_search_path_resolves_module,none,
23932386
"'%0' can be found using a search path that was specified when building module '%1' ('%2'). "
2394-
"This search path was not explicitly specified on the current compilation.", (StringRef, StringRef, StringRef))
2387+
"This search path was not explicitly specified on the current compilation", (StringRef, StringRef, StringRef))
2388+
2389+
ERROR(dependency_scan_compatible_swift_module_not_found, none,
2390+
"unable to resolve Swift module dependency to a compatible module: '%0'",
2391+
(StringRef))
2392+
NOTE(dependency_scan_incompatible_module_found,none,
2393+
"found incompatible module '%0': %1", (StringRef, StringRef))
2394+
2395+
WARNING(dependency_scan_module_incompatible, none,
2396+
"module file '%0' is incompatible with this Swift compiler: %1",
2397+
(StringRef, StringRef))
2398+
2399+
ERROR(clang_dependency_scan_error, none, "clang dependency scanning failure: %0", (StringRef))
23952400

2396-
ERROR(clang_dependency_scan_error, none, "Clang dependency scanner failure: %0", (StringRef))
2397-
ERROR(clang_header_dependency_scan_error, none, "Bridging header dependency scan failure: %0", (StringRef))
2401+
ERROR(clang_header_dependency_scan_error, none, "bridging header dependency scanning failure: %0", (StringRef))
23982402

23992403
// Enum annotations
24002404
ERROR(indirect_case_without_payload,none,

include/swift/AST/ModuleDependencies.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ struct ScannerImportStatementInfo {
124124
uint32_t columnNumber;
125125
};
126126

127+
ScannerImportStatementInfo(std::string importIdentifier)
128+
: importIdentifier(importIdentifier), importLocations(),
129+
isExported(false), accessLevel(AccessLevel::Public) {}
130+
127131
ScannerImportStatementInfo(std::string importIdentifier, bool isExported,
128132
AccessLevel accessLevel)
129133
: importIdentifier(importIdentifier), importLocations(),

include/swift/DependencyScan/ModuleDependencyScanner.h

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class ModuleDependencyScanningWorker {
4646
&alreadySeenModules);
4747

4848
/// Retrieve the module dependencies for the Swift module with the given name.
49-
ModuleDependencyVector scanFilesystemForSwiftModuleDependency(
49+
SwiftModuleScannerQueryResult scanFilesystemForSwiftModuleDependency(
5050
Identifier moduleName, bool isTestableImport = false);
5151

5252
/// Query dependency information for header dependencies
@@ -122,27 +122,67 @@ class SwiftDependencyTracker {
122122
SwiftDependencyTracker(std::shared_ptr<llvm::cas::ObjectStore> CAS,
123123
llvm::PrefixMapper *Mapper,
124124
const CompilerInvocation &CI);
125-
125+
126126
void startTracking(bool includeCommonDeps = true);
127127
void trackFile(const Twine &path);
128128
llvm::Expected<llvm::cas::ObjectProxy> createTreeFromDependencies();
129-
129+
130130
private:
131131
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
132132
std::shared_ptr<llvm::cas::ObjectStore> CAS;
133133
llvm::PrefixMapper *Mapper;
134-
134+
135135
struct FileEntry {
136136
llvm::cas::ObjectRef FileRef;
137137
size_t Size;
138-
138+
139139
FileEntry(llvm::cas::ObjectRef FileRef, size_t Size)
140-
: FileRef(FileRef), Size(Size) {}
140+
: FileRef(FileRef), Size(Size) {}
141141
};
142142
llvm::StringMap<FileEntry> CommonFiles;
143143
std::map<std::string, FileEntry> TrackedFiles;
144144
};
145145

146+
class ModuleDependencyIssueReporter {
147+
private:
148+
ModuleDependencyIssueReporter(DiagnosticEngine &Diagnostics)
149+
: Diagnostics(Diagnostics) {}
150+
151+
/// Diagnose scanner failure and attempt to reconstruct the dependency
152+
/// path from the main module to the missing dependency
153+
void diagnoseModuleNotFoundFailure(
154+
const ScannerImportStatementInfo &moduleImport,
155+
const ModuleDependenciesCache &cache,
156+
std::optional<ModuleDependencyID> dependencyOf,
157+
std::optional<std::pair<ModuleDependencyID, std::string>>
158+
resolvingSerializedSearchPath,
159+
std::optional<
160+
std::vector<SwiftModuleScannerQueryResult::IncompatibleCandidate>>
161+
foundIncompatibleCandidates = std::nullopt);
162+
163+
/// Upon query failure, if incompatible binary module
164+
/// candidates were found, emit a failure diagnostic
165+
void diagnoseFailureOnOnlyIncompatibleCandidates(
166+
const ScannerImportStatementInfo &moduleImport,
167+
const std::vector<SwiftModuleScannerQueryResult::IncompatibleCandidate>
168+
&candidates,
169+
const ModuleDependenciesCache &cache,
170+
std::optional<ModuleDependencyID> dependencyOf);
171+
172+
/// Emit warnings for each discovered binary Swift module
173+
/// which was incompatible with the current compilation
174+
/// when querying \c moduleName
175+
void warnOnIncompatibleCandidates(
176+
StringRef moduleName,
177+
const std::vector<SwiftModuleScannerQueryResult::IncompatibleCandidate>
178+
&candidates);
179+
180+
DiagnosticEngine &Diagnostics;
181+
std::unordered_set<std::string> ReportedMissing;
182+
// Restrict access to the parent scanner class.
183+
friend class ModuleDependencyScanner;
184+
};
185+
146186
class ModuleDependencyScanner {
147187
public:
148188
ModuleDependencyScanner(SwiftDependencyScanningService &ScanningService,
@@ -246,7 +286,7 @@ class ModuleDependencyScanner {
246286
StringRef mainModuleName, ModuleDependenciesCache &cache,
247287
llvm::function_ref<void(ModuleDependencyID)> action);
248288

249-
/// Performance BridgingHeader Chaining.
289+
/// Perform Bridging Header Chaining.
250290
llvm::Error
251291
performBridgingHeaderChaining(const ModuleDependencyID &rootModuleID,
252292
ModuleDependenciesCache &cache,
@@ -261,12 +301,6 @@ class ModuleDependencyScanner {
261301
/// for a given module name.
262302
Identifier getModuleImportIdentifier(StringRef moduleName);
263303

264-
/// Diagnose scanner failure and attempt to reconstruct the dependency
265-
/// path from the main module to the missing dependency.
266-
void diagnoseScannerFailure(const ScannerImportStatementInfo &moduleImport,
267-
const ModuleDependenciesCache &cache,
268-
std::optional<ModuleDependencyID> dependencyOf);
269-
270304
/// Assuming the \c `moduleImport` failed to resolve,
271305
/// iterate over all binary Swift module dependencies with serialized
272306
/// search paths and attempt to diagnose if the failed-to-resolve module
@@ -275,12 +309,12 @@ class ModuleDependencyScanner {
275309
std::optional<std::pair<ModuleDependencyID, std::string>>
276310
attemptToFindResolvingSerializedSearchPath(
277311
const ScannerImportStatementInfo &moduleImport,
278-
const ModuleDependenciesCache &cache, const SourceLoc &importLoc);
312+
const ModuleDependenciesCache &cache);
279313

280314
private:
281315
const CompilerInvocation &ScanCompilerInvocation;
282316
ASTContext &ScanASTContext;
283-
DiagnosticEngine &Diagnostics;
317+
ModuleDependencyIssueReporter IssueReporter;
284318

285319
/// The available pool of workers for filesystem module search
286320
unsigned NumThreads;

include/swift/Serialization/ScanningLoaders.h

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,28 @@
1818
#include "swift/Serialization/SerializedModuleLoader.h"
1919

2020
namespace swift {
21+
22+
/// Result of looking up a Swift module on the current filesystem
23+
/// search paths.
24+
struct SwiftModuleScannerQueryResult {
25+
struct IncompatibleCandidate {
26+
std::string path;
27+
std::string incompatibilityReason;
28+
};
29+
30+
SwiftModuleScannerQueryResult()
31+
: foundDependencyInfo(std::nullopt), incompatibleCandidates() {}
32+
33+
SwiftModuleScannerQueryResult(
34+
std::optional<ModuleDependencyInfo> &&dependencyInfo,
35+
std::vector<IncompatibleCandidate> &&candidates)
36+
: foundDependencyInfo(dependencyInfo),
37+
incompatibleCandidates(candidates) {}
38+
39+
std::optional<ModuleDependencyInfo> foundDependencyInfo;
40+
std::vector<IncompatibleCandidate> incompatibleCandidates;
41+
};
42+
2143
/// A module "loader" that looks for .swiftinterface and .swiftmodule files
2244
/// for the purpose of determining dependencies, but does not attempt to
2345
/// load the module files.
@@ -59,23 +81,27 @@ class SwiftModuleScanner : public SerializedModuleLoaderBase {
5981
/// Swift module compilation commands
6082
std::vector<std::string> swiftModuleClangCC1CommandLineArgs;
6183

84+
/// Constituents of a result of a given Swift module query,
85+
/// reset at the end of every query.
86+
std::optional<ModuleDependencyInfo> foundDependencyInfo;
87+
std::vector<SwiftModuleScannerQueryResult::IncompatibleCandidate>
88+
incompatibleCandidates;
6289
public:
63-
std::optional<ModuleDependencyInfo> dependencies;
64-
65-
SwiftModuleScanner(ASTContext &ctx, ModuleLoadingMode LoadMode,
66-
InterfaceSubContextDelegate &astDelegate,
67-
StringRef moduleOutputPath, StringRef sdkModuleOutputPath,
68-
std::vector<std::string> swiftModuleClangCC1CommandLineArgs)
90+
SwiftModuleScanner(
91+
ASTContext &ctx, ModuleLoadingMode LoadMode,
92+
InterfaceSubContextDelegate &astDelegate, StringRef moduleOutputPath,
93+
StringRef sdkModuleOutputPath,
94+
std::vector<std::string> swiftModuleClangCC1CommandLineArgs)
6995
: SerializedModuleLoaderBase(ctx, nullptr, LoadMode,
7096
/*IgnoreSwiftSourceInfoFile=*/true),
71-
astDelegate(astDelegate),
72-
moduleOutputPath(moduleOutputPath),
97+
astDelegate(astDelegate), moduleOutputPath(moduleOutputPath),
7398
sdkModuleOutputPath(sdkModuleOutputPath),
74-
swiftModuleClangCC1CommandLineArgs(swiftModuleClangCC1CommandLineArgs) {}
99+
swiftModuleClangCC1CommandLineArgs(swiftModuleClangCC1CommandLineArgs) {
100+
}
75101

76102
/// Perform a filesystem search for a Swift module with a given name
77-
llvm::SmallVector<std::pair<ModuleDependencyID, ModuleDependencyInfo>, 1>
78-
lookupSwiftModule(Identifier moduleName, bool isTestableImport);
103+
SwiftModuleScannerQueryResult lookupSwiftModule(Identifier moduleName,
104+
bool isTestableImport);
79105
};
80106
} // namespace swift
81107

0 commit comments

Comments
 (0)