Skip to content

Commit d663696

Browse files
committed
ModuleInterface: Setup logic to load swiftinterfaces by default
The Swift compiler can load either the binary swiftmodule file or the textual swiftinterface file when importing a module. It currently picks the swiftmodule over the swiftinterface, unless there’s an exception. We should flip the default for distributed modules, prefer the swiftinterface over the swiftmodule unless there’s an exception. rdar://122955640
1 parent 8bb6846 commit d663696

File tree

3 files changed

+202
-20
lines changed

3 files changed

+202
-20
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,11 +444,19 @@ NOTE(compiled_module_ignored_reason,none,
444444
"|it belongs to a framework in the SDK"
445445
"|loading from module interfaces is preferred"
446446
"|it's a compiler host module"
447-
"|the module name is blocklisted}1",
447+
"|the module name is blocklisted,"
448+
"|the default is to load from module interfaces}1",
448449
(StringRef, unsigned))
449450
NOTE(out_of_date_module_here,none,
450451
"%select{compiled|cached|forwarding|prebuilt}0 module is out of date: '%1'",
451452
(unsigned, StringRef))
453+
NOTE(module_interface_ignored_reason,none,
454+
"not defaulting to module interface because %select{%error"
455+
"|it is a local module"
456+
"|it was blocklisted"
457+
"|the reader is a debugger}1"
458+
", preferring binary module at '%0'",
459+
(StringRef, unsigned))
452460
NOTE(module_interface_dependency_out_of_date,none,
453461
"dependency is out of date: '%0'",
454462
(StringRef))

lib/Frontend/ModuleInterfaceLoader.cpp

Lines changed: 98 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -240,12 +240,21 @@ struct ModuleRebuildInfo {
240240
InterfacePreferred,
241241
CompilerHostModule,
242242
Blocklisted,
243+
DistributedInterfaceByDefault,
244+
};
245+
// Keep aligned with diag::module_interface_ignored_reason.
246+
enum class ReasonModuleInterfaceIgnored {
247+
NotIgnored,
248+
LocalModule,
249+
Blocklisted,
250+
Debugger,
243251
};
244252
struct CandidateModule {
245253
std::string path;
246254
llvm::Optional<serialization::Status> serializationStatus;
247255
ModuleKind kind;
248256
ReasonIgnored reasonIgnored;
257+
ReasonModuleInterfaceIgnored reasonModuleInterfaceIgnored;
249258
SmallVector<std::string, 10> outOfDateDependencies;
250259
SmallVector<std::string, 10> missingDependencies;
251260
};
@@ -259,6 +268,7 @@ struct ModuleRebuildInfo {
259268
llvm::None,
260269
ModuleKind::Normal,
261270
ReasonIgnored::NotIgnored,
271+
ReasonModuleInterfaceIgnored::NotIgnored,
262272
{},
263273
{}});
264274
return candidateModules.back();
@@ -290,13 +300,21 @@ struct ModuleRebuildInfo {
290300
.missingDependencies.push_back(depPath.str());
291301
}
292302

293-
/// Sets the reason that the module at \c path was ignored. If this is
303+
/// Sets the reason that the module at \c modulePath was ignored. If this is
294304
/// anything besides \c NotIgnored a note will be added stating why the module
295305
/// was ignored.
296306
void addIgnoredModule(StringRef modulePath, ReasonIgnored reasonIgnored) {
297307
getOrInsertCandidateModule(modulePath).reasonIgnored = reasonIgnored;
298308
}
299309

