Skip to content

Commit dfe9d33

Browse files
Merge pull request #71741 from cachemeifyoucan/eng/PR-123120159
[ExplicitModule] Change how @testable imports are handled
2 parents 0ed3514 + 26ac2e0 commit dfe9d33

File tree

3 files changed

+76
-67
lines changed

3 files changed

+76
-67
lines changed

include/swift/Serialization/ScanningLoaders.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ class SwiftModuleScanner : public SerializedModuleLoaderBase {
3434

3535
/// Scan the given interface file to determine dependencies.
3636
llvm::ErrorOr<ModuleDependencyInfo>
37-
scanInterfaceFile(Twine moduleInterfacePath, bool isFramework,
38-
bool isTestableImport);
37+
scanInterfaceFile(Twine moduleInterfacePath, bool isFramework);
3938

4039
InterfaceSubContextDelegate &astDelegate;
4140

lib/Serialization/ScanningLoaders.cpp

Lines changed: 9 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,7 @@ std::error_code SwiftModuleScanner::findModuleFilesInDirectory(
8080
InPath = PrivateInPath;
8181
}
8282
}
83-
auto dependencies =
84-
scanInterfaceFile(InPath, IsFramework, isTestableDependencyLookup);
83+
auto dependencies = scanInterfaceFile(InPath, IsFramework);
8584
if (dependencies) {
8685
this->dependencies = std::move(dependencies.get());
8786
return std::error_code();
@@ -148,7 +147,7 @@ static std::vector<std::string> getCompiledCandidates(ASTContext &ctx,
148147

149148
llvm::ErrorOr<ModuleDependencyInfo>
150149
SwiftModuleScanner::scanInterfaceFile(Twine moduleInterfacePath,
151-
bool isFramework, bool isTestableImport) {
150+
bool isFramework) {
152151
// Create a module filename.
153152
// FIXME: Query the module interface loader to determine an appropriate
154153
// name for the module, which includes an appropriate hash.
@@ -242,64 +241,6 @@ SwiftModuleScanner::scanInterfaceFile(Twine moduleInterfacePath,
242241
&alreadyAddedModules);
243242
}
244243

245-
// For a `@testable` direct dependency, read in the dependencies
246-
// from an adjacent binary module, for completeness.
247-
if (isTestableImport) {
248-
auto adjacentBinaryModule = std::find_if(
249-
compiledCandidates.begin(), compiledCandidates.end(),
250-
[moduleInterfacePath](const std::string &candidate) {
251-
return llvm::sys::path::parent_path(candidate) ==
252-
llvm::sys::path::parent_path(moduleInterfacePath.str());
253-
});
254-
if (adjacentBinaryModule != compiledCandidates.end()) {
255-
// Required modules.
256-
auto adjacentBinaryModuleRequiredImports = getImportsOfModule(
257-
*adjacentBinaryModule, ModuleLoadingBehavior::Required,
258-
isFramework, isRequiredOSSAModules(),
259-
isRequiredNoncopyableGenerics(),
260-
Ctx.LangOpts.SDKName,
261-
Ctx.LangOpts.PackageName, Ctx.SourceMgr.getFileSystem().get(),
262-
Ctx.SearchPathOpts.DeserializedPathRecoverer);
263-
if (!adjacentBinaryModuleRequiredImports)
264-
return adjacentBinaryModuleRequiredImports.getError();
265-
auto adjacentBinaryModuleRequiredModuleImports =
266-
(*adjacentBinaryModuleRequiredImports).moduleImports;
267-
#ifndef NDEBUG
268-
// Verify that the set of required modules read out from the binary
269-
// module is a super-set of module imports identified in the
270-
// textual interface.
271-
for (const auto &requiredImport : Result->getModuleImports()) {
272-
assert(
273-
adjacentBinaryModuleRequiredModuleImports.contains(
274-
requiredImport) &&
275-
"Expected adjacent binary module's import set to contain all "
276-
"textual interface imports.");
277-
}
278-
#endif
279-
280-
for (const auto &requiredImport :
281-
adjacentBinaryModuleRequiredModuleImports)
282-
Result->addModuleImport(requiredImport.getKey(),
283-
&alreadyAddedModules);
284-
285-
// Optional modules. Will be looked-up on a best-effort basis
286-
auto adjacentBinaryModuleOptionalImports = getImportsOfModule(
287-
*adjacentBinaryModule, ModuleLoadingBehavior::Optional,
288-
isFramework, isRequiredOSSAModules(),
289-
isRequiredNoncopyableGenerics(), Ctx.LangOpts.SDKName,
290-
Ctx.LangOpts.PackageName, Ctx.SourceMgr.getFileSystem().get(),
291-
Ctx.SearchPathOpts.DeserializedPathRecoverer);
292-
if (!adjacentBinaryModuleOptionalImports)
293-
return adjacentBinaryModuleOptionalImports.getError();
294-
auto adjacentBinaryModuleOptionalModuleImports =
295-
(*adjacentBinaryModuleOptionalImports).moduleImports;
296-
for (const auto &optionalImport :
297-
adjacentBinaryModuleOptionalModuleImports)
298-
Result->addOptionalModuleImport(optionalImport.getKey(),
299-
&alreadyAddedModules);
300-
}
301-
}
302-
303244
return std::error_code();
304245
});
305246

