Skip to content

Commit b9fef33

Browse files
Merge pull request swiftlang#67263 from cachemeifyoucan/eng/PR-explicit-module-interface-check
[ExplicitModule] Allow typecheck-module-from-interface using explicit module
2 parents bf18947 + 411937d commit b9fef33

File tree

10 files changed

+157
-61
lines changed

10 files changed

+157
-61
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ WARNING(warning_cannot_find_locale_file,none,
105105
WARNING(warning_cannot_multithread_batch_mode,none,
106106
"ignoring -num-threads argument; cannot multithread batch mode", ())
107107
ERROR(error_cannot_explicit_interface_build_in_mode,none,
108-
"'-explicit-interface-module-build' only supported when building a module from interface ('-compile-module-from-interface')'", ())
108+
"'-explicit-interface-module-build' only supported when building a module from interface ('-compile-module-from-interface' or '-typecheck-module-from-interface')'", ())
109109
ERROR(error_cannot_direct_cc1_pcm_build_in_mode,none,
110110
"'-direct-clang-cc1-module-build' only supported when building a PCM ('-emit-pcm')'", ())
111111
ERROR(error_unsupported_option_argument,none,

include/swift/Frontend/FrontendOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ class FrontendOptions {
141141
/// Clang Include Trees.
142142
std::vector<std::string> ClangIncludeTrees;
143143

144+
/// CacheKey for input file.
145+
std::string InputFileKey;
146+
144147
/// Number of retry opening an input file if the previous opening returns
145148
/// bad file descriptor error.
146149
unsigned BadFileDescriptorRetryCount = 0;

include/swift/Option/FrontendOptions.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,8 @@ def always_compile_output_files :
12251225
def allow_unstable_cache_key_for_testing: Flag<["-"], "allow-unstable-cache-key-for-testing">,
12261226
HelpText<"Allow compilation caching with unstable inputs for testing purpose">;
12271227

1228+
def input_file_key : Separate<["-"], "input-file-key">,
1229+
HelpText<"Cache Key for input file">;
12281230
def bridging_header_pch_key : Separate<["-"], "bridging-header-pch-key">,
12291231
HelpText<"Cache Key for bridging header pch">;
12301232

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,33 @@ bool ArgsToFrontendOptionsConverter::convert(
249249
if (checkBuildFromInterfaceOnlyOptions())
250250
return true;
251251

252+
Opts.DeterministicCheck = Args.hasArg(OPT_enable_deterministic_check);
253+
Opts.EnableCaching = Args.hasArg(OPT_cache_compile_job);
254+
Opts.EnableCachingRemarks = Args.hasArg(OPT_cache_remarks);
255+
Opts.CacheSkipReplay = Args.hasArg(OPT_cache_disable_replay);
256+
Opts.CASOpts.CASPath =
257+
Args.getLastArgValue(OPT_cas_path, llvm::cas::getDefaultOnDiskCASPath());
258+
Opts.CASOpts.PluginPath = Args.getLastArgValue(OPT_cas_plugin_path);
259+
for (StringRef Opt : Args.getAllArgValues(OPT_cas_plugin_option)) {
260+
StringRef Name, Value;
261+
std::tie(Name, Value) = Opt.split('=');
262+
Opts.CASOpts.PluginOptions.emplace_back(std::string(Name),
263+
std::string(Value));
264+
}
265+
266+
Opts.CASFSRootIDs = Args.getAllArgValues(OPT_cas_fs);
267+
Opts.ClangIncludeTrees = Args.getAllArgValues(OPT_clang_include_tree_root);
268+
Opts.InputFileKey = Args.getLastArgValue(OPT_input_file_key);
269+
270+
if (Opts.EnableCaching && Opts.CASFSRootIDs.empty() &&
271+
Opts.ClangIncludeTrees.empty() &&
272+
FrontendOptions::supportCompilationCaching(Opts.RequestedAction)) {
273+
if (!Args.hasArg(OPT_allow_unstable_cache_key_for_testing)) {
274+
Diags.diagnose(SourceLoc(), diag::error_caching_no_cas_fs);
275+
return true;
276+
}
277+
}
278+
252279
if (FrontendOptions::doesActionGenerateIR(Opts.RequestedAction)) {
253280
if (Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies) ||
254281
Args.hasArg(OPT_experimental_skip_all_function_bodies) ||
@@ -346,36 +373,10 @@ bool ArgsToFrontendOptionsConverter::convert(
346373
Opts.serializedPathObfuscator.addMapping(SplitMap.first, SplitMap.second);
347374
}
348375
Opts.emptyABIDescriptor = Args.hasArg(OPT_empty_abi_descriptor);
349-
Opts.DeterministicCheck = Args.hasArg(OPT_enable_deterministic_check);
350376
for (auto A : Args.getAllArgValues(options::OPT_block_list_file)) {
351377
Opts.BlocklistConfigFilePaths.push_back(A);
352378
}
353379

354-
Opts.EnableCaching = Args.hasArg(OPT_cache_compile_job);
355-
Opts.EnableCachingRemarks = Args.hasArg(OPT_cache_remarks);
356-
Opts.CacheSkipReplay = Args.hasArg(OPT_cache_disable_replay);
357-
Opts.CASOpts.CASPath =
358-
Args.getLastArgValue(OPT_cas_path, llvm::cas::getDefaultOnDiskCASPath());
359-
Opts.CASOpts.PluginPath = Args.getLastArgValue(OPT_cas_plugin_path);
360-
for (StringRef Opt : Args.getAllArgValues(OPT_cas_plugin_option)) {
361-
StringRef Name, Value;
362-
std::tie(Name, Value) = Opt.split('=');
363-
Opts.CASOpts.PluginOptions.emplace_back(std::string(Name),
364-
std::string(Value));
365-
}
366-
367-
Opts.CASFSRootIDs = Args.getAllArgValues(OPT_cas_fs);
368-
Opts.ClangIncludeTrees = Args.getAllArgValues(OPT_clang_include_tree_root);
369-
370-
if (Opts.EnableCaching && Opts.CASFSRootIDs.empty() &&
371-
Opts.ClangIncludeTrees.empty() &&
372-
FrontendOptions::supportCompilationCaching(Opts.RequestedAction)) {
373-
if (!Args.hasArg(OPT_allow_unstable_cache_key_for_testing)) {
374-
Diags.diagnose(SourceLoc(), diag::error_caching_no_cas_fs);
375-
return true;
376-
}
377-
}
378-
379380
return false;
380381
}
381382

@@ -706,7 +707,10 @@ bool ArgsToFrontendOptionsConverter::
706707

707708
bool ArgsToFrontendOptionsConverter::checkBuildFromInterfaceOnlyOptions()
708709
const {
709-
if (Opts.RequestedAction != FrontendOptions::ActionType::CompileModuleFromInterface &&
710+
if (Opts.RequestedAction !=
711+
FrontendOptions::ActionType::CompileModuleFromInterface &&
712+
Opts.RequestedAction !=
713+
FrontendOptions::ActionType::TypecheckModuleFromInterface &&
710714
Opts.ExplicitInterfaceBuild) {
711715
Diags.diagnose(SourceLoc(),
712716
diag::error_cannot_explicit_interface_build_in_mode);

lib/Frontend/Frontend.cpp

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -520,38 +520,44 @@ bool CompilerInstance::setup(const CompilerInvocation &Invoke,
520520
}
521521

522522
bool CompilerInstance::setUpVirtualFileSystemOverlays() {
523-
if (Invocation.getFrontendOptions().EnableCaching &&
524-
(!Invocation.getFrontendOptions().CASFSRootIDs.empty() ||
525-
!Invocation.getFrontendOptions().ClangIncludeTrees.empty())) {
526-
// Set up CASFS as BaseFS.
523+
if (Invocation.getFrontendOptions().EnableCaching) {
527524
const auto &Opts = getInvocation().getFrontendOptions();
528-
auto FS =
529-
createCASFileSystem(*CAS, Opts.CASFSRootIDs, Opts.ClangIncludeTrees);
530-
if (!FS) {
531-
Diagnostics.diagnose(SourceLoc(), diag::error_cas,
532-
toString(FS.takeError()));
533-
return true;
525+
if (!Invocation.getFrontendOptions().CASFSRootIDs.empty() ||
526+
!Invocation.getFrontendOptions().ClangIncludeTrees.empty()) {
527+
// Set up CASFS as BaseFS.
528+
auto FS =
529+
createCASFileSystem(*CAS, Opts.CASFSRootIDs, Opts.ClangIncludeTrees);
530+
if (!FS) {
531+
Diagnostics.diagnose(SourceLoc(), diag::error_cas,
532+
toString(FS.takeError()));
533+
return true;
534+
}
535+
SourceMgr.setFileSystem(std::move(*FS));
536+
}
537+
538+
// If we need to load any files from CAS, try load it now and overlay it.
539+
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> MemFS =
540+
new llvm::vfs::InMemoryFileSystem();
541+
const auto &ClangOpts = getInvocation().getClangImporterOptions();
542+
543+
if (!ClangOpts.BridgingHeaderPCHCacheKey.empty()) {
544+
if (auto loadedBuffer = loadCachedCompileResultFromCacheKey(
545+
getObjectStore(), getActionCache(), Diagnostics,
546+
ClangOpts.BridgingHeaderPCHCacheKey, ClangOpts.BridgingHeader))
547+
MemFS->addFile(Invocation.getClangImporterOptions().BridgingHeader, 0,
548+
std::move(loadedBuffer));
534549
}
535-
SourceMgr.setFileSystem(std::move(*FS));
536-
}
537-
538-
// If we have a bridging header cache key, try load it now and overlay it.
539-
if (!Invocation.getClangImporterOptions().BridgingHeaderPCHCacheKey.empty() &&
540-
Invocation.getFrontendOptions().EnableCaching) {
541-
auto loadedBridgingBuffer = loadCachedCompileResultFromCacheKey(
542-
getObjectStore(), getActionCache(), Diagnostics,
543-
Invocation.getClangImporterOptions().BridgingHeaderPCHCacheKey,
544-
Invocation.getClangImporterOptions().BridgingHeader);
545-
if (loadedBridgingBuffer) {
546-
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> PCHFS =
547-
new llvm::vfs::InMemoryFileSystem();
548-
PCHFS->addFile(Invocation.getClangImporterOptions().BridgingHeader, 0,
549-
std::move(loadedBridgingBuffer));
550-
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayVFS =
551-
new llvm::vfs::OverlayFileSystem(SourceMgr.getFileSystem());
552-
OverlayVFS->pushOverlay(PCHFS);
553-
SourceMgr.setFileSystem(std::move(OverlayVFS));
550+
if (!Opts.InputFileKey.empty()) {
551+
auto InputPath = Opts.InputsAndOutputs.getFilenameOfFirstInput();
552+
if (auto loadedBuffer = loadCachedCompileResultFromCacheKey(
553+
getObjectStore(), getActionCache(), Diagnostics,
554+
Opts.InputFileKey, InputPath))
555+
MemFS->addFile(InputPath, 0, std::move(loadedBuffer));
554556
}
557+
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayVFS =
558+
new llvm::vfs::OverlayFileSystem(SourceMgr.getFileSystem());
559+
OverlayVFS->pushOverlay(MemFS);
560+
SourceMgr.setFileSystem(std::move(OverlayVFS));
555561
}
556562

557563
auto ExpectedOverlay =

lib/Frontend/FrontendOptions.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,6 @@ bool FrontendOptions::supportCompilationCaching(ActionType action) {
229229
case ActionType::DumpInterfaceHash:
230230
case ActionType::EmitImportedModules:
231231
case ActionType::ScanDependencies:
232-
case ActionType::TypecheckModuleFromInterface:
233232
case ActionType::ResolveImports:
234233
case ActionType::Typecheck:
235234
case ActionType::DumpAST:
@@ -241,6 +240,7 @@ bool FrontendOptions::supportCompilationCaching(ActionType action) {
241240
case ActionType::Immediate:
242241
case ActionType::DumpTypeInfo:
243242
return false;
243+
case ActionType::TypecheckModuleFromInterface:
244244
case ActionType::CompileModuleFromInterface:
245245
case ActionType::EmitPCH:
246246
case ActionType::EmitPCM:
@@ -769,14 +769,14 @@ bool FrontendOptions::doesActionProduceOutput(ActionType action) {
769769
case ActionType::EmitImportedModules:
770770
case ActionType::MergeModules:
771771
case ActionType::CompileModuleFromInterface:
772-
case ActionType::TypecheckModuleFromInterface:
773772
case ActionType::DumpTypeInfo:
774773
case ActionType::EmitPCM:
775774
case ActionType::DumpPCM:
776775
case ActionType::ScanDependencies:
777776
case ActionType::PrintFeature:
778777
return true;
779778

779+
case ActionType::TypecheckModuleFromInterface:
780780
case ActionType::NoneAction:
781781
case ActionType::Immediate:
782782
case ActionType::REPL:
@@ -800,12 +800,12 @@ bool FrontendOptions::doesActionProduceTextualOutput(ActionType action) {
800800
case ActionType::Immediate:
801801
case ActionType::REPL:
802802
case ActionType::EmitPCM:
803+
case ActionType::TypecheckModuleFromInterface:
803804
return false;
804805

805806
case ActionType::Parse:
806807
case ActionType::ResolveImports:
807808
case ActionType::Typecheck:
808-
case ActionType::TypecheckModuleFromInterface:
809809
case ActionType::DumpParse:
810810
case ActionType::DumpInterfaceHash:
811811
case ActionType::DumpAST:

lib/Frontend/Serialization.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,10 @@ void swift::serializeToBuffers(
6565
std::unique_ptr<llvm::MemoryBuffer> *moduleDocBuffer,
6666
std::unique_ptr<llvm::MemoryBuffer> *moduleSourceInfoBuffer,
6767
const SILModule *M) {
68+
// Serialization output is disabled.
69+
if (options.OutputPath.empty())
70+
return;
6871

69-
assert(!options.OutputPath.empty());
7072
{
7173
FrontendStatsTracer tracer(getContext(DC).Stats,
7274
"Serialization, swiftmodule, to buffer");

test/CAS/Inputs/ExtractOutputKey.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Usage: ExtractOutputKey.py file.json OutputPath
4+
5+
import json
6+
import sys
7+
8+
input_json = sys.argv[1]
9+
output_path = sys.argv[2]
10+
11+
12+
with open(input_json, 'r') as file:
13+
outputs = json.load(file)
14+
for output in outputs:
15+
if output['OutputPath'] != output_path:
16+
continue
17+
print(output['CacheKey'])

test/CAS/cas-explicit-module-map.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,33 @@
110110

111111
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/Foo.swiftmodule -disable-implicit-swift-modules -module-cache-path %t.module-cache -explicit-swift-module-map-file @%t/map.casid -Rmodule-loading -Xcc -Rmodule-import %s -cache-compile-job -cas-path %t/cas -allow-unstable-cache-key-for-testing 2>&1 | %FileCheck %s
112112

113+
// RUN: %target-swift-frontend -typecheck -emit-module-interface-path %t/Foo.swiftinterface -disable-implicit-swift-modules -module-cache-path %t.module-cache -explicit-swift-module-map-file @%t/map.casid %s -cache-compile-job -cas-path %t/cas -allow-unstable-cache-key-for-testing -swift-version 5 -enable-library-evolution
114+
// RUN: %cache-tool -cas-path %t/cas -cache-tool-action print-output-keys -- \
115+
// RUN: %target-swift-frontend -typecheck -emit-module-interface-path %t/Foo.swiftinterface -disable-implicit-swift-modules \
116+
// RUN: -module-cache-path %t.module-cache -explicit-swift-module-map-file @%t/map.casid %s -cache-compile-job \
117+
// RUN: -cas-path %t/cas -allow-unstable-cache-key-for-testing -swift-version 5 -enable-library-evolution > %t/keys.json
118+
119+
// RUN: %S/Inputs/ExtractOutputKey.py %t/keys.json %t/Foo.swiftinterface > %t/interface.casid
120+
// RUN: %target-swift-frontend -typecheck-module-from-interface %t/Foo.swiftinterface -disable-implicit-swift-modules \
121+
// RUN: -module-cache-path %t.module-cache -explicit-swift-module-map-file @%t/map.casid \
122+
// RUN: -cache-compile-job -cas-path %t/cas -allow-unstable-cache-key-for-testing -swift-version 5 -enable-library-evolution \
123+
// RUN: -explicit-interface-module-build -Rcache-compile-job 2>&1 | %FileCheck %s --check-prefix=VERIFY-OUTPUT --check-prefix=CACHE-MISS
124+
// RUN: %target-swift-frontend -typecheck-module-from-interface %t/Foo.swiftinterface -disable-implicit-swift-modules \
125+
// RUN: -module-cache-path %t.module-cache -explicit-swift-module-map-file @%t/map.casid \
126+
// RUN: -cache-compile-job -cas-path %t/cas -allow-unstable-cache-key-for-testing -swift-version 5 -enable-library-evolution \
127+
// RUN: -explicit-interface-module-build -Rcache-compile-job 2>&1 | %FileCheck %s --check-prefix=VERIFY-OUTPUT --check-prefix=CACHE-HIT
128+
113129
// CHECK-DAG: loaded module 'A'
114130
// CHECK-DAG: loaded module 'B'
115131
// CHECK-DAG: loaded module 'Swift'
116132
// CHECK-DAG: loaded module '_StringProcessing'
117133
// CHECK-DAG: loaded module '_Concurrency'
118134
// CHECK-DAG: loaded module 'SwiftOnoneSupport'
119135

136+
// CACHE-MISS: remark: cache miss output file
137+
// VERIFY-OUTPUT: warning: module 'A' was not compiled with library evolution support
138+
// CACHE-HIT: remark: replay output file
139+
120140
//--- A.swift
121141
func test() {}
122142

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: mkdir -p %t/clang-module-cache
3+
// RUN: mkdir -p %t/inputs
4+
// RUN: echo "/// Some cool comments" > %t/foo.swift
5+
// RUN: echo "public func foo() {}" >> %t/foo.swift
6+
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/inputs/Foo.swiftmodule -emit-module-interface-path %t/Foo.swiftinterface \
7+
// RUN: -swift-version 5 -enable-library-evolution -module-cache-path %t.module-cache %t/foo.swift -module-name Foo
8+
9+
// RUN: echo "[{" > %/t/inputs/map.json
10+
// RUN: echo "\"moduleName\": \"Foo\"," >> %/t/inputs/map.json
11+
// RUN: echo "\"modulePath\": \"%/t/inputs/Foo.swiftmodule\"," >> %/t/inputs/map.json
12+
// RUN: echo "\"docPath\": \"%/t/inputs/Foo.swiftdoc\"," >> %/t/inputs/map.json
13+
// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/Foo.swiftsourceinfo\"," >> %/t/inputs/map.json
14+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
15+
// RUN: echo "}," >> %/t/inputs/map.json
16+
// RUN: echo "{" >> %/t/inputs/map.json
17+
// RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json
18+
// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json
19+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
20+
// RUN: echo "}," >> %/t/inputs/map.json
21+
// RUN: echo "{" >> %/t/inputs/map.json
22+
// RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json
23+
// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json
24+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
25+
// RUN: echo "}," >> %/t/inputs/map.json
26+
// RUN: echo "{" >> %/t/inputs/map.json
27+
// RUN: echo "\"moduleName\": \"_Concurrency\"," >> %/t/inputs/map.json
28+
// RUN: echo "\"modulePath\": \"%/concurrency_module\"," >> %/t/inputs/map.json
29+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
30+
// RUN: echo "}," >> %/t/inputs/map.json
31+
// RUN: echo "{" >> %/t/inputs/map.json
32+
// RUN: echo "\"moduleName\": \"_StringProcessing\"," >> %/t/inputs/map.json
33+
// RUN: echo "\"modulePath\": \"%/string_processing_module\"," >> %/t/inputs/map.json
34+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
35+
// RUN: echo "}]" >> %/t/inputs/map.json
36+
37+
// RUN: %target-swift-frontend -typecheck-module-from-interface %t/Foo.swiftinterface -module-cache-path %t.module-cache \
38+
// RUN: -explicit-interface-module-build -explicit-swift-module-map-file %t/inputs/map.json -Rmodule-loading -Xcc -Rmodule-import 2>&1 | %FileCheck %s
39+
40+
// CHECK-DAG: loaded module 'Swift'
41+
// CHECK-DAG: loaded module '_StringProcessing'
42+
// CHECK-DAG: loaded module '_Concurrency'

0 commit comments

Comments
 (0)