310+
/// Record why no swiftinterfaces were preferred over the binary swiftmodule
311+
/// at \c modulePath.
312+
void addIgnoredModuleInterface(StringRef modulePath,
313+
ReasonModuleInterfaceIgnored reasonIgnored) {
314+
getOrInsertCandidateModule(modulePath).reasonModuleInterfaceIgnored =
315+
reasonIgnored;
316+
}
317+
300318
/// Determines if we saw the given module path and registered is as out of
301319
/// date.
302320
bool sawOutOfDateModule(StringRef modulePath) {
@@ -365,7 +383,7 @@ struct ModuleRebuildInfo {
365383
// We may have found multiple failing modules, that failed for different
366384
// reasons. Emit a note for each of them.
367385
for (auto &mod : candidateModules) {
368-
// If a the compiled module was ignored, diagnose the reason.
386+
// If the compiled module was ignored, diagnose the reason.
369387
if (mod.reasonIgnored != ReasonIgnored::NotIgnored) {
370388
diags.diagnose(loc, diag::compiled_module_ignored_reason, mod.path,
371389
(unsigned)mod.reasonIgnored);
@@ -397,6 +415,19 @@ struct ModuleRebuildInfo {
397415
}
398416
}
399417
}
418+
419+
/// Emits a diagnostic for the reason why binary swiftmodules were preferred
420+
/// over textual swiftinterfaces.
421+
void diagnoseIgnoredModuleInterfaces(ASTContext &ctx, SourceLoc loc) {
422+
for (auto &mod : candidateModules) {
423+
auto interfaceIgnore = mod.reasonModuleInterfaceIgnored;
424+
if (interfaceIgnore == ReasonModuleInterfaceIgnored::NotIgnored)
425+
continue;
426+
427+
ctx.Diags.diagnose(loc, diag::module_interface_ignored_reason,
428+
mod.path, (unsigned)interfaceIgnore);
429+
}
430+
}
400431
};
401432

402433
/// Constructs the full path of the dependency \p dep by prepending the SDK
@@ -759,6 +790,12 @@ class ModuleInterfaceLoaderImpl {
759790
return pathStartsWith(hostPath, path);
760791
}
761792

793+
bool isInSDK(StringRef path) {
794+
StringRef sdkPath = ctx.SearchPathOpts.getSDKPath();
795+
if (sdkPath.empty()) return false;
796+
return pathStartsWith(sdkPath, path);
797+
}
798+
762799
bool isInSystemFrameworks(StringRef path, bool publicFramework) {
763800
StringRef sdkPath = ctx.SearchPathOpts.getSDKPath();
764801
if (sdkPath.empty()) return false;
@@ -773,26 +810,64 @@ class ModuleInterfaceLoaderImpl {
773810

774811
std::pair<std::string, std::string> getCompiledModuleCandidates() {
775812
using ReasonIgnored = ModuleRebuildInfo::ReasonIgnored;
813+
using ReasonModuleInterfaceIgnored =
814+
ModuleRebuildInfo::ReasonModuleInterfaceIgnored;
776815
std::pair<std::string, std::string> result;
777-
// Should we attempt to load a swiftmodule adjacent to the swiftinterface?
778-
bool shouldLoadAdjacentModule = !ctx.IgnoreAdjacentModules;
779816

780-
if (modulePath.contains(".sdk")) {
781-
if (ctx.blockListConfig.hasBlockListAction(moduleName,
782-
BlockListKeyKind::ModuleName, BlockListAction::ShouldUseTextualModule)) {
783-
shouldLoadAdjacentModule = false;
784-
rebuildInfo.addIgnoredModule(modulePath, ReasonIgnored::Blocklisted);
817+
bool ignoreByDefault = ctx.blockListConfig.hasBlockListAction(
818+
"Swift_UseSwiftinterfaceByDefault",
819+
BlockListKeyKind::ModuleName,
820+
BlockListAction::ShouldUseBinaryModule);
821+
bool shouldLoadAdjacentModule;
822+
if (ignoreByDefault) {
823+
ReasonModuleInterfaceIgnored ignore =
824+
ReasonModuleInterfaceIgnored::NotIgnored;
825+
826+
if (!isInSDK(modulePath) &&
827+
!isInResourceHostDir(modulePath)) {
828+
ignore = ReasonModuleInterfaceIgnored::LocalModule;
829+
} else if (ctx.blockListConfig.hasBlockListAction(moduleName,
830+
BlockListKeyKind::ModuleName,
831+
BlockListAction::ShouldUseBinaryModule)) {
832+
ignore = ReasonModuleInterfaceIgnored::Blocklisted;
833+
} else if (ctx.LangOpts.DebuggerSupport) {
834+
ignore = ReasonModuleInterfaceIgnored::Debugger;
785835
}
786-
}
787836

788-
// Don't use the adjacent swiftmodule for frameworks from the public
789-
// Frameworks folder of the SDK.
790-
if (isInSystemFrameworks(modulePath, /*publicFramework*/true)) {
791-
shouldLoadAdjacentModule = false;
792-
rebuildInfo.addIgnoredModule(modulePath, ReasonIgnored::PublicFramework);
793-
} else if (isInResourceHostDir(modulePath)) {
794-
shouldLoadAdjacentModule = false;
795-
rebuildInfo.addIgnoredModule(modulePath, ReasonIgnored::CompilerHostModule);
837+
shouldLoadAdjacentModule =
838+
ignore != ReasonModuleInterfaceIgnored::NotIgnored;
839+
if (shouldLoadAdjacentModule) {
840+
// Prefer the swiftmodule.
841+
rebuildInfo.addIgnoredModuleInterface(modulePath, ignore);
842+
} else {
843+
// Prefer the swiftinterface.
844+
rebuildInfo.addIgnoredModule(modulePath,
845+
ReasonIgnored::DistributedInterfaceByDefault);
846+
}
847+
} else {
848+
// Should we attempt to load a swiftmodule adjacent to the swiftinterface?
849+
shouldLoadAdjacentModule = !ctx.IgnoreAdjacentModules;
850+
851+
if (modulePath.contains(".sdk")) {
852+
if (ctx.blockListConfig.hasBlockListAction(moduleName,
853+
BlockListKeyKind::ModuleName,
854+
BlockListAction::ShouldUseTextualModule)) {
855+
shouldLoadAdjacentModule = false;
856+
rebuildInfo.addIgnoredModule(modulePath, ReasonIgnored::Blocklisted);
857+
}
858+
}
859+
860+
// Don't use the adjacent swiftmodule for frameworks from the public
861+
// Frameworks folder of the SDK.
862+
if (isInSystemFrameworks(modulePath, /*publicFramework*/true)) {
863+
shouldLoadAdjacentModule = false;
864+
rebuildInfo.addIgnoredModule(modulePath,
865+
ReasonIgnored::PublicFramework);
866+
} else if (isInResourceHostDir(modulePath)) {
867+
shouldLoadAdjacentModule = false;
868+
rebuildInfo.addIgnoredModule(modulePath,
869+
ReasonIgnored::CompilerHostModule);
870+
}
796871
}
797872

798873
switch (loadMode) {
@@ -1075,8 +1150,10 @@ class ModuleInterfaceLoaderImpl {
10751150
// If we errored with anything other than 'no such file or directory',
10761151
// fail this load and let the other module loader diagnose it.
10771152
if (!moduleOrErr &&
1078-
moduleOrErr.getError() != std::errc::no_such_file_or_directory)
1153+
moduleOrErr.getError() != std::errc::no_such_file_or_directory) {
1154+
rebuildInfo.diagnoseIgnoredModuleInterfaces(ctx, diagnosticLoc);
10791155
return moduleOrErr.getError();
1156+
}
10801157

10811158
// We discovered a module! Return that module's buffer so we can load it.
10821159
if (moduleOrErr) {
@@ -1099,6 +1176,7 @@ class ModuleInterfaceLoaderImpl {
10991176
}
11001177
}
11011178

1179+
11021180
return std::move(module.moduleBuffer);
11031181
}
11041182
// If building from interface is disabled, return error.
@@ -1114,6 +1192,7 @@ class ModuleInterfaceLoaderImpl {
11141192
// Note that we use `diags` so that we emit this remark even when we're
11151193
// emitting other messages to `emptyDiags` (see below); these act as status
11161194
// messages to explain what's taking so long.
1195+
// XYHERE for print even on positive? or alternative
11171196
auto remarkRebuildAll = [&]() {
11181197
rebuildInfo.diagnose(ctx, diags, prebuiltCacheDir, diagnosticLoc,
11191198
diag::rebuilding_module_from_interface, moduleName,
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/// The blocklist can enable loading distributed swiftinterfaces by default.
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: split-file %s %t --leading-lines
5+
// REQUIRES: VENDOR=apple
6+
7+
/// Setup the SDK and local modules.
8+
//// SDK module in S/L/F.
9+
// RUN: %target-swift-frontend -emit-module -module-name SDKModule %t/Empty.swift \
10+
// RUN: -enable-library-evolution -swift-version 5 -parse-stdlib \
11+
// RUN: -emit-module-path %t/sdk/System/Library/Frameworks/SDKModule.framework/Modules/SDKModule.swiftmodule/%target-swiftmodule-name \
12+
// RUN: -emit-module-interface-path %t/sdk/System/Library/Frameworks/SDKModule.framework/Modules/SDKModule.swiftmodule/%target-swiftinterface-name
13+
// RUN: %target-swift-typecheck-module-from-interface(%t/sdk/System/Library/Frameworks/SDKModule.framework/Modules/SDKModule.swiftmodule/%target-swiftinterface-name) -module-name SDKModule
14+
15+
//// SDK module not in S/L/F.
16+
// RUN: %target-swift-frontend -emit-module -module-name SDKModuleAtUnusualPath %t/Empty.swift \
17+
// RUN: -enable-library-evolution -swift-version 5 -parse-stdlib \
18+
// RUN: -emit-module-path %t/sdk/System/Library/OtherFrameworks/SDKModuleAtUnusualPath.framework/Modules/SDKModuleAtUnusualPath.swiftmodule/%target-swiftmodule-name \
19+
// RUN: -emit-module-interface-path %t/sdk/System/Library/OtherFrameworks/SDKModuleAtUnusualPath.framework/Modules/SDKModuleAtUnusualPath.swiftmodule/%target-swiftinterface-name
20+
// RUN: %target-swift-typecheck-module-from-interface(%t/sdk/System/Library/OtherFrameworks/SDKModuleAtUnusualPath.framework/Modules/SDKModuleAtUnusualPath.swiftmodule/%target-swiftinterface-name) -module-name SDKModuleAtUnusualPath
21+
22+
//// Local module.
23+
// RUN: %target-swift-frontend -emit-module -module-name LocalModule %t/Empty.swift \
24+
// RUN: -enable-library-evolution -swift-version 5 -parse-stdlib \
25+
// RUN: -emit-module-path %t/not_sdk/LocalModule.swiftmodule \
26+
// RUN: -emit-module-interface-path %t/not_sdk/LocalModule.swiftinterface
27+
// RUN: %target-swift-typecheck-module-from-interface(%t/not_sdk/LocalModule.swiftinterface) -module-name LocalModule
28+
29+
//// Host resource-dir module.
30+
// RUN: %target-swift-frontend -emit-module -module-name HostResourceDirModule %t/Empty.swift \
31+
// RUN: -enable-library-evolution -swift-version 5 -parse-stdlib \
32+
// RUN: -emit-module-path %t/res/host/HostResourceDirModule.swiftmodule \
33+
// RUN: -emit-module-interface-path %t/res/host/HostResourceDirModule.swiftinterface
34+
// RUN: %target-swift-typecheck-module-from-interface(%t/res/host/HostResourceDirModule.swiftinterface) -module-name HostResourceDirModule
35+
36+
//// Blocklisted module.
37+
// RUN: %target-swift-frontend -emit-module -module-name BlocklistedModule %t/Empty.swift \
38+
// RUN: -enable-library-evolution -swift-version 5 -parse-stdlib \
39+
// RUN: -emit-module-path %t/sdk/System/Library/Frameworks/BlocklistedModule.framework/Modules/BlocklistedModule.swiftmodule/%target-swiftmodule-name \
40+
// RUN: -emit-module-interface-path %t/sdk/System/Library/Frameworks/BlocklistedModule.framework/Modules/BlocklistedModule.swiftmodule/%target-swiftinterface-name
41+
// RUN: %target-swift-typecheck-module-from-interface(%t/sdk/System/Library/Frameworks/BlocklistedModule.framework/Modules/BlocklistedModule.swiftmodule/%target-swiftinterface-name) -module-name BlocklistedModule
42+
43+
/// Build a client preferring swiftinterfaces.
44+
// RUN: %target-swift-frontend -typecheck -module-name Main %t/Client_SwiftinterfacesByDefault.swift \
45+
// RUN: -parse-stdlib -module-cache-path %t/cache \
46+
// RUN: -blocklist-file %t/blocklistEnabled.yml \
47+
// RUN: -sdk %t/sdk -I %t/not_sdk -resource-dir %t/res -I %t/res/host/ \
48+
// RUN: -F %t/sdk/System/Library/OtherFrameworks/ \
49+
// RUN: -Rmodule-interface-rebuild -verify
50+
51+
/// Build a client preferring swiftmodules.
52+
// RUN: %empty-directory(%t/cache)
53+
// RUN: %target-swift-frontend -typecheck -module-name Main %t/Client_SwiftmodulesByDefault.swift \
54+
// RUN: -parse-stdlib -module-cache-path %t/cache \
55+
// RUN: -blocklist-file %t/blocklistDisabled.yml \
56+
// RUN: -sdk %t/sdk -I %t/not_sdk -resource-dir %t/res -I %t/res/host/ \
57+
// RUN: -F %t/sdk/System/Library/OtherFrameworks/ \
58+
// RUN: -Rmodule-interface-rebuild -verify
59+
60+
//--- Empty.swift
61+
62+
//--- Client_SwiftinterfacesByDefault.swift
63+
/// New behavior
64+
import SDKModule // expected-remark {{rebuilding module 'SDKModule' from interface}}
65+
// expected-note @-1 {{was ignored because the default is to load from module interfaces}}
66+
import SDKModuleAtUnusualPath // expected-remark {{rebuilding module 'SDKModuleAtUnusualPath' from interface}}
67+
// expected-note @-1 {{was ignored because the default is to load from module interfaces}}
68+
import HostResourceDirModule // expected-remark {{rebuilding module 'HostResourceDirModule' from interface}}
69+
// expected-note @-1 {{was ignored because the default is to load from module interfaces}}
70+
import LocalModule // expected-note {{not defaulting to module interface because it is a local module, preferring binary module at}}
71+
import BlocklistedModule // expected-note {{not defaulting to module interface because it was blocklisted, preferring binary module at}}
72+
73+
//--- Client_SwiftmodulesByDefault.swift
74+
/// Old behavior
75+
import SDKModule // expected-remark {{rebuilding module 'SDKModule' from interface}}
76+
// expected-note @-1 {{was ignored because it belongs to a framework in the SDK}}
77+
import SDKModuleAtUnusualPath
78+
import HostResourceDirModule // expected-remark {{rebuilding module 'HostResourceDirModule' from interface}}
79+
// expected-note @-1 {{was ignored because it's a compiler host module}}
80+
import LocalModule
81+
import BlocklistedModule // expected-remark {{rebuilding module 'BlocklistedModule' from interface}}
82+
// expected-note @-1 {{was ignored because it belongs to a framework in the SDK}}
83+
84+
//--- blocklistDisabled.yml
85+
---
86+
ShouldUseBinaryModule:
87+
ModuleName:
88+
- BlocklistedModule
89+
90+
//--- blocklistEnabled.yml
91+
---
92+
ShouldUseBinaryModule:
93+
ModuleName:
94+
- Swift_UseSwiftinterfaceByDefault
95+
- BlocklistedModule

0 commit comments

Comments
 (0)