@@ -324,6 +265,10 @@ ModuleDependencyVector SerializedModuleLoaderBase::getModuleDependencies(
324265
if (CacheFS)
325266
tracker = SwiftDependencyTracker(*CacheFS, mapper);
326267

268+
// Do not load interface module if it is testable import.
269+
ModuleLoadingMode MLM =
270+
isTestableDependencyLookup ? ModuleLoadingMode::OnlySerialized : LoadMode;
271+
327272
// Instantiate dependency scanning "loaders".
328273
SmallVector<std::unique_ptr<SwiftModuleScanner>, 2> scanners;
329274
// Placeholder dependencies must be resolved first, to prevent the
@@ -332,11 +277,10 @@ ModuleDependencyVector SerializedModuleLoaderBase::getModuleDependencies(
332277
// dependency graph of the placeholder dependency module itself.
333278
// FIXME: submodules?
334279
scanners.push_back(std::make_unique<PlaceholderSwiftModuleScanner>(
335-
Ctx, LoadMode, moduleId,
336-
Ctx.SearchPathOpts.PlaceholderDependencyModuleMap, delegate,
337-
moduleOutputPath, tracker));
280+
Ctx, MLM, moduleId, Ctx.SearchPathOpts.PlaceholderDependencyModuleMap,
281+
delegate, moduleOutputPath, tracker));
338282
scanners.push_back(std::make_unique<SwiftModuleScanner>(
339-
Ctx, LoadMode, moduleId, delegate, moduleOutputPath,
283+
Ctx, MLM, moduleId, delegate, moduleOutputPath,
340284
SwiftModuleScanner::MDS_plain, tracker));
341285

342286
// Check whether there is a module with this name that we can import.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -emit-module -module-name C -o %t/C.swiftmodule -swift-version 5 \
5+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \
6+
// RUN: -emit-module-interface-path %t/C.swiftinterface -enable-library-evolution -I %t -enable-testing \
7+
// RUN: %t/C.swift
8+
9+
// RUN: %target-swift-frontend -emit-module -module-name B -o %t/B.swiftmodule -swift-version 5 \
10+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \
11+
// RUN: -emit-module-interface-path %t/B.swiftinterface -enable-library-evolution -I %t -enable-testing \
12+
// RUN: %t/B.swift
13+
14+
// RUN: %target-swift-frontend -emit-module -module-name A -o %t/A.swiftmodule -swift-version 5 \
15+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \
16+
// RUN: -emit-module-interface-path %t/A.swiftinterface -enable-library-evolution -I %t -enable-testing \
17+
// RUN: %t/A.swift
18+
19+
// RUN: %target-swift-frontend -scan-dependencies -module-name Test %t/test1.swift \
20+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -enable-testing \
21+
// RUN: -o %t/deps1.json -I %t -swift-version 5
22+
// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps1.json Test directDependencies | %FileCheck %s --check-prefix TEST1
23+
// TEST1-DAG: "swiftPrebuiltExternal": "B"
24+
// TEST1-DAG: "swift": "C"
25+
26+
// RUN: %target-swift-frontend -scan-dependencies -module-name Test %t/test2.swift \
27+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -enable-testing \
28+
// RUN: -o %t/deps2.json -I %t -swift-version 5
29+
// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps2.json Test directDependencies | %FileCheck %s --check-prefix TEST2
30+
// TEST2-DAG: "swift": "A"
31+
// TEST2-DAG: "swiftPrebuiltExternal": "B"
32+
33+
/// Verify that the interface module inside A is overwritten to be binary module due to the deps in main module.
34+
// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps2.json A directDependencies | %FileCheck %s --check-prefix TEST2-A
35+
// TEST2-A-DAG: "swiftPrebuiltExternal": "B"
36+
// TEST2-A-DAG: "swift": "C"
37+
38+
/// An indirect @testable import is still interface deps.
39+
// RUN: %target-swift-frontend -scan-dependencies -module-name Test %t/test3.swift \
40+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -enable-testing \
41+
// RUN: -o %t/deps3.json -I %t -swift-version 5
42+
// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps3.json Test directDependencies | %FileCheck %s --check-prefix TEST3
43+
// TEST3-DAG: "swiftPrebuiltExternal": "A"
44+
// TEST3-DAG: "swift": "C"
45+
46+
//--- test1.swift
47+
@testable import B
48+
import C
49+
50+
//--- test2.swift
51+
import A
52+
@testable import B
53+
54+
//--- test3.swift
55+
@testable import A
56+
import C
57+
58+
//--- A.swift
59+
import B
60+
@testable import C
61+
62+
//--- B.swift
63+
@_spi(Testing) public func b() {}
64+
65+
//--- C.swift
66+
@_spi(Testing) public func c() {}

0 commit comments

Comments
 (0)