Skip to content

Commit 9bc787e

Browse files
committed
Add a “typecheck module interface” mode
1 parent 9bbe6e7 commit 9bc787e

File tree

10 files changed

+62
-8
lines changed

10 files changed

+62
-8
lines changed

include/swift/Frontend/FrontendOptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ class FrontendOptions {
116116

117117
/// Build from a swiftinterface, as close to `import` as possible
118118
CompileModuleFromInterface,
119+
/// Same as CompileModuleFromInterface, but stopping after typechecking
120+
TypecheckModuleFromInterface,
119121

120122
EmitSIBGen, ///< Emit serialized AST + raw SIL
121123
EmitSIB, ///< Emit serialized AST + canonical SIL

include/swift/Frontend/ModuleInterfaceLoader.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ class ExplicitModuleMapParser {
263263
};
264264

265265
struct ModuleInterfaceLoaderOptions {
266+
FrontendOptions::ActionType requestedAction =
267+
FrontendOptions::ActionType::EmitModuleOnly;
266268
bool remarkOnRebuildFromInterface = false;
267269
bool disableInterfaceLock = false;
268270
bool disableImplicitSwiftModule = false;
@@ -271,7 +273,17 @@ struct ModuleInterfaceLoaderOptions {
271273
remarkOnRebuildFromInterface(Opts.RemarkOnRebuildFromModuleInterface),
272274
disableInterfaceLock(Opts.DisableInterfaceFileLock),
273275
disableImplicitSwiftModule(Opts.DisableImplicitModules),
274-
mainExecutablePath(Opts.MainExecutablePath) {}
276+
mainExecutablePath(Opts.MainExecutablePath)
277+
{
278+
switch (Opts.RequestedAction) {
279+
case FrontendOptions::ActionType::TypecheckModuleFromInterface:
280+
requestedAction = FrontendOptions::ActionType::Typecheck;
281+
break;
282+
default:
283+
requestedAction = FrontendOptions::ActionType::EmitModuleOnly;
284+
break;
285+
}
286+
}
275287
ModuleInterfaceLoaderOptions() = default;
276288
};
277289

include/swift/Option/FrontendOptions.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,11 @@ def build_module_from_parseable_interface :
641641
Alias<compile_module_from_interface>,
642642
ModeOpt;
643643

644+
def typecheck_module_from_interface :
645+
Flag<["-"], "typecheck-module-from-interface">,
646+
HelpText<"Treat the (single) input as a swiftinterface and typecheck it">,
647+
ModeOpt;
648+
644649
def module_interface_preserve_types_as_written :
645650
Flag<["-"], "module-interface-preserve-types-as-written">,
646651
HelpText<"When emitting a module interface, preserve types as they were "

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ bool ArgsToFrontendOptionsConverter::convert(
147147
Opts.RequestedAction = determineRequestedAction(Args);
148148
}
149149

150-
if (Opts.RequestedAction == FrontendOptions::ActionType::CompileModuleFromInterface) {
150+
if (Opts.RequestedAction == FrontendOptions::ActionType::CompileModuleFromInterface ||
151+
Opts.RequestedAction == FrontendOptions::ActionType::TypecheckModuleFromInterface) {
151152
// The situations where we use this action, e.g. explicit module building and
152153
// generating prebuilt module cache, don't need synchronization. We should avoid
153154
// using lock files for them.
@@ -389,6 +390,8 @@ ArgsToFrontendOptionsConverter::determineRequestedAction(const ArgList &args) {
389390
return FrontendOptions::ActionType::Immediate;
390391
if (Opt.matches(OPT_compile_module_from_interface))
391392
return FrontendOptions::ActionType::CompileModuleFromInterface;
393+
if (Opt.matches(OPT_typecheck_module_from_interface))
394+
return FrontendOptions::ActionType::TypecheckModuleFromInterface;
392395

393396
llvm_unreachable("Unhandled mode option");
394397
}

lib/Frontend/Frontend.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,9 @@ void CompilerInstance::recordPrimaryInputBuffer(unsigned BufID) {
192192

193193
bool CompilerInstance::setUpASTContextIfNeeded() {
194194
if (Invocation.getFrontendOptions().RequestedAction ==
195-
FrontendOptions::ActionType::CompileModuleFromInterface) {
195+
FrontendOptions::ActionType::CompileModuleFromInterface ||
196+
Invocation.getFrontendOptions().RequestedAction ==
197+
FrontendOptions::ActionType::TypecheckModuleFromInterface) {
196198
// Compiling a module interface from source uses its own CompilerInstance
197199
// with options read from the input file. Don't bother setting up an
198200
// ASTContext at this level.

lib/Frontend/FrontendOptions.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ bool FrontendOptions::needsProperModuleName(ActionType action) {
5151
case ActionType::EmitModuleOnly:
5252
case ActionType::MergeModules:
5353
case ActionType::CompileModuleFromInterface:
54+
case ActionType::TypecheckModuleFromInterface:
5455
return true;
5556
case ActionType::Immediate:
5657
case ActionType::REPL:
@@ -118,6 +119,7 @@ FrontendOptions::formatForPrincipalOutputFileForAction(ActionType action) {
118119
case ActionType::Parse:
119120
case ActionType::ResolveImports:
120121
case ActionType::Typecheck:
122+
case ActionType::TypecheckModuleFromInterface:
121123
case ActionType::DumpParse:
122124
case ActionType::DumpInterfaceHash:
123125
case ActionType::DumpAST:
@@ -192,6 +194,7 @@ bool FrontendOptions::canActionEmitDependencies(ActionType action) {
192194
case ActionType::DumpTypeRefinementContexts:
193195
case ActionType::DumpTypeInfo:
194196
case ActionType::CompileModuleFromInterface:
197+
case ActionType::TypecheckModuleFromInterface:
195198
case ActionType::Immediate:
196199
case ActionType::REPL:
197200
case ActionType::DumpPCM:
@@ -232,6 +235,7 @@ bool FrontendOptions::canActionEmitReferenceDependencies(ActionType action) {
232235
case ActionType::DumpTypeRefinementContexts:
233236
case ActionType::DumpTypeInfo:
234237
case ActionType::CompileModuleFromInterface:
238+
case ActionType::TypecheckModuleFromInterface:
235239
case ActionType::Immediate:
236240
case ActionType::REPL:
237241
case ActionType::EmitPCM:
@@ -280,6 +284,7 @@ bool FrontendOptions::canActionEmitObjCHeader(ActionType action) {
280284
case ActionType::DumpTypeRefinementContexts:
281285
case ActionType::DumpTypeInfo:
282286
case ActionType::CompileModuleFromInterface:
287+
case ActionType::TypecheckModuleFromInterface:
283288
case ActionType::Immediate:
284289
case ActionType::REPL:
285290
case ActionType::EmitPCM:
@@ -317,6 +322,7 @@ bool FrontendOptions::canActionEmitLoadedModuleTrace(ActionType action) {
317322
case ActionType::DumpTypeRefinementContexts:
318323
case ActionType::DumpTypeInfo:
319324
case ActionType::CompileModuleFromInterface:
325+
case ActionType::TypecheckModuleFromInterface:
320326
case ActionType::Immediate:
321327
case ActionType::REPL:
322328
case ActionType::EmitPCM:
@@ -360,6 +366,7 @@ bool FrontendOptions::canActionEmitModule(ActionType action) {
360366
case ActionType::DumpTypeInfo:
361367
case ActionType::EmitSILGen:
362368
case ActionType::CompileModuleFromInterface:
369+
case ActionType::TypecheckModuleFromInterface:
363370
case ActionType::Immediate:
364371
case ActionType::REPL:
365372
case ActionType::EmitPCM:
@@ -404,6 +411,7 @@ bool FrontendOptions::canActionEmitInterface(ActionType action) {
404411
case ActionType::EmitSILGen:
405412
case ActionType::EmitSIBGen:
406413
case ActionType::CompileModuleFromInterface:
414+
case ActionType::TypecheckModuleFromInterface:
407415
case ActionType::Immediate:
408416
case ActionType::REPL:
409417
case ActionType::EmitPCM:
@@ -450,6 +458,7 @@ bool FrontendOptions::doesActionProduceOutput(ActionType action) {
450458
case ActionType::EmitImportedModules:
451459
case ActionType::MergeModules:
452460
case ActionType::CompileModuleFromInterface:
461+
case ActionType::TypecheckModuleFromInterface:
453462
case ActionType::DumpTypeInfo:
454463
case ActionType::EmitPCM:
455464
case ActionType::DumpPCM:
@@ -484,6 +493,7 @@ bool FrontendOptions::doesActionProduceTextualOutput(ActionType action) {
484493
case ActionType::Parse:
485494
case ActionType::ResolveImports:
486495
case ActionType::Typecheck:
496+
case ActionType::TypecheckModuleFromInterface:
487497
case ActionType::DumpParse:
488498
case ActionType::DumpInterfaceHash:
489499
case ActionType::DumpAST:
@@ -521,6 +531,7 @@ bool FrontendOptions::doesActionGenerateSIL(ActionType action) {
521531
case ActionType::EmitImportedModules:
522532
case ActionType::EmitPCH:
523533
case ActionType::CompileModuleFromInterface:
534+
case ActionType::TypecheckModuleFromInterface:
524535
case ActionType::EmitPCM:
525536
case ActionType::DumpPCM:
526537
case ActionType::ScanDependencies:
@@ -557,6 +568,7 @@ bool FrontendOptions::doesActionGenerateIR(ActionType action) {
557568
case ActionType::DumpTypeRefinementContexts:
558569
case ActionType::DumpTypeInfo:
559570
case ActionType::CompileModuleFromInterface:
571+
case ActionType::TypecheckModuleFromInterface:
560572
case ActionType::Typecheck:
561573
case ActionType::ResolveImports:
562574
case ActionType::MergeModules:

lib/Frontend/ModuleInterfaceBuilder.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal(
176176
return false;
177177
}
178178
FrontendOptions &FEOpts = subInvocation.getFrontendOptions();
179+
bool isTypeChecking =
180+
(FEOpts.RequestedAction == FrontendOptions::ActionType::Typecheck);
179181
const auto &InputInfo = FEOpts.InputsAndOutputs.firstInput();
180182
StringRef InPath = InputInfo.file();
181183
const auto &OutputInfo =
@@ -242,6 +244,9 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal(
242244
if (ShouldSerializeDeps)
243245
SerializationOpts.Dependencies = Deps;
244246
SILMod->setSerializeSILAction([&]() {
247+
if (isTypeChecking)
248+
return;
249+
245250
// We don't want to serialize module docs in the cache -- they
246251
// will be serialized beside the interface file.
247252
serializeToBuffers(Mod, SerializationOpts, ModuleBuffer,

lib/Frontend/ModuleInterfaceLoader.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,7 +1259,7 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl(
12591259
inheritOptionsForBuildingInterface(searchPathOpts, langOpts);
12601260
// Configure front-end input.
12611261
auto &SubFEOpts = genericSubInvocation.getFrontendOptions();
1262-
SubFEOpts.RequestedAction = FrontendOptions::ActionType::EmitModuleOnly;
1262+
SubFEOpts.RequestedAction = LoaderOpts.requestedAction;
12631263
if (!moduleCachePath.empty()) {
12641264
genericSubInvocation.setClangModuleCachePath(moduleCachePath);
12651265
}
@@ -1442,7 +1442,10 @@ bool InterfaceSubContextDelegateImpl::runInSubCompilerInstance(StringRef moduleN
14421442
std::vector<std::string> outputFiles{"/<unused>"};
14431443
std::vector<SupplementaryOutputPaths> ModuleOutputPaths;
14441444
ModuleOutputPaths.emplace_back();
1445-
ModuleOutputPaths.back().ModuleOutputPath = outputPath.str();
1445+
if (subInvocation.getFrontendOptions().RequestedAction ==
1446+
FrontendOptions::ActionType::EmitModuleOnly) {
1447+
ModuleOutputPaths.back().ModuleOutputPath = outputPath.str();
1448+
}
14461449
assert(subInvocation.getFrontendOptions().InputsAndOutputs.isWholeModule());
14471450
subInvocation.getFrontendOptions().InputsAndOutputs
14481451
.setMainAndSupplementaryOutputs(outputFiles, ModuleOutputPaths);

lib/FrontendTool/FrontendTool.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1711,7 +1711,8 @@ static bool performCompile(CompilerInstance &Instance,
17111711
<< Invocation.getLangOptions().Target.str() << '\n';
17121712
return false;
17131713
}
1714-
if (Action == FrontendOptions::ActionType::CompileModuleFromInterface)
1714+
if (Action == FrontendOptions::ActionType::CompileModuleFromInterface ||
1715+
Action == FrontendOptions::ActionType::TypecheckModuleFromInterface)
17151716
return buildModuleFromInterface(Instance);
17161717

17171718
if (Invocation.getInputKind() == InputFileKind::LLVM)

test/ModuleInterface/unbuildable.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,15 @@
1414
//
1515
// And finally, test:
1616
//
17-
// RUN: not %target-swift-frontend -typecheck %s -I %t -DCURRENT 2>&1 | %FileCheck -check-prefix=CURRENT %s
18-
// RUN: not %target-swift-frontend -typecheck %s -I %t -DFUTURE 2>&1 | %FileCheck -check-prefix=FUTURE %s
17+
// RUN: not %target-swift-frontend -typecheck %s -I %t -DCURRENT 2>&1 | %FileCheck -check-prefixes=ALL,CURRENT %s
18+
// RUN: not %target-swift-frontend -typecheck %s -I %t -DFUTURE 2>&1 | %FileCheck -check-prefixes=ALL,FUTURE %s
19+
//
20+
// Test that we get the same results when typechecking the interface:
21+
//
22+
// RUN: not %target-swift-frontend -typecheck-module-from-interface %t/UnbuildableCurrent.swiftinterface 2>&1 | %FileCheck -check-prefixes=ALL,CURRENT-PREBUILD %s
23+
// RUN: not %target-swift-frontend -typecheck-module-from-interface %t/UnbuildableFuture.swiftinterface 2>&1 | %FileCheck -check-prefixes=ALL,FUTURE-PREBUILD %s
24+
25+
// ALL: Unbuildable{{[^.]+}}.swiftinterface:{{[0-9]+}}:{{[0-9]+}}: error: use of unknown directive '#somethingYouveNeverHeardOf'
1926

2027
#if CURRENT
2128
import UnbuildableCurrent
@@ -25,3 +32,5 @@ import UnbuildableFuture
2532
// FUTURE: unbuildable.swift:[[@LINE-1]]:8: error: failed to build module 'UnbuildableFuture' from its module interface; the compiler that produced it, 'NeoTokyoSwift 2000.42', may have used features that aren't supported by this compiler, '{{.*Swift version.*}}'
2633
#endif
2734

35+
// CURRENT-PREBUILD: UnbuildableCurrent.swiftinterface:1:1: error: failed to build module 'UnbuildableCurrent' from its module interface; it may have been damaged or it may have triggered a bug in the Swift compiler when it was produced
36+
// FUTURE-PREBUILD: UnbuildableFuture.swiftinterface:1:1: error: failed to build module 'UnbuildableFuture' from its module interface; the compiler that produced it, 'NeoTokyoSwift 2000.42', may have used features that aren't supported by this compiler, '{{.*Swift version.*}}'

0 commit comments

Comments
 (0)