Skip to content

Commit 3ea7544

Browse files
authored
[Frontend] Allow -emit-interface with -typecheck (#19676)
Textual module interfaces don't actually depend on SILGen, so we shouldn't need to run SILGen (or serialize an entire binary module) if we're just trying to emit a textual interface. On the other hand, if we /are/ going to run SILGen and then SIL diagnostics, we shouldn't delay those diagnostics by spending time emitting a textual interface, or for that matter a TBD file. Using this, update all the ModuleInterface tests that use `-emit-module -o /dev/null` to use `-typecheck` instead, except for those using `-merge-modules`.
1 parent 6cc6f4f commit 3ea7544

15 files changed

+84
-36
lines changed

include/swift/Frontend/Frontend.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,11 @@ class CompilerInvocation {
337337
/// so return the TBDPath when in that mode and fail an assert
338338
/// if not in that mode.
339339
std::string getTBDPathForWholeModule() const;
340+
341+
/// ModuleInterfaceOutputPath only makes sense in whole module compilation
342+
/// mode, so return the ModuleInterfaceOutputPath when in that mode and fail
343+
/// an assert if not in that mode.
344+
std::string getModuleInterfaceOutputPathForWholeModule() const;
340345
};
341346

342347
/// A class which manages the state and execution of the compiler.

lib/Frontend/Frontend.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,15 @@ std::string CompilerInvocation::getTBDPathForWholeModule() const {
109109
.SupplementaryOutputs.TBDPath;
110110
}
111111

112+
std::string
113+
CompilerInvocation::getModuleInterfaceOutputPathForWholeModule() const {
114+
assert(getFrontendOptions().InputsAndOutputs.isWholeModule() &&
115+
"ModuleInterfaceOutputPath only makes sense when the whole module can "
116+
"be seen");
117+
return getPrimarySpecificPathsForAtMostOnePrimary()
118+
.SupplementaryOutputs.ModuleInterfaceOutputPath;
119+
}
120+
112121
void CompilerInstance::createSILModule() {
113122
assert(MainModule && "main module not created yet");
114123
// Assume WMO if a -primary-file option was not provided.

lib/Frontend/FrontendOptions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,6 @@ bool FrontendOptions::canActionEmitInterface(ActionType action) {
374374
case ActionType::NoneAction:
375375
case ActionType::Parse:
376376
case ActionType::ResolveImports:
377-
case ActionType::Typecheck:
378377
case ActionType::DumpParse:
379378
case ActionType::DumpInterfaceHash:
380379
case ActionType::DumpAST:
@@ -390,6 +389,7 @@ bool FrontendOptions::canActionEmitInterface(ActionType action) {
390389
case ActionType::REPL:
391390
case ActionType::EmitImportedModules:
392391
return false;
392+
case ActionType::Typecheck:
393393
case ActionType::MergeModules:
394394
case ActionType::EmitModuleOnly:
395395
case ActionType::EmitSIL:

lib/FrontendTool/FrontendTool.cpp

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,40 @@ emitIndexData(CompilerInvocation &Invocation, CompilerInstance &Instance) {
867867
return hadEmitIndexDataError;
868868
}
869869

870+
/// Emits all "one-per-module" supplementary outputs that don't depend on
871+
/// anything past type-checking.
872+
///
873+
/// These are extracted out so that they can be invoked early when using
874+
/// `-typecheck`, but skipped for any mode that runs SIL diagnostics if there's
875+
/// an error found there (to get those diagnostics back to the user faster).
876+
static bool emitAnyWholeModulePostTypeCheckSupplementaryOutputs(
877+
CompilerInstance &Instance, CompilerInvocation &Invocation,
878+
bool moduleIsPublic) {
879+
const FrontendOptions &opts = Invocation.getFrontendOptions();
880+
881+
// Record whether we failed to emit any of these outputs, but keep going; one
882+
// failure does not mean skipping the rest.
883+
bool hadAnyError = false;
884+
885+
if (opts.InputsAndOutputs.hasObjCHeaderOutputPath()) {
886+
hadAnyError |= printAsObjCIfNeeded(
887+
Invocation.getObjCHeaderOutputPathForAtMostOnePrimary(),
888+
Instance.getMainModule(), opts.ImplicitObjCHeaderPath, moduleIsPublic);
889+
}
890+
891+
if (opts.InputsAndOutputs.hasModuleInterfaceOutputPath()) {
892+
hadAnyError |= printModuleInterfaceIfNeeded(
893+
Invocation.getModuleInterfaceOutputPathForWholeModule(),
894+
Instance.getMainModule());
895+
}
896+
897+
{
898+
hadAnyError |= writeTBDIfNeeded(Invocation, Instance);
899+
}
900+
901+
return hadAnyError;
902+
}
903+
870904
static bool performCompileStepsPostSILGen(
871905
CompilerInstance &Instance, CompilerInvocation &Invocation,
872906
std::unique_ptr<SILModule> SM, bool astGuaranteedToCorrespondToSIL,
@@ -965,9 +999,6 @@ static bool performCompile(CompilerInstance &Instance,
965999
return true;
9661000
}
9671001

968-
if (writeTBDIfNeeded(Invocation, Instance))
969-
return true;
970-
9711002
// FIXME: This is still a lousy approximation of whether the module file will
9721003
// be externally consumed.
9731004
bool moduleIsPublic =
@@ -977,17 +1008,14 @@ static bool performCompile(CompilerInstance &Instance,
9771008

9781009
// We've just been told to perform a typecheck, so we can return now.
9791010
if (Action == FrontendOptions::ActionType::Typecheck) {
980-
const bool hadPrintAsObjCError =
981-
Invocation.getFrontendOptions()
982-
.InputsAndOutputs.hasObjCHeaderOutputPath() &&
983-
printAsObjCIfNeeded(
984-
Invocation.getObjCHeaderOutputPathForAtMostOnePrimary(),
985-
Instance.getMainModule(), opts.ImplicitObjCHeaderPath,
986-
moduleIsPublic);
987-
988-
const bool hadEmitIndexDataError = emitIndexData(Invocation, Instance);
989-
990-
return hadPrintAsObjCError || hadEmitIndexDataError || Context.hadError();
1011+
if (emitIndexData(Invocation, Instance))
1012+
return true;
1013+
if (emitAnyWholeModulePostTypeCheckSupplementaryOutputs(Instance,
1014+
Invocation,
1015+
moduleIsPublic)) {
1016+
return true;
1017+
}
1018+
return false;
9911019
}
9921020

9931021
assert(FrontendOptions::doesActionGenerateSIL(Action) &&
@@ -1272,6 +1300,9 @@ static bool performCompileStepsPostSILGen(
12721300
SM->verify();
12731301
}
12741302

1303+
emitAnyWholeModulePostTypeCheckSupplementaryOutputs(Instance, Invocation,
1304+
moduleIsPublic);
1305+
12751306
// This is the action to be used to serialize SILModule.
12761307
// It may be invoked multiple times, but it will perform
12771308
// serialization only once. The serialization may either happen
@@ -1309,14 +1340,6 @@ static bool performCompileStepsPostSILGen(
13091340

13101341
setPrivateDiscriminatorIfNeeded(IRGenOpts, MSF);
13111342

1312-
(void)printAsObjCIfNeeded(PSPs.SupplementaryOutputs.ObjCHeaderOutputPath,
1313-
Instance.getMainModule(),
1314-
opts.ImplicitObjCHeaderPath, moduleIsPublic);
1315-
1316-
(void)printModuleInterfaceIfNeeded(
1317-
PSPs.SupplementaryOutputs.ModuleInterfaceOutputPath,
1318-
Instance.getMainModule());
1319-
13201343
if (Action == FrontendOptions::ActionType::EmitSIB)
13211344
return serializeSIB(SM.get(), PSPs, Instance.getASTContext(), MSF);
13221345

test/Frontend/supplementary-output-support.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,5 @@
2626

2727
// RUN: not %target-swift-frontend -parse -emit-interface-path %t %s 2>&1 | %FileCheck -check-prefix=PARSE_NO_INTERFACE %s
2828
// PARSE_NO_INTERFACE: error: this mode does not support emitting textual interface files{{$}}
29-
// RUN: not %target-swift-frontend -typecheck -emit-interface-path %t %s 2>&1 | %FileCheck -check-prefix=TYPECHECK_NO_INTERFACE %s
30-
// TYPECHECK_NO_INTERFACE: error: this mode does not support emitting textual interface files{{$}}
3129
// RUN: not %target-swift-frontend -emit-silgen -emit-interface-path %t %s 2>&1 | %FileCheck -check-prefix=SILGEN_NO_INTERFACE %s
3230
// SILGEN_NO_INTERFACE: error: this mode does not support emitting textual interface files{{$}}

test/ModuleInterface/access-filter.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -emit-interface-path %t.swiftinterface -emit-module -o /dev/null %s
1+
// RUN: %target-swift-frontend -typecheck -emit-interface-path %t.swiftinterface %s
22
// RUN: %FileCheck %s < %t.swiftinterface
33
// RUN: %FileCheck -check-prefix NEGATIVE %s < %t.swiftinterface
44

test/ModuleInterface/attrs.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -emit-interface-path %t.swiftinterface -enable-resilience -emit-module -o /dev/null %s
1+
// RUN: %target-swift-frontend -typecheck -emit-interface-path %t.swiftinterface -enable-resilience %s
22
// RUN: %FileCheck %s < %t.swiftinterface
33

44
// CHECK: @_transparent public func glass() -> Int { return 0 }{{$}}

test/ModuleInterface/conformances.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -emit-interface-path %t.swiftinterface -emit-module -o /dev/null %s
1+
// RUN: %target-swift-frontend-typecheck -emit-interface-path %t.swiftinterface %s
22
// RUN: %FileCheck %s < %t.swiftinterface
33
// RUN: %FileCheck -check-prefix NEGATIVE %s < %t.swiftinterface
44

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: rm -f %t
2+
// RUN: not %target-swift-frontend -emit-interface-path %t -emit-module -o /dev/null %s
3+
// RUN: test ! -f %t
4+
// RUN: %target-swift-frontend -emit-interface-path %t -typecheck %s
5+
// RUN: test -f %t
6+
7+
public struct BadInit {
8+
public var x: Int
9+
public init() {
10+
return // without initializing 'x'
11+
}
12+
}

test/ModuleInterface/if-configs.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// RUN: %target-swift-frontend -merge-modules -emit-module -o %t/Test.swiftmodule %t/Test~partial.swiftmodule
44
// RUN: %target-swift-ide-test -print-module -module-to-print=Test -source-filename=x -I %t | %FileCheck %s
55

6-
// RUN: %target-swift-frontend -emit-interface-path %t.swiftinterface -enable-resilience -emit-module -o /dev/null %s
6+
// RUN: %target-swift-frontend -typecheck -emit-interface-path %t.swiftinterface -enable-resilience %s
77
// RUN: %FileCheck %s < %t.swiftinterface
88

99
// CHECK: func hasClosureDefaultArg(_ x: () -> Void = {

test/ModuleInterface/imports-submodule-order.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %target-swift-frontend -emit-interface-path - -emit-module -o /dev/null %s -I %S/Inputs/imports-submodule-order/ | %FileCheck %s
2-
// RUN: %target-swift-frontend -emit-interface-path - -emit-module -o /dev/null %s -I %S/Inputs/imports-submodule-order/ -D XY | %FileCheck %s
1+
// RUN: %target-swift-frontend -typecheck -emit-interface-path - %s -I %S/Inputs/imports-submodule-order/ | %FileCheck %s
2+
// RUN: %target-swift-frontend -typecheck -emit-interface-path - %s -I %S/Inputs/imports-submodule-order/ -D XY | %FileCheck %s
33

44
#if XY
55
@_exported import X.Submodule

test/ModuleInterface/imports.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %empty-directory(%t)
22
// RUN: %target-swift-frontend -emit-module -o %t/empty.swiftmodule %S/../Inputs/empty.swift
3-
// RUN: %target-swift-frontend -emit-interface-path - -emit-module -o /dev/null %s %S/Inputs/imports-other.swift -I %S/Inputs/imports-clang-modules/ -I %t -verify | %FileCheck %s
3+
// RUN: %target-swift-frontend -typecheck -emit-interface-path - %s %S/Inputs/imports-other.swift -I %S/Inputs/imports-clang-modules/ -I %t -verify | %FileCheck %s
44

55

66
@_exported import empty

test/ModuleInterface/private-stored-members.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// RUN: %empty-directory(%t)
22

3-
// RUN: %target-swift-frontend -emit-interface-path %t.swiftinterface -emit-module -o /dev/null %s
3+
// RUN: %target-swift-frontend -typecheck -emit-interface-path %t.swiftinterface %s
44
// RUN: %FileCheck %s < %t.swiftinterface --check-prefix CHECK --check-prefix COMMON
55

6-
// RUN: %target-swift-frontend -emit-interface-path %t-resilient.swiftinterface -enable-resilience -emit-module -o /dev/null %s
6+
// RUN: %target-swift-frontend -typecheck -emit-interface-path %t-resilient.swiftinterface -enable-resilience %s
77
// RUN: %FileCheck %s --check-prefix RESILIENT --check-prefix COMMON < %t-resilient.swiftinterface
88

99
// RUN: %target-swift-frontend -emit-module -o %t/Test.swiftmodule %t.swiftinterface -disable-objc-attr-requires-foundation-module

test/ModuleInterface/smoke-test.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %target-swift-frontend -emit-interface-path - -emit-module -o /dev/null %s | %FileCheck %s
2-
// RUN: %target-swift-frontend -emit-interface-path - -emit-module -o /dev/null %s %S/Inputs/other.swift | %FileCheck -check-prefix CHECK -check-prefix CHECK-MULTI-FILE %s
1+
// RUN: %target-swift-frontend -typecheck -emit-interface-path - %s | %FileCheck %s
2+
// RUN: %target-swift-frontend -typecheck -emit-interface-path - %s %S/Inputs/other.swift | %FileCheck -check-prefix CHECK -check-prefix CHECK-MULTI-FILE %s
33

44
// CHECK: public func verySimpleFunction(){{$}}
55
public func verySimpleFunction() {}

test/ModuleInterface/stdlib.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// RUN: %target-swift-frontend -typecheck -emit-interface-path - -parse-stdlib %s | %FileCheck %s
12
// RUN: %target-swift-frontend -emit-interface-path - -emit-module -o /dev/null -parse-stdlib %s | %FileCheck %s
23

34
// CHECK-NOT: import Builtin

0 commit comments

Comments
 (